< prev index next >

src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m

Print this page
rev 54094 : 8257853: Remove dependencies on JNF's JNI utility functions in AWT and 2D code
rev 54095 : 8259343: [macOS] Update JNI error handling in Cocoa code.
rev 54096 : 8259651: [macOS] Replace JNF_COCOA_ENTER/EXIT macros
rev 54097 : 8259869: [macOS] Remove desktop module dependencies on JNF Reference APIs
rev 54098 : 8260616: Removing remaining JNF dependencies in the java.desktop module
8259729: Missed JNFInstanceOf -> IsInstanceOf conversion
rev 54102 : 8261198: [macOS] Incorrect JNI parameters in number conversion in A11Y code
Reviewed-by: serb, psadhukhan
rev 54103 : 8263846: Bad JNI lookup getFocusOwner in accessibility code on Mac OS X
Reviewed-by: azvegint, prr


  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 // External Java Accessibility links:
  27 //
  28 // <https://docs.oracle.com/javase/8/docs/technotes/guides/access/index.html>
  29 // <http://www-106.ibm.com/developerworks/library/j-access/?n-j-10172>
  30 // <http://archives.java.sun.com/archives/java-access.html> (Sun's mailing list for Java accessibility)
  31 
  32 #import "JavaComponentAccessibility.h"
  33 
  34 #import "sun_lwawt_macosx_CAccessibility.h"
  35 
  36 #import <AppKit/AppKit.h>
  37 
  38 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  39 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
  40 
  41 #import <dlfcn.h>
  42 
  43 #import "JavaAccessibilityAction.h"
  44 #import "JavaAccessibilityUtilities.h"
  45 #import "JavaTextAccessibility.h"
  46 #import "ThreadUtilities.h"

  47 #import "AWTView.h"
  48 
  49 
  50 // these constants are duplicated in CAccessibility.java
  51 #define JAVA_AX_ALL_CHILDREN (-1)
  52 #define JAVA_AX_SELECTED_CHILDREN (-2)
  53 #define JAVA_AX_VISIBLE_CHILDREN (-3)
  54 // If the value is >=0, it's an index
  55 
  56 static JNF_STATIC_MEMBER_CACHE(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;");
  57 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleComponent, sjc_CAccessibility, "getAccessibleComponent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleComponent;");
  58 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleValue, sjc_CAccessibility, "getAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleValue;");
  59 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
  60 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleDescription, sjc_CAccessibility, "getAccessibleDescription", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
  61 static JNF_STATIC_MEMBER_CACHE(sjm_isFocusTraversable, sjc_CAccessibility, "isFocusTraversable", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z");
  62 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleIndexInParent, sjc_CAccessibility, "getAccessibleIndexInParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I");
  63 
  64 static JNF_CLASS_CACHE(sjc_CAccessible, "sun/lwawt/macosx/CAccessible");


























  65 
  66 static JNF_MEMBER_CACHE(jf_ptr, sjc_CAccessible, "ptr", "J");
  67 static JNF_STATIC_MEMBER_CACHE(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;");
  68 
  69 static jobject sAccessibilityClass = NULL;
  70 
  71 // sAttributeNamesForRoleCache holds the names of the attributes to which each java
  72 // AccessibleRole responds (see AccessibleRole.java).
  73 // This cache is queried before attempting to access a given attribute for a particular role.
  74 static NSMutableDictionary *sAttributeNamesForRoleCache = nil;
  75 static NSObject *sAttributeNamesLOCK = nil;
  76 
  77 @interface TabGroupAccessibility : JavaComponentAccessibility {
  78     NSInteger _numTabs;
  79 }
  80 
  81 - (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
  82 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
  83 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
  84 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
  85 
  86 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
  87 - (NSArray *)accessibilityChildrenAttribute;


 239     return (*env)->IsSameObject(env, accessibility->fAccessible, fAccessible);
 240 }
 241 
 242 - (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible
 243 {
 244     return (*env)->IsSameObject(env, fAccessible, accessible);
 245 }
 246 
 247 + (void)initialize
 248 {
 249     if (sAttributeNamesForRoleCache == nil) {
 250         sAttributeNamesLOCK = [[NSObject alloc] init];
 251         sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:60];
 252     }
 253 
 254     if (sRoles == nil) {
 255         initializeRoles();
 256     }
 257 
 258     if (sAccessibilityClass == NULL) {
 259         JNF_STATIC_MEMBER_CACHE(jm_getAccessibility, sjc_CAccessibility, "getAccessibility", "([Ljava/lang/String;)Lsun/lwawt/macosx/CAccessibility;");



 260 
 261 #ifdef JAVA_AX_NO_IGNORES
 262         NSArray *ignoredKeys = [NSArray array];
 263 #else
 264         NSArray *ignoredKeys = [sRoles allKeysForObject:JavaAccessibilityIgnore];
 265 #endif
 266         jobjectArray result = NULL;
 267         jsize count = [ignoredKeys count];
 268 
 269         JNIEnv *env = [ThreadUtilities getJNIEnv];
 270 
 271         static JNF_CLASS_CACHE(jc_String, "java/lang/String");
 272         result = JNFNewObjectArray(env, &jc_String, count);
 273         if (!result) {
 274             NSLog(@"In %s, can't create Java array of String objects", __FUNCTION__);
 275             return;
 276         }
 277 
 278         NSInteger i;
 279         for (i = 0; i < count; i++) {
 280             jstring jString = JNFNSToJavaString(env, [ignoredKeys objectAtIndex:i]);
 281             (*env)->SetObjectArrayElement(env, result, i, jString);
 282             (*env)->DeleteLocalRef(env, jString);
 283         }
 284 
 285         sAccessibilityClass = JNFCallStaticObjectMethod(env, jm_getAccessibility, result); // AWT_THREADING Safe (known object)

 286     }
 287 }
 288 
 289 + (void)postFocusChanged:(id)message
 290 {
 291     AWT_ASSERT_APPKIT_THREAD;
 292     NSAccessibilityPostNotification([NSApp accessibilityFocusedUIElement], NSAccessibilityFocusedUIElementChangedNotification);
 293 }
 294 
 295 + (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
 296     if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {




 297         return jaccessible;
 298     } else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
 299         return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);


 300     }
 301     return NULL;
 302 }
 303 
 304 + (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
 305 {
 306     if (parent->fAccessible == NULL) return nil;
 307     jobjectArray jchildrenAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)



 308     if (jchildrenAndRoles == NULL) return nil;
 309 
 310     jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
 311     NSMutableArray *children = [NSMutableArray arrayWithCapacity:arrayLen/2]; //childrenAndRoles array contains two elements (child, role) for each child
 312 
 313     NSInteger i;
 314     NSUInteger childIndex = (whichChildren >= 0) ? whichChildren : 0; // if we're getting one particular child, make sure to set its index correctly
 315     for(i = 0; i < arrayLen; i+=2)
 316     {
 317         jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
 318         jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
 319 
 320         NSString *childJavaRole = nil;
 321         if (jchildJavaRole != NULL) {
 322             jobject jkey = JNFGetObjectField(env, jchildJavaRole, sjf_key);
 323             childJavaRole = JNFJavaToNSString(env, jkey);



 324             (*env)->DeleteLocalRef(env, jkey);
 325         }
 326 
 327         JavaComponentAccessibility *child = [self createWithParent:parent accessible:jchild role:childJavaRole index:childIndex withEnv:env withView:parent->fView];
 328 
 329         (*env)->DeleteLocalRef(env, jchild);
 330         (*env)->DeleteLocalRef(env, jchildJavaRole);
 331 
 332         [children addObject:child];
 333         childIndex++;
 334     }
 335     (*env)->DeleteLocalRef(env, jchildrenAndRoles);
 336 
 337     return children;
 338 }
 339 
 340 + (JavaComponentAccessibility *)createWithAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env withView:(NSView *)view
 341 {

 342     JavaComponentAccessibility *ret = nil;
 343     jobject jcomponent = [(AWTView *)view awtComponent:env];
 344     jint index = JNFCallStaticIntMethod(env, sjm_getAccessibleIndexInParent, jaccessible, jcomponent);

 345     if (index >= 0) {
 346       NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
 347       ret = [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
 348     }
 349     (*env)->DeleteLocalRef(env, jcomponent);
 350     return ret;
 351 }
 352 
 353 + (JavaComponentAccessibility *) createWithAccessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
 354 {
 355     return [self createWithParent:nil accessible:jaccessible role:javaRole index:index withEnv:env withView:view];
 356 }
 357 
 358 + (JavaComponentAccessibility *) createWithParent:(JavaComponentAccessibility *)parent accessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
 359 {


 360     // try to fetch the jCAX from Java, and return autoreleased
 361     jobject jCAX = [JavaComponentAccessibility getCAccessible:jaccessible withEnv:env];
 362     if (jCAX == NULL) return nil;
 363     JavaComponentAccessibility *value = (JavaComponentAccessibility *) jlong_to_ptr(JNFGetLongField(env, jCAX, jf_ptr));
 364     if (value != nil) {
 365         (*env)->DeleteLocalRef(env, jCAX);
 366         return [[value retain] autorelease];
 367     }
 368 
 369     // otherwise, create a new instance
 370     JavaComponentAccessibility *newChild = nil;
 371     if ([javaRole isEqualToString:@"pagetablist"]) {
 372         newChild = [TabGroupAccessibility alloc];
 373     } else if ([javaRole isEqualToString:@"scrollpane"]) {
 374         newChild = [ScrollAreaAccessibility alloc];
 375     } else {
 376         NSString *nsRole = [sRoles objectForKey:javaRole];
 377         if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
 378             newChild = [JavaTextAccessibility alloc];
 379         } else {
 380             newChild = [JavaComponentAccessibility alloc];
 381         }
 382     }
 383 
 384     // must init freshly -alloc'd object
 385     [newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
 386 
 387     // If creating a JPopupMenu (not a combobox popup list) need to fire menuOpened.
 388     // This is the only way to know if the menu is opening; visible state change
 389     // can't be caught because the listeners are not set up in time.
 390     if ( [javaRole isEqualToString:@"popupmenu"] &&
 391          ![[parent javaRole] isEqualToString:@"combobox"] ) {
 392         [newChild postMenuOpened];
 393     }
 394 
 395     // must hard retain pointer poked into Java object
 396     [newChild retain];
 397     JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
 398     (*env)->DeleteLocalRef(env, jCAX);
 399 
 400     // return autoreleased instance
 401     return [newChild autorelease];
 402 }
 403 
 404 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
 405 {
 406     static JNF_STATIC_MEMBER_CACHE(jm_getInitialAttributeStates, sjc_CAccessibility, "getInitialAttributeStates", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[Z");


 407 
 408     NSMutableArray *attributeNames = [NSMutableArray arrayWithCapacity:20];
 409     [attributeNames retain];
 410 
 411     // all elements respond to parent, role, role description, window, topLevelUIElement, help
 412     [attributeNames addObject:NSAccessibilityParentAttribute];
 413     [attributeNames addObject:NSAccessibilityRoleAttribute];
 414     [attributeNames addObject:NSAccessibilityRoleDescriptionAttribute];
 415     [attributeNames addObject:NSAccessibilityHelpAttribute];
 416 
 417     // cmcnote: AXMenu usually doesn't respond to window / topLevelUIElement. But menus within a Java app's window
 418     // probably should. Should we use some role other than AXMenu / AXMenuBar for Java menus?
 419     [attributeNames addObject:NSAccessibilityWindowAttribute];
 420     [attributeNames addObject:NSAccessibilityTopLevelUIElementAttribute];
 421 
 422     // set accessible subrole
 423     NSString *javaRole = [self javaRole];
 424     if (javaRole != nil && [javaRole isEqualToString:@"passwordtext"]) {
 425         //cmcnote: should turn this into a constant
 426         [attributeNames addObject:NSAccessibilitySubroleAttribute];
 427     }
 428 
 429     // Get all the other accessibility attributes states we need in one swell foop.
 430     // javaRole isn't pulled in because we need protected access to AccessibleRole.key
 431     jbooleanArray attributeStates = (jbooleanArray)JNFCallStaticObjectMethod(env, jm_getInitialAttributeStates, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)


 432     if (attributeStates == NULL) return nil;
 433     jboolean *attributeStatesArray = (*env)->GetBooleanArrayElements(env, attributeStates, 0);
 434     if (attributeStatesArray == NULL) {
 435         // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
 436         NSLog(@"%s failed calling GetBooleanArrayElements", __FUNCTION__);
 437         return nil;
 438     }
 439 
 440     // if there's a component, it can be enabled and it has a size/position
 441     if (attributeStatesArray[0]) {
 442         [attributeNames addObject:NSAccessibilityEnabledAttribute];
 443         [attributeNames addObject:NSAccessibilitySizeAttribute];
 444         [attributeNames addObject:NSAccessibilityPositionAttribute];
 445     }
 446 
 447     // According to javadoc, a component that is focusable will return true from isFocusTraversable,
 448     // as well as having AccessibleState.FOCUSABLE in it's AccessibleStateSet.
 449     // We use the former heuristic; if the component focus-traversable, add a focused attribute
 450     // See also: accessibilityIsFocusedAttributeSettable
 451     if (attributeStatesArray[1])


 500     // Cleanup
 501     (*env)->ReleaseBooleanArrayElements(env, attributeStates, attributeStatesArray, JNI_ABORT);
 502 
 503     return attributeNames;
 504 }
 505 
 506 - (NSDictionary *)getActions:(JNIEnv *)env
 507 {
 508     @synchronized(fActionsLOCK) {
 509         if (fActions == nil) {
 510             fActions = [[NSMutableDictionary alloc] initWithCapacity:3];
 511             [self getActionsWithEnv:env];
 512         }
 513     }
 514 
 515     return fActions;
 516 }
 517 
 518 - (void)getActionsWithEnv:(JNIEnv *)env
 519 {
 520     static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleAction, sjc_CAccessibility, "getAccessibleAction", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleAction;");


 521 
 522     // On MacOSX, text doesn't have actions, in java it does.
 523     // cmcnote: NOT TRUE - Editable text has AXShowMenu. Textfields have AXConfirm. Static text has no actions.
 524     jobject axAction = JNFCallStaticObjectMethod(env, jm_getAccessibleAction, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)

 525     if (axAction != NULL) {
 526         //+++gdb NOTE: In MacOSX, there is just a single Action, not multiple. In java,
 527         //  the first one seems to be the most basic, so this will be used.
 528         // cmcnote: NOT TRUE - Sometimes there are multiple actions, eg sliders have AXDecrement AND AXIncrement (radr://3893192)
 529         JavaAxAction *action = [[JavaAxAction alloc] initWithEnv:env withAccessibleAction:axAction withIndex:0 withComponent:fComponent];
 530         [fActions setObject:action forKey:[self isMenu] ? NSAccessibilityPickAction : NSAccessibilityPressAction];
 531         [action release];
 532         (*env)->DeleteLocalRef(env, axAction);
 533     }
 534 }
 535 
 536 - (jobject)axContextWithEnv:(JNIEnv *)env
 537 {
 538     return getAxContext(env, fAccessible, fComponent);
 539 }
 540 
 541 - (id)parent
 542 {
 543     static JNF_CLASS_CACHE(sjc_Window, "java/awt/Window");
 544     static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleParent, sjc_CAccessibility, "getAccessibleParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
 545     static JNF_STATIC_MEMBER_CACHE(sjm_getSwingAccessible, sjc_CAccessible, "getSwingAccessible", "(Ljavax/accessibility/Accessible;)Ljavax/accessibility/Accessible;");
 546 
 547     if(fParent == nil) {
 548         JNIEnv* env = [ThreadUtilities getJNIEnv];







 549 
 550         jobject jparent = JNFCallStaticObjectMethod(env, sjm_getAccessibleParent, fAccessible, fComponent);

 551 
 552         if (jparent == NULL) {
 553             fParent = fView;
 554         } else {
 555             AWTView *view = fView;
 556             jobject jax = JNFCallStaticObjectMethod(env, sjm_getSwingAccessible, fAccessible);

 557 
 558             if (JNFIsInstanceOf(env, jax, &sjc_Window)) {
 559                 // In this case jparent is an owner toplevel and we should retrieve its own view
 560                 view = [AWTView awtView:env ofAccessible:jparent];
 561             }
 562             if (view != nil) {
 563                 fParent = [JavaComponentAccessibility createWithAccessible:jparent withEnv:env withView:view];
 564             }
 565             if (fParent == nil) {
 566                 fParent = fView;
 567             }
 568             (*env)->DeleteLocalRef(env, jparent);
 569             (*env)->DeleteLocalRef(env, jax );
 570         }
 571         [fParent retain];
 572     }
 573     return fParent;
 574 }
 575 
 576 - (NSView *)view
 577 {
 578     return fView;


 742     }
 743 
 744     return value;
 745 }
 746 
 747 - (BOOL)accessibilityIsChildrenAttributeSettable
 748 {
 749     return NO;
 750 }
 751 
 752 - (NSUInteger)accessibilityIndexOfChild:(id)child
 753 {
 754     // Only special-casing for Lists, for now. This allows lists to be accessible, fixing radr://3856139 "JLists are broken".
 755     // Will probably want to special-case for Tables when we implement them (radr://3096643 "Accessibility: Table").
 756     // In AppKit, NSMatrixAccessibility (which uses NSAccessibilityListRole), NSTableRowAccessibility, and NSTableViewAccessibility are the
 757     // only ones that override the default implementation in NSAccessibility
 758     if (![[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityListRole]) {
 759         return [super accessibilityIndexOfChild:child];
 760     }
 761 


 762     jint returnValue =
 763         JNFCallStaticIntMethod( [ThreadUtilities getJNIEnv],

 764                                 sjm_getAccessibleIndexInParent,
 765                                 ((JavaComponentAccessibility *)child)->fAccessible,
 766                                 ((JavaComponentAccessibility *)child)->fComponent );

 767     return (returnValue == -1) ? NSNotFound : returnValue;
 768 }
 769 
 770 // Without this optimization accessibilityChildrenAttribute is called in order to get the entire array of children.
 771 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount {
 772     if ( (maxCount == 1) && [attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
 773         // Children codes for ALL, SELECTED, VISIBLE are <0. If the code is >=0, we treat it as an index to a single child
 774         NSArray *child = [JavaComponentAccessibility childrenOfParent:self withEnv:[ThreadUtilities getJNIEnv] withChildrenCode:(NSInteger)index allowIgnored:NO];
 775         if ([child count] > 0) {
 776             return child;
 777         }
 778     }
 779     return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
 780 }
 781 
 782 // Flag indicating enabled state of element (NSNumber)
 783 - (NSNumber *)accessibilityEnabledAttribute
 784 {
 785     static JNF_STATIC_MEMBER_CACHE(jm_isEnabled, sjc_CAccessibility, "isEnabled", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z");
 786 
 787     JNIEnv* env = [ThreadUtilities getJNIEnv];
 788     NSNumber *value = [NSNumber numberWithBool:JNFCallStaticBooleanMethod(env, jm_isEnabled, fAccessible, fComponent)]; // AWT_THREADING Safe (AWTRunLoop)




 789     if (value == nil) {
 790         NSLog(@"WARNING: %s called on component that has no accessible component: %@", __FUNCTION__, self);
 791     }
 792     return value;
 793 }
 794 
 795 - (BOOL)accessibilityIsEnabledAttributeSettable
 796 {
 797     return NO;
 798 }
 799 
 800 // Flag indicating presence of keyboard focus (NSNumber)
 801 - (NSNumber *)accessibilityFocusedAttribute
 802 {
 803     if ([self accessibilityIsFocusedAttributeSettable]) {
 804         return [NSNumber numberWithBool:[self isEqual:[NSApp accessibilityFocusedUIElement]]];
 805     }
 806     return [NSNumber numberWithBool:NO];
 807 }
 808 
 809 - (BOOL)accessibilityIsFocusedAttributeSettable
 810 {
 811     JNIEnv* env = [ThreadUtilities getJNIEnv];



 812     // According to javadoc, a component that is focusable will return true from isFocusTraversable,
 813     // as well as having AccessibleState.FOCUSABLE in its AccessibleStateSet.
 814     // We use the former heuristic; if the component focus-traversable, add a focused attribute
 815     // See also initializeAttributeNamesWithEnv:
 816     if (JNFCallStaticBooleanMethod(env, sjm_isFocusTraversable, fAccessible, fComponent)) { // AWT_THREADING Safe (AWTRunLoop)
 817         return YES;
 818     }

 819 
 820     return NO;
 821 }
 822 
 823 - (void)accessibilitySetFocusedAttribute:(id)value
 824 {
 825     static JNF_STATIC_MEMBER_CACHE(jm_requestFocus, sjc_CAccessibility, "requestFocus", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)V");



 826 
 827     if ([(NSNumber*)value boolValue])
 828     {
 829         JNIEnv* env = [ThreadUtilities getJNIEnv];
 830         JNFCallStaticVoidMethod(env, jm_requestFocus, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 831     }
 832 }
 833 
 834 // Instance description, such as a help tag string (NSString)
 835 - (NSString *)accessibilityHelpAttribute
 836 {
 837     JNIEnv* env = [ThreadUtilities getJNIEnv];
 838 
 839     jobject val = JNFCallStaticObjectMethod(env, sjm_getAccessibleDescription, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)





 840     if (val == NULL) {
 841         return nil;
 842     }
 843     NSString* str = JNFJavaToNSString(env, val);
 844     (*env)->DeleteLocalRef(env, val);
 845     return str;
 846 }
 847 
 848 - (BOOL)accessibilityIsHelpAttributeSettable
 849 {
 850     return NO;
 851 }
 852 
 853 - (NSValue *)accessibilityIndexAttribute
 854 {
 855     NSInteger index = fIndex;
 856     NSValue *returnValue = [NSValue value:&index withObjCType:@encode(NSInteger)];
 857     return returnValue;
 858 }
 859 
 860 - (BOOL)accessibilityIsIndexAttributeSettable
 861 {
 862     return NO;
 863 }
 864 


























 865 // Element's maximum value (id)
 866 - (id)accessibilityMaxValueAttribute
 867 {
 868     static JNF_STATIC_MEMBER_CACHE(jm_getMaximumAccessibleValue, sjc_CAccessibility, "getMaximumAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/Number;");
 869 
 870     JNIEnv* env = [ThreadUtilities getJNIEnv];



 871 
 872     jobject axValue = JNFCallStaticObjectMethod(env, jm_getMaximumAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)

 873     if (axValue == NULL) {
 874         return [NSNumber numberWithInt:0];
 875     }
 876     NSNumber* num = JNFJavaToNSNumber(env, axValue);
 877     (*env)->DeleteLocalRef(env, axValue);
 878     return num;
 879 }
 880 
 881 - (BOOL)accessibilityIsMaxValueAttributeSettable
 882 {
 883     return NO;
 884 }
 885 
 886 // Element's minimum value (id)
 887 - (id)accessibilityMinValueAttribute
 888 {
 889     static JNF_STATIC_MEMBER_CACHE(jm_getMinimumAccessibleValue, sjc_CAccessibility, "getMinimumAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/Number;");
 890 
 891     JNIEnv* env = [ThreadUtilities getJNIEnv];



 892 
 893     jobject axValue = JNFCallStaticObjectMethod(env, jm_getMinimumAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)

 894     if (axValue == NULL) {
 895         return [NSNumber numberWithInt:0];
 896     }
 897     NSNumber* num = JNFJavaToNSNumber(env, axValue);
 898     (*env)->DeleteLocalRef(env, axValue);
 899     return num;
 900 }
 901 
 902 - (BOOL)accessibilityIsMinValueAttributeSettable
 903 {
 904     return NO;
 905 }
 906 
 907 - (id)accessibilityOrientationAttribute
 908 {
 909     JNIEnv* env = [ThreadUtilities getJNIEnv];
 910     jobject axContext = [self axContextWithEnv:env];
 911 
 912     // cmcnote - should batch these two calls into one that returns an array of two bools, one for vertical and one for horiz
 913     if (isVertical(env, axContext, fComponent)) {
 914         (*env)->DeleteLocalRef(env, axContext);
 915         return NSAccessibilityVerticalOrientationValue;
 916     }
 917 


 927 - (BOOL)accessibilityIsOrientationAttributeSettable
 928 {
 929     return NO;
 930 }
 931 
 932 // Element containing current element (id)
 933 - (id)accessibilityParentAttribute
 934 {
 935     return NSAccessibilityUnignoredAncestor([self parent]);
 936 }
 937 
 938 - (BOOL)accessibilityIsParentAttributeSettable
 939 {
 940     return NO;
 941 }
 942 
 943 // Screen position of element's lower-left corner in lower-left relative screen coordinates (NSValue)
 944 - (NSValue *)accessibilityPositionAttribute
 945 {
 946     JNIEnv* env = [ThreadUtilities getJNIEnv];
 947     jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)



 948 
 949     // NSAccessibility wants the bottom left point of the object in
 950     // bottom left based screen coords
 951 
 952     // Get the java screen coords, and make a NSPoint of the bottom left of the AxComponent.
 953     NSSize size = getAxComponentSize(env, axComponent, fComponent);
 954     NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
 955     (*env)->DeleteLocalRef(env, axComponent);
 956 
 957     point.y += size.height;
 958 
 959     // Now make it into Cocoa screen coords.
 960     point.y = [[[[self view] window] screen] frame].size.height - point.y;
 961 
 962     return [NSValue valueWithPoint:point];
 963 }
 964 
 965 - (BOOL)accessibilityIsPositionAttributeSettable
 966 {
 967     // In AppKit, position is only settable for a window (NSAccessibilityWindowRole). Our windows are taken care of natively, so we don't need to deal with this here


 988             fNSRole = javaRole;
 989         }
 990         [fNSRole retain];
 991     }
 992     return fNSRole;
 993 }
 994 
 995 - (BOOL)accessibilityIsRoleAttributeSettable
 996 {
 997     return NO;
 998 }
 999 
1000 // Localized, user-readable description of role, such as radio button (NSString)
1001 - (NSString *)accessibilityRoleDescriptionAttribute
1002 {
1003     // first ask AppKit for its accessible role description for a given AXRole
1004     NSString *value = NSAccessibilityRoleDescription([self accessibilityRoleAttribute], nil);
1005 
1006     if (value == nil) {
1007         // query java if necessary
1008         static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleRoleDisplayString, sjc_CAccessibility, "getAccessibleRoleDisplayString", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
1009 
1010         JNIEnv* env = [ThreadUtilities getJNIEnv];



1011 
1012         jobject axRole = JNFCallStaticObjectMethod(env, jm_getAccessibleRoleDisplayString, fAccessible, fComponent);


1013         if (axRole != NULL) {
1014             value = JNFJavaToNSString(env, axRole);
1015             (*env)->DeleteLocalRef(env, axRole);
1016         } else {
1017             value = @"unknown";
1018         }
1019     }
1020 
1021     return value;
1022 }
1023 
1024 - (BOOL)accessibilityIsRoleDescriptionAttributeSettable
1025 {
1026     return NO;
1027 }
1028 
1029 // Currently selected children (NSArray)
1030 - (NSArray *)accessibilitySelectedChildrenAttribute
1031 {
1032     JNIEnv* env = [ThreadUtilities getJNIEnv];
1033     NSArray *selectedChildren = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_SELECTED_CHILDREN allowIgnored:NO];
1034     if ([selectedChildren count] > 0) {


1042 {
1043     return NO; // cmcnote: actually it should be. so need to write accessibilitySetSelectedChildrenAttribute also
1044 }
1045 
1046 - (NSNumber *)accessibilitySelectedAttribute
1047 {
1048     return [NSNumber numberWithBool:[self isSelected:[ThreadUtilities getJNIEnv]]];
1049 }
1050 
1051 - (BOOL)accessibilityIsSelectedAttributeSettable
1052 {
1053     if ([self isSelectable:[ThreadUtilities getJNIEnv]]) {
1054         return YES;
1055     } else {
1056         return NO;
1057     }
1058 }
1059 
1060 - (void)accessibilitySetSelectedAttribute:(id)value
1061 {
1062     static JNF_STATIC_MEMBER_CACHE( jm_requestSelection,


1063                                     sjc_CAccessibility,
1064                                     "requestSelection",
1065                                     "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)V" );
1066 
1067     if ([(NSNumber*)value boolValue]) {
1068         JNIEnv* env = [ThreadUtilities getJNIEnv];
1069         JNFCallStaticVoidMethod(env, jm_requestSelection, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
1070     }
1071 }
1072 
1073 // Element size (NSValue)
1074 - (NSValue *)accessibilitySizeAttribute {
1075     JNIEnv* env = [ThreadUtilities getJNIEnv];
1076     jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)



1077     NSValue* size = [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
1078     (*env)->DeleteLocalRef(env, axComponent);
1079     return size;
1080 }
1081 
1082 - (BOOL)accessibilityIsSizeAttributeSettable
1083 {
1084     // SIZE is settable in windows if [self styleMask] & NSResizableWindowMask - but windows are heavyweight so we're ok here
1085     // SIZE is settable in columns if [[self tableValue] allowsColumnResizing - haven't dealt with columns yet
1086     return NO;
1087 }
1088 
1089 // Element subrole type, such as NSAccessibilityTableRowSubrole (NSString). See the subrole attribute table at
1090 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
1091 - (NSString *)accessibilitySubroleAttribute
1092 {
1093     NSString *value = nil;
1094     if ([[self javaRole] isEqualToString:@"passwordtext"]) {
1095         value = NSAccessibilitySecureTextFieldSubrole;
1096     }


1116      NSAccessibilitySearchFieldSubrole    //no
1117      */
1118     return value;
1119 }
1120 
1121 - (BOOL)accessibilityIsSubroleAttributeSettable
1122 {
1123     return NO;
1124 }
1125 
1126 // Title of element, such as button text (NSString)
1127 - (NSString *)accessibilityTitleAttribute
1128 {
1129     // Return empty string for labels, since their value and tile end up being the same thing and this leads to repeated text.
1130     if ([[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityStaticTextRole]) {
1131         return @"";
1132     }
1133 
1134     JNIEnv* env = [ThreadUtilities getJNIEnv];
1135 
1136     jobject val = JNFCallStaticObjectMethod(env, sjm_getAccessibleName, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)


1137     if (val == NULL) {
1138         return nil;
1139     }
1140     NSString* str = JNFJavaToNSString(env, val);
1141     (*env)->DeleteLocalRef(env, val);
1142     return str;
1143 }
1144 
1145 - (BOOL)accessibilityIsTitleAttributeSettable
1146 {
1147     return NO;
1148 }
1149 
1150 - (NSWindow *)accessibilityTopLevelUIElementAttribute
1151 {
1152     return [self window];
1153 }
1154 
1155 - (BOOL)accessibilityIsTopLevelUIElementAttributeSettable
1156 {
1157     return NO;
1158 }
1159 
1160 // Element's value (id)
1161 // note that the appKit meaning of "accessibilityValue" is different from the java
1162 // meaning of "accessibleValue", which is specific to numerical values
1163 // (https://docs.oracle.com/javase/8/docs/api/javax/accessibility/AccessibleValue.html#setCurrentAccessibleValue-java.lang.Number-)
1164 - (id)accessibilityValueAttribute
1165 {
1166     static JNF_STATIC_MEMBER_CACHE(jm_getCurrentAccessibleValue, sjc_CAccessibility, "getCurrentAccessibleValue", "(Ljavax/accessibility/AccessibleValue;Ljava/awt/Component;)Ljava/lang/Number;");
1167 
1168     JNIEnv* env = [ThreadUtilities getJNIEnv];
1169 
1170     // Need to handle popupmenus differently.
1171     //
1172     // At least for now don't handle combo box menus.
1173     // This may change when later fixing issues which currently
1174     // exist for combo boxes, but for now the following is only
1175     // for JPopupMenus, not for combobox menus.
1176     id parent = [self parent];
1177     if ( [[self javaRole] isEqualToString:@"popupmenu"] &&
1178          ![[parent javaRole] isEqualToString:@"combobox"] ) {
1179         NSArray *children =
1180             [JavaComponentAccessibility childrenOfParent:self
1181                                         withEnv:env
1182                                         withChildrenCode:JAVA_AX_ALL_CHILDREN
1183                                         allowIgnored:YES];
1184         if ([children count] > 0) {
1185             // handle case of AXMenuItem
1186             // need to ask menu what is selected
1187             NSArray *selectedChildrenOfMenu =
1188                 [self accessibilitySelectedChildrenAttribute];
1189             JavaComponentAccessibility *selectedMenuItem =
1190                 [selectedChildrenOfMenu objectAtIndex:0];
1191             if (selectedMenuItem != nil) {


1192                 jobject itemValue =
1193                         JNFCallStaticObjectMethod( env,
1194                                                    sjm_getAccessibleName,
1195                                                    selectedMenuItem->fAccessible,
1196                                                    selectedMenuItem->fComponent ); // AWT_THREADING Safe (AWTRunLoop)

1197                 if (itemValue == NULL) {
1198                     return nil;
1199                 }
1200                 NSString* itemString = JNFJavaToNSString(env, itemValue);
1201                 (*env)->DeleteLocalRef(env, itemValue);
1202                 return itemString;
1203             } else {
1204                 return nil;
1205             }
1206         }
1207     }
1208 
1209     // ask Java for the component's accessibleValue. In java, the "accessibleValue" just means a numerical value
1210     // a text value is taken care of in JavaTextAccessibility
1211 
1212     // cmcnote should coalesce these calls into one java call
1213     NSNumber *num = nil;
1214     jobject axValue = JNFCallStaticObjectMethod(env, sjm_getAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)




1215     if (axValue != NULL) {
1216         jobject str = JNFCallStaticObjectMethod(env, jm_getCurrentAccessibleValue, axValue, fComponent);



1217         if (str != NULL) {
1218             num = JNFJavaToNSNumber(env, str); // AWT_THREADING Safe (AWTRunLoop)
1219             (*env)->DeleteLocalRef(env, str);
1220         }
1221         (*env)->DeleteLocalRef(env, axValue);
1222     }
1223     if (num == nil) {
1224         num = [NSNumber numberWithInt:0];
1225     }
1226     return num;
1227 }
1228 
1229 - (BOOL)accessibilityIsValueAttributeSettable
1230 {
1231     // according ot AppKit sources, in general the value attribute is not settable, except in the cases
1232     // of an NSScroller, an NSSplitView, and text that's both enabled & editable
1233     BOOL isSettable = NO;
1234     NSString *role = [self accessibilityRoleAttribute];
1235 
1236     if ([role isEqualToString:NSAccessibilityScrollBarRole] || // according to NSScrollerAccessibility
1237         [role isEqualToString:NSAccessibilitySplitGroupRole] ) // according to NSSplitViewAccessibility
1238     {


1294 {
1295     AWT_ASSERT_APPKIT_THREAD;
1296 
1297     JNIEnv *env = [ThreadUtilities getJNIEnv];
1298     [(id <JavaAccessibilityAction>)[[self getActions:env] objectForKey:action] perform];
1299 }
1300 
1301 
1302 // -- misc accessibility --
1303 - (BOOL)accessibilityIsIgnored
1304 {
1305 #ifdef JAVA_AX_NO_IGNORES
1306     return NO;
1307 #else
1308     return [[self accessibilityRoleAttribute] isEqualToString:JavaAccessibilityIgnore];
1309 #endif /* JAVA_AX_NO_IGNORES */
1310 }
1311 
1312 - (id)accessibilityHitTest:(NSPoint)point withEnv:(JNIEnv *)env
1313 {
1314     static JNF_CLASS_CACHE(jc_Container, "java/awt/Container");
1315     static JNF_STATIC_MEMBER_CACHE(jm_accessibilityHitTest, sjc_CAccessibility, "accessibilityHitTest", "(Ljava/awt/Container;FF)Ljavax/accessibility/Accessible;");

1316 
1317     // Make it into java screen coords
1318     point.y = [[[[self view] window] screen] frame].size.height - point.y;
1319 
1320     jobject jparent = fComponent;
1321 
1322     id value = nil;
1323     if (JNFIsInstanceOf(env, jparent, &jc_Container)) {
1324         jobject jaccessible = JNFCallStaticObjectMethod(env, jm_accessibilityHitTest, jparent, (jfloat)point.x, (jfloat)point.y); // AWT_THREADING Safe (AWTRunLoop)


1325         if (jaccessible != NULL) {
1326             value = [JavaComponentAccessibility createWithAccessible:jaccessible withEnv:env withView:fView];
1327             (*env)->DeleteLocalRef(env, jaccessible);
1328         }
1329     }
1330 
1331     if (value == nil) {
1332         value = self;
1333     }
1334 
1335     if ([value accessibilityIsIgnored]) {
1336         value = NSAccessibilityUnignoredAncestor(value);
1337     }
1338 
1339 #ifdef JAVA_AX_DEBUG
1340     NSLog(@"%s: %@", __FUNCTION__, value);
1341 #endif
1342     return value;
1343 }
1344 
1345 - (id)accessibilityFocusedUIElement
1346 {
1347     static JNF_STATIC_MEMBER_CACHE(jm_getFocusOwner, sjc_CAccessibility, "getFocusOwner", "(Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
1348 
1349     JNIEnv *env = [ThreadUtilities getJNIEnv];



1350     id value = nil;
1351 
1352     NSWindow* hostWindow = [[self->fView window] retain];
1353     jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop)
1354     [hostWindow release];

1355 
1356     if (focused != NULL) {
1357         if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) {

1358             value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
1359         }

1360         (*env)->DeleteLocalRef(env, focused);
1361     }
1362 
1363     if (value == nil) {
1364         value = self;
1365     }
1366 #ifdef JAVA_AX_DEBUG
1367     NSLog(@"%s: %@", __FUNCTION__, value);
1368 #endif
1369     return value;
1370 }
1371 
1372 @end
1373 
1374 /*
1375  * Class:     sun_lwawt_macosx_CAccessibility
1376  * Method:    focusChanged
1377  * Signature: ()V
1378  */
1379 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
1380 (JNIEnv *env, jobject jthis)
1381 {
1382 JNF_COCOA_ENTER(env);
1383     [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO];
1384 JNF_COCOA_EXIT(env);
1385 }
1386 
1387 /*
1388  * Class:     sun_lwawt_macosx_CAccessible
1389  * Method:    valueChanged
1390  * Signature: (I)V
1391  */
1392 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged
1393 (JNIEnv *env, jclass jklass, jlong element)
1394 {
1395 JNF_COCOA_ENTER(env);
1396     [ThreadUtilities performOnMainThread:@selector(postValueChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1397 JNF_COCOA_EXIT(env);
1398 }
1399 
1400 /*
1401  * Class:     sun_lwawt_macosx_CAccessible
1402  * Method:    selectedTextChanged
1403  * Signature: (I)V
1404  */
1405 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectedTextChanged
1406 (JNIEnv *env, jclass jklass, jlong element)
1407 {
1408 JNF_COCOA_ENTER(env);
1409     [ThreadUtilities performOnMainThread:@selector(postSelectedTextChanged)
1410                      on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1411                      withObject:nil
1412                      waitUntilDone:NO];
1413 JNF_COCOA_EXIT(env);
1414 }
1415 
1416 /*
1417  * Class:     sun_lwawt_macosx_CAccessible
1418  * Method:    selectionChanged
1419  * Signature: (I)V
1420  */
1421 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged
1422 (JNIEnv *env, jclass jklass, jlong element)
1423 {
1424 JNF_COCOA_ENTER(env);
1425     [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1426 JNF_COCOA_EXIT(env);
1427 }
1428 
1429 /*
1430  * Class:     sun_lwawt_macosx_CAccessible
1431  * Method:    menuOpened
1432  * Signature: (I)V
1433  */
1434 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened
1435 (JNIEnv *env, jclass jklass, jlong element)
1436 {
1437 JNF_COCOA_ENTER(env);
1438     [ThreadUtilities performOnMainThread:@selector(postMenuOpened)
1439                      on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1440                      withObject:nil
1441                      waitUntilDone:NO];
1442 JNF_COCOA_EXIT(env);
1443 }
1444 
1445 /*
1446  * Class:     sun_lwawt_macosx_CAccessible
1447  * Method:    menuClosed
1448  * Signature: (I)V
1449  */
1450 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed
1451 (JNIEnv *env, jclass jklass, jlong element)
1452 {
1453 JNF_COCOA_ENTER(env);
1454     [ThreadUtilities performOnMainThread:@selector(postMenuClosed)
1455                      on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1456                      withObject:nil
1457                      waitUntilDone:NO];
1458 JNF_COCOA_EXIT(env);
1459 }
1460 
1461 /*
1462  * Class:     sun_lwawt_macosx_CAccessible
1463  * Method:    menuItemSelected
1464  * Signature: (I)V
1465  */
1466 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected
1467 (JNIEnv *env, jclass jklass, jlong element)
1468 {
1469 JNF_COCOA_ENTER(env);
1470     [ThreadUtilities performOnMainThread:@selector(postMenuItemSelected)
1471                      on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1472                      withObject:nil
1473                      waitUntilDone:NO];
1474 JNF_COCOA_EXIT(env);
1475 }
1476 
1477 /*
1478  * Class:     sun_lwawt_macosx_CAccessible
1479  * Method:    unregisterFromCocoaAXSystem
1480  * Signature: (I)V
1481  */
1482 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSystem
1483 (JNIEnv *env, jclass jklass, jlong element)
1484 {
1485 JNF_COCOA_ENTER(env);
1486     [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1487 JNF_COCOA_EXIT(env);
1488 }
1489 
1490 @implementation TabGroupAccessibility
1491 
1492 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
1493 {
1494     self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
1495     if (self) {
1496         _numTabs = -1; //flag for uninitialized numTabs
1497     }
1498     return self;
1499 }
1500 
1501 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
1502 {
1503     NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
1504 
1505     [names addObject:NSAccessibilityTabsAttribute];
1506     [names addObject:NSAccessibilityContentsAttribute];
1507     [names addObject:NSAccessibilityValueAttribute];


1517     jobject selAccessible = getAxContextSelection(env, axContext, 0, fComponent);
1518     if (selAccessible == NULL) return nil;
1519 
1520     // Go through the tabs and find selAccessible
1521     _numTabs = [tabs count];
1522     JavaComponentAccessibility *aTab;
1523     NSInteger i;
1524     for (i = 0; i < _numTabs; i++) {
1525         aTab = (JavaComponentAccessibility *)[tabs objectAtIndex:i];
1526         if ([aTab isAccessibleWithEnv:env forAccessible:selAccessible]) {
1527             (*env)->DeleteLocalRef(env, selAccessible);
1528             return aTab;
1529         }
1530     }
1531     (*env)->DeleteLocalRef(env, selAccessible);
1532     return nil;
1533 }
1534 
1535 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
1536 {
1537     jobjectArray jtabsAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, fAccessible, fComponent, whichTabs, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)



1538     if(jtabsAndRoles == NULL) return nil;
1539 
1540     jsize arrayLen = (*env)->GetArrayLength(env, jtabsAndRoles);
1541     if (arrayLen == 0) {
1542         (*env)->DeleteLocalRef(env, jtabsAndRoles);
1543         return nil;
1544     }
1545     NSMutableArray *tabs = [NSMutableArray arrayWithCapacity:(arrayLen/2)];
1546 
1547     // all of the tabs have the same role, so we can just find out what that is here and use it for all the tabs
1548     jobject jtabJavaRole = (*env)->GetObjectArrayElement(env, jtabsAndRoles, 1); // the array entries alternate between tab/role, starting with tab. so the first role is entry 1.
1549     if (jtabJavaRole == NULL) {
1550         (*env)->DeleteLocalRef(env, jtabsAndRoles);
1551         return nil;
1552     }
1553     jobject jkey = JNFGetObjectField(env, jtabJavaRole, sjf_key);
1554     NSString *tabJavaRole = JNFJavaToNSString(env, jkey);



1555     (*env)->DeleteLocalRef(env, jkey);
1556 
1557     NSInteger i;
1558     NSUInteger tabIndex = (whichTabs >= 0) ? whichTabs : 0; // if we're getting one particular child, make sure to set its index correctly
1559     for(i = 0; i < arrayLen; i+=2) {
1560         jobject jtab = (*env)->GetObjectArrayElement(env, jtabsAndRoles, i);
1561         JavaComponentAccessibility *tab = [[[TabGroupControlAccessibility alloc] initWithParent:self withEnv:env withAccessible:jtab withIndex:tabIndex withTabGroup:axContext withView:[self view] withJavaRole:tabJavaRole] autorelease];
1562         (*env)->DeleteLocalRef(env, jtab);
1563         [tabs addObject:tab];
1564         tabIndex++;
1565     }
1566     (*env)->DeleteLocalRef(env, jtabsAndRoles);
1567     return tabs;
1568 }
1569 
1570 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
1571 {
1572     // Contents are the children of the selected tab.
1573     id currentTab = [self currentTabWithEnv:env withAxContext:axContext];
1574     if (currentTab == nil) return nil;


1676         }
1677         (*env)->DeleteLocalRef(env, axContext);
1678     } else {
1679         result = [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
1680     }
1681     return result;
1682 }
1683 
1684 @end
1685 
1686 
1687 static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
1688 
1689 @implementation TabGroupControlAccessibility
1690 
1691 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
1692 {
1693     self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
1694     if (self) {
1695         if (tabGroup != NULL) {
1696             fTabGroupAxContext = JNFNewWeakGlobalRef(env, tabGroup);

1697         } else {
1698             fTabGroupAxContext = NULL;
1699         }
1700     }
1701     return self;
1702 }
1703 
1704 - (void)dealloc
1705 {
1706     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
1707 
1708     if (fTabGroupAxContext != NULL) {
1709         JNFDeleteWeakGlobalRef(env, fTabGroupAxContext);
1710         fTabGroupAxContext = NULL;
1711     }
1712 
1713     [super dealloc];
1714 }
1715 
1716 - (id)accessibilityValueAttribute
1717 {
1718     JNIEnv *env = [ThreadUtilities getJNIEnv];
1719     jobject axContext = [self axContextWithEnv:env];
1720     jobject selAccessible = getAxContextSelection(env, [self tabGroup], fIndex, fComponent);
1721 
1722     // Returns the current selection of the page tab list
1723     id val = [NSNumber numberWithBool:ObjectEquals(env, axContext, selAccessible, fComponent)];
1724 
1725     (*env)->DeleteLocalRef(env, selAccessible);
1726     (*env)->DeleteLocalRef(env, axContext);
1727     return val;
1728 }
1729 
1730 - (void)getActionsWithEnv:(JNIEnv *)env
1731 {
1732     TabGroupAction *action = [[TabGroupAction alloc] initWithEnv:env withTabGroup:[self tabGroup] withIndex:fIndex withComponent:fComponent];
1733     [fActions setObject:action forKey:NSAccessibilityPressAction];
1734     [action release];
1735 }
1736 
1737 - (jobject)tabGroup
1738 {
1739     if (fTabGroupAxContext == NULL) {
1740         JNIEnv* env = [ThreadUtilities getJNIEnv];
1741         jobject tabGroupAxContext = [(JavaComponentAccessibility *)[self parent] axContextWithEnv:env];
1742         fTabGroupAxContext = JNFNewWeakGlobalRef(env, tabGroupAxContext);

1743         (*env)->DeleteLocalRef(env, tabGroupAxContext);
1744     }
1745     return fTabGroupAxContext;
1746 }
1747 
1748 @end
1749 
1750 
1751 @implementation ScrollAreaAccessibility
1752 
1753 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
1754 {
1755     NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
1756 
1757     [names addObject:NSAccessibilityHorizontalScrollBarAttribute];
1758     [names addObject:NSAccessibilityVerticalScrollBarAttribute];
1759     [names addObject:NSAccessibilityContentsAttribute];
1760 
1761     return names;
1762 }


1835             // no scroll bars in contents
1836             [(NSMutableArray *)contents addObject:aElement];
1837         }
1838     }
1839 
1840     return contents;
1841 }
1842 
1843 - (BOOL)accessibilityIsContentsAttributeSettable
1844 {
1845     return NO;
1846 }
1847 
1848 @end
1849 
1850 /*
1851  * Returns Object.equals for the two items
1852  * This may use LWCToolkit.invokeAndWait(); don't call while holding fLock
1853  * and try to pass a component so the event happens on the correct thread.
1854  */
1855 static JNF_CLASS_CACHE(sjc_Object, "java/lang/Object");
1856 static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component)
1857 {
1858     static JNF_MEMBER_CACHE(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z");

1859 
1860     if ((a == NULL) && (b == NULL)) return YES;
1861     if ((a == NULL) || (b == NULL)) return NO;
1862 
1863     if (pthread_main_np() != 0) {
1864         // If we are on the AppKit thread
1865         static JNF_CLASS_CACHE(sjc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit");
1866         static JNF_STATIC_MEMBER_CACHE(jm_doEquals, sjc_LWCToolkit, "doEquals", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/awt/Component;)Z");
1867         return JNFCallStaticBooleanMethod(env, jm_doEquals, a, b, component); // AWT_THREADING Safe (AWTRunLoopMode)


1868     }
1869 
1870     return JNFCallBooleanMethod(env, a, jm_equals, b); // AWT_THREADING Safe (!appKit)


1871 }


  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 // External Java Accessibility links:
  27 //
  28 // <https://docs.oracle.com/javase/8/docs/technotes/guides/access/index.html>
  29 // <http://www-106.ibm.com/developerworks/library/j-access/?n-j-10172>
  30 // <http://archives.java.sun.com/archives/java-access.html> (Sun's mailing list for Java accessibility)
  31 
  32 #import "JavaComponentAccessibility.h"
  33 
  34 #import "sun_lwawt_macosx_CAccessibility.h"
  35 
  36 #import <AppKit/AppKit.h>
  37 

  38 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
  39 
  40 #import <dlfcn.h>
  41 
  42 #import "JavaAccessibilityAction.h"
  43 #import "JavaAccessibilityUtilities.h"
  44 #import "JavaTextAccessibility.h"
  45 #import "ThreadUtilities.h"
  46 #import "JNIUtilities.h"
  47 #import "AWTView.h"
  48 
  49 
  50 // these constants are duplicated in CAccessibility.java
  51 #define JAVA_AX_ALL_CHILDREN (-1)
  52 #define JAVA_AX_SELECTED_CHILDREN (-2)
  53 #define JAVA_AX_VISIBLE_CHILDREN (-3)
  54 // If the value is >=0, it's an index
  55 
  56 // GET* macros defined in JavaAccessibilityUtilities.h, so they can be shared.
  57 static jclass sjc_CAccessibility = NULL;





  58 
  59 static jmethodID sjm_getAccessibleName = NULL;
  60 #define GET_ACCESSIBLENAME_METHOD_RETURN(ret) \
  61     GET_CACCESSIBILITY_CLASS_RETURN(ret); \
  62     GET_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", \
  63                      "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", ret);
  64 
  65 static jmethodID jm_getChildrenAndRoles = NULL;
  66 #define GET_CHILDRENANDROLES_METHOD_RETURN(ret) \
  67     GET_CACCESSIBILITY_CLASS_RETURN(ret); \
  68     GET_STATIC_METHOD_RETURN(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles",\
  69                       "(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;", ret);
  70 
  71 static jmethodID sjm_getAccessibleComponent = NULL;
  72 #define GET_ACCESSIBLECOMPONENT_STATIC_METHOD_RETURN(ret) \
  73     GET_CACCESSIBILITY_CLASS_RETURN(ret); \
  74     GET_STATIC_METHOD_RETURN(sjm_getAccessibleComponent, sjc_CAccessibility, "getAccessibleComponent", \
  75            "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleComponent;", ret);
  76 
  77 static jmethodID sjm_getAccessibleIndexInParent = NULL;
  78 #define GET_ACCESSIBLEINDEXINPARENT_STATIC_METHOD_RETURN(ret) \
  79     GET_CACCESSIBILITY_CLASS_RETURN(ret); \
  80     GET_STATIC_METHOD_RETURN(sjm_getAccessibleIndexInParent, sjc_CAccessibility, "getAccessibleIndexInParent", \
  81                              "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I", ret);
  82 
  83 static jclass sjc_CAccessible = NULL;
  84 #define GET_CACCESSIBLE_CLASS_RETURN(ret) \
  85     GET_CLASS_RETURN(sjc_CAccessible, "sun/lwawt/macosx/CAccessible", ret);
  86 


  87 
  88 static jobject sAccessibilityClass = NULL;
  89 
  90 // sAttributeNamesForRoleCache holds the names of the attributes to which each java
  91 // AccessibleRole responds (see AccessibleRole.java).
  92 // This cache is queried before attempting to access a given attribute for a particular role.
  93 static NSMutableDictionary *sAttributeNamesForRoleCache = nil;
  94 static NSObject *sAttributeNamesLOCK = nil;
  95 
  96 @interface TabGroupAccessibility : JavaComponentAccessibility {
  97     NSInteger _numTabs;
  98 }
  99 
 100 - (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
 101 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
 102 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
 103 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
 104 
 105 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
 106 - (NSArray *)accessibilityChildrenAttribute;


 258     return (*env)->IsSameObject(env, accessibility->fAccessible, fAccessible);
 259 }
 260 
 261 - (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible
 262 {
 263     return (*env)->IsSameObject(env, fAccessible, accessible);
 264 }
 265 
 266 + (void)initialize
 267 {
 268     if (sAttributeNamesForRoleCache == nil) {
 269         sAttributeNamesLOCK = [[NSObject alloc] init];
 270         sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:60];
 271     }
 272 
 273     if (sRoles == nil) {
 274         initializeRoles();
 275     }
 276 
 277     if (sAccessibilityClass == NULL) {
 278         JNIEnv *env = [ThreadUtilities getJNIEnv];
 279 
 280         GET_CACCESSIBILITY_CLASS();
 281         DECLARE_STATIC_METHOD(jm_getAccessibility, sjc_CAccessibility, "getAccessibility", "([Ljava/lang/String;)Lsun/lwawt/macosx/CAccessibility;");
 282 
 283 #ifdef JAVA_AX_NO_IGNORES
 284         NSArray *ignoredKeys = [NSArray array];
 285 #else
 286         NSArray *ignoredKeys = [sRoles allKeysForObject:JavaAccessibilityIgnore];
 287 #endif
 288         jobjectArray result = NULL;
 289         jsize count = [ignoredKeys count];
 290 
 291         DECLARE_CLASS(jc_String, "java/lang/String");
 292         result = (*env)->NewObjectArray(env, count, jc_String, NULL);
 293         CHECK_EXCEPTION();

 294         if (!result) {
 295             NSLog(@"In %s, can't create Java array of String objects", __FUNCTION__);
 296             return;
 297         }
 298 
 299         NSInteger i;
 300         for (i = 0; i < count; i++) {
 301             jstring jString = NSStringToJavaString(env, [ignoredKeys objectAtIndex:i]);
 302             (*env)->SetObjectArrayElement(env, result, i, jString);
 303             (*env)->DeleteLocalRef(env, jString);
 304         }
 305 
 306         sAccessibilityClass = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getAccessibility, result); // AWT_THREADING Safe (known object)
 307         CHECK_EXCEPTION();
 308     }
 309 }
 310 
 311 + (void)postFocusChanged:(id)message
 312 {
 313     AWT_ASSERT_APPKIT_THREAD;
 314     NSAccessibilityPostNotification([NSApp accessibilityFocusedUIElement], NSAccessibilityFocusedUIElementChangedNotification);
 315 }
 316 
 317 + (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
 318     DECLARE_CLASS_RETURN(sjc_Accessible, "javax/accessibility/Accessible", NULL);
 319     GET_CACCESSIBLE_CLASS_RETURN(NULL);
 320     DECLARE_STATIC_METHOD_RETURN(sjm_getCAccessible, sjc_CAccessible, "getCAccessible",
 321                                 "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;", NULL);
 322     if ((*env)->IsInstanceOf(env, jaccessible, sjc_CAccessible)) {
 323         return jaccessible;
 324     } else if ((*env)->IsInstanceOf(env, jaccessible, sjc_Accessible)) {
 325         jobject o = (*env)->CallStaticObjectMethod(env, sjc_CAccessible,  sjm_getCAccessible, jaccessible);
 326         CHECK_EXCEPTION();
 327         return o;
 328     }
 329     return NULL;
 330 }
 331 
 332 + (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
 333 {
 334     if (parent->fAccessible == NULL) return nil;
 335     GET_CHILDRENANDROLES_METHOD_RETURN(nil);
 336     jobjectArray jchildrenAndRoles = (jobjectArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getChildrenAndRoles,
 337                   parent->fAccessible, parent->fComponent, whichChildren, allowIgnored);
 338     CHECK_EXCEPTION();
 339     if (jchildrenAndRoles == NULL) return nil;
 340 
 341     jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
 342     NSMutableArray *children = [NSMutableArray arrayWithCapacity:arrayLen/2]; //childrenAndRoles array contains two elements (child, role) for each child
 343 
 344     NSInteger i;
 345     NSUInteger childIndex = (whichChildren >= 0) ? whichChildren : 0; // if we're getting one particular child, make sure to set its index correctly
 346     for(i = 0; i < arrayLen; i+=2)
 347     {
 348         jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
 349         jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
 350 
 351         NSString *childJavaRole = nil;
 352         if (jchildJavaRole != NULL) {
 353             DECLARE_CLASS_RETURN(sjc_AccessibleRole, "javax/accessibility/AccessibleRole", nil);
 354             DECLARE_FIELD_RETURN(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;", nil);
 355             jobject jkey = (*env)->GetObjectField(env, jchildJavaRole, sjf_key);
 356             CHECK_EXCEPTION();
 357             childJavaRole = JavaStringToNSString(env, jkey);
 358             (*env)->DeleteLocalRef(env, jkey);
 359         }
 360 
 361         JavaComponentAccessibility *child = [self createWithParent:parent accessible:jchild role:childJavaRole index:childIndex withEnv:env withView:parent->fView];
 362 
 363         (*env)->DeleteLocalRef(env, jchild);
 364         (*env)->DeleteLocalRef(env, jchildJavaRole);
 365 
 366         [children addObject:child];
 367         childIndex++;
 368     }
 369     (*env)->DeleteLocalRef(env, jchildrenAndRoles);
 370 
 371     return children;
 372 }
 373 
 374 + (JavaComponentAccessibility *)createWithAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env withView:(NSView *)view
 375 {
 376     GET_ACCESSIBLEINDEXINPARENT_STATIC_METHOD_RETURN(nil);
 377     JavaComponentAccessibility *ret = nil;
 378     jobject jcomponent = [(AWTView *)view awtComponent:env];
 379     jint index = (*env)->CallStaticIntMethod(env, sjc_CAccessibility, sjm_getAccessibleIndexInParent, jaccessible, jcomponent);
 380     CHECK_EXCEPTION();
 381     if (index >= 0) {
 382       NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
 383       ret = [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
 384     }
 385     (*env)->DeleteLocalRef(env, jcomponent);
 386     return ret;
 387 }
 388 
 389 + (JavaComponentAccessibility *) createWithAccessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
 390 {
 391     return [self createWithParent:nil accessible:jaccessible role:javaRole index:index withEnv:env withView:view];
 392 }
 393 
 394 + (JavaComponentAccessibility *) createWithParent:(JavaComponentAccessibility *)parent accessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
 395 {
 396     GET_CACCESSIBLE_CLASS_RETURN(NULL);
 397     DECLARE_FIELD_RETURN(jf_ptr, sjc_CAccessible, "ptr", "J", NULL);
 398     // try to fetch the jCAX from Java, and return autoreleased
 399     jobject jCAX = [JavaComponentAccessibility getCAccessible:jaccessible withEnv:env];
 400     if (jCAX == NULL) return nil;
 401     JavaComponentAccessibility *value = (JavaComponentAccessibility *) jlong_to_ptr((*env)->GetLongField(env, jCAX, jf_ptr));
 402     if (value != nil) {
 403         (*env)->DeleteLocalRef(env, jCAX);
 404         return [[value retain] autorelease];
 405     }
 406 
 407     // otherwise, create a new instance
 408     JavaComponentAccessibility *newChild = nil;
 409     if ([javaRole isEqualToString:@"pagetablist"]) {
 410         newChild = [TabGroupAccessibility alloc];
 411     } else if ([javaRole isEqualToString:@"scrollpane"]) {
 412         newChild = [ScrollAreaAccessibility alloc];
 413     } else {
 414         NSString *nsRole = [sRoles objectForKey:javaRole];
 415         if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
 416             newChild = [JavaTextAccessibility alloc];
 417         } else {
 418             newChild = [JavaComponentAccessibility alloc];
 419         }
 420     }
 421 
 422     // must init freshly -alloc'd object
 423     [newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
 424 
 425     // If creating a JPopupMenu (not a combobox popup list) need to fire menuOpened.
 426     // This is the only way to know if the menu is opening; visible state change
 427     // can't be caught because the listeners are not set up in time.
 428     if ( [javaRole isEqualToString:@"popupmenu"] &&
 429          ![[parent javaRole] isEqualToString:@"combobox"] ) {
 430         [newChild postMenuOpened];
 431     }
 432 
 433     // must hard retain pointer poked into Java object
 434     [newChild retain];
 435     (*env)->SetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
 436     (*env)->DeleteLocalRef(env, jCAX);
 437 
 438     // return autoreleased instance
 439     return [newChild autorelease];
 440 }
 441 
 442 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
 443 {
 444     GET_CACCESSIBILITY_CLASS_RETURN(nil);
 445     DECLARE_STATIC_METHOD_RETURN(jm_getInitialAttributeStates, sjc_CAccessibility, "getInitialAttributeStates",
 446                                   "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[Z", nil);
 447 
 448     NSMutableArray *attributeNames = [NSMutableArray arrayWithCapacity:20];
 449     [attributeNames retain];
 450 
 451     // all elements respond to parent, role, role description, window, topLevelUIElement, help
 452     [attributeNames addObject:NSAccessibilityParentAttribute];
 453     [attributeNames addObject:NSAccessibilityRoleAttribute];
 454     [attributeNames addObject:NSAccessibilityRoleDescriptionAttribute];
 455     [attributeNames addObject:NSAccessibilityHelpAttribute];
 456 
 457     // cmcnote: AXMenu usually doesn't respond to window / topLevelUIElement. But menus within a Java app's window
 458     // probably should. Should we use some role other than AXMenu / AXMenuBar for Java menus?
 459     [attributeNames addObject:NSAccessibilityWindowAttribute];
 460     [attributeNames addObject:NSAccessibilityTopLevelUIElementAttribute];
 461 
 462     // set accessible subrole
 463     NSString *javaRole = [self javaRole];
 464     if (javaRole != nil && [javaRole isEqualToString:@"passwordtext"]) {
 465         //cmcnote: should turn this into a constant
 466         [attributeNames addObject:NSAccessibilitySubroleAttribute];
 467     }
 468 
 469     // Get all the other accessibility attributes states we need in one swell foop.
 470     // javaRole isn't pulled in because we need protected access to AccessibleRole.key
 471     jbooleanArray attributeStates = (jbooleanArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
 472                      jm_getInitialAttributeStates, fAccessible, fComponent);
 473     CHECK_EXCEPTION();
 474     if (attributeStates == NULL) return nil;
 475     jboolean *attributeStatesArray = (*env)->GetBooleanArrayElements(env, attributeStates, 0);
 476     if (attributeStatesArray == NULL) {
 477         // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
 478         NSLog(@"%s failed calling GetBooleanArrayElements", __FUNCTION__);
 479         return nil;
 480     }
 481 
 482     // if there's a component, it can be enabled and it has a size/position
 483     if (attributeStatesArray[0]) {
 484         [attributeNames addObject:NSAccessibilityEnabledAttribute];
 485         [attributeNames addObject:NSAccessibilitySizeAttribute];
 486         [attributeNames addObject:NSAccessibilityPositionAttribute];
 487     }
 488 
 489     // According to javadoc, a component that is focusable will return true from isFocusTraversable,
 490     // as well as having AccessibleState.FOCUSABLE in it's AccessibleStateSet.
 491     // We use the former heuristic; if the component focus-traversable, add a focused attribute
 492     // See also: accessibilityIsFocusedAttributeSettable
 493     if (attributeStatesArray[1])


 542     // Cleanup
 543     (*env)->ReleaseBooleanArrayElements(env, attributeStates, attributeStatesArray, JNI_ABORT);
 544 
 545     return attributeNames;
 546 }
 547 
 548 - (NSDictionary *)getActions:(JNIEnv *)env
 549 {
 550     @synchronized(fActionsLOCK) {
 551         if (fActions == nil) {
 552             fActions = [[NSMutableDictionary alloc] initWithCapacity:3];
 553             [self getActionsWithEnv:env];
 554         }
 555     }
 556 
 557     return fActions;
 558 }
 559 
 560 - (void)getActionsWithEnv:(JNIEnv *)env
 561 {
 562     GET_CACCESSIBILITY_CLASS();
 563     DECLARE_STATIC_METHOD(jm_getAccessibleAction, sjc_CAccessibility, "getAccessibleAction",
 564                            "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleAction;");
 565 
 566     // On MacOSX, text doesn't have actions, in java it does.
 567     // cmcnote: NOT TRUE - Editable text has AXShowMenu. Textfields have AXConfirm. Static text has no actions.
 568     jobject axAction = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getAccessibleAction, fAccessible, fComponent);
 569     CHECK_EXCEPTION();
 570     if (axAction != NULL) {
 571         //+++gdb NOTE: In MacOSX, there is just a single Action, not multiple. In java,
 572         //  the first one seems to be the most basic, so this will be used.
 573         // cmcnote: NOT TRUE - Sometimes there are multiple actions, eg sliders have AXDecrement AND AXIncrement (radr://3893192)
 574         JavaAxAction *action = [[JavaAxAction alloc] initWithEnv:env withAccessibleAction:axAction withIndex:0 withComponent:fComponent];
 575         [fActions setObject:action forKey:[self isMenu] ? NSAccessibilityPickAction : NSAccessibilityPressAction];
 576         [action release];
 577         (*env)->DeleteLocalRef(env, axAction);
 578     }
 579 }
 580 
 581 - (jobject)axContextWithEnv:(JNIEnv *)env
 582 {
 583     return getAxContext(env, fAccessible, fComponent);
 584 }
 585 
 586 - (id)parent
 587 {




 588     if(fParent == nil) {
 589         JNIEnv* env = [ThreadUtilities getJNIEnv];
 590         GET_CACCESSIBILITY_CLASS_RETURN(nil);
 591         DECLARE_STATIC_METHOD_RETURN(sjm_getAccessibleParent, sjc_CAccessibility, "getAccessibleParent",
 592                                  "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;", nil);
 593         GET_CACCESSIBLE_CLASS_RETURN(nil);
 594         DECLARE_STATIC_METHOD_RETURN(sjm_getSwingAccessible, sjc_CAccessible, "getSwingAccessible",
 595                                  "(Ljavax/accessibility/Accessible;)Ljavax/accessibility/Accessible;", nil);
 596         DECLARE_CLASS_RETURN(sjc_Window, "java/awt/Window", nil);
 597 
 598         jobject jparent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,  sjm_getAccessibleParent, fAccessible, fComponent);
 599         CHECK_EXCEPTION();
 600 
 601         if (jparent == NULL) {
 602             fParent = fView;
 603         } else {
 604             AWTView *view = fView;
 605             jobject jax = (*env)->CallStaticObjectMethod(env, sjc_CAccessible, sjm_getSwingAccessible, fAccessible);
 606             CHECK_EXCEPTION();
 607 
 608             if ((*env)->IsInstanceOf(env, jax, sjc_Window)) {
 609                 // In this case jparent is an owner toplevel and we should retrieve its own view
 610                 view = [AWTView awtView:env ofAccessible:jparent];
 611             }
 612             if (view != nil) {
 613                 fParent = [JavaComponentAccessibility createWithAccessible:jparent withEnv:env withView:view];
 614             }
 615             if (fParent == nil) {
 616                 fParent = fView;
 617             }
 618             (*env)->DeleteLocalRef(env, jparent);
 619             (*env)->DeleteLocalRef(env, jax );
 620         }
 621         [fParent retain];
 622     }
 623     return fParent;
 624 }
 625 
 626 - (NSView *)view
 627 {
 628     return fView;


 792     }
 793 
 794     return value;
 795 }
 796 
 797 - (BOOL)accessibilityIsChildrenAttributeSettable
 798 {
 799     return NO;
 800 }
 801 
 802 - (NSUInteger)accessibilityIndexOfChild:(id)child
 803 {
 804     // Only special-casing for Lists, for now. This allows lists to be accessible, fixing radr://3856139 "JLists are broken".
 805     // Will probably want to special-case for Tables when we implement them (radr://3096643 "Accessibility: Table").
 806     // In AppKit, NSMatrixAccessibility (which uses NSAccessibilityListRole), NSTableRowAccessibility, and NSTableViewAccessibility are the
 807     // only ones that override the default implementation in NSAccessibility
 808     if (![[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityListRole]) {
 809         return [super accessibilityIndexOfChild:child];
 810     }
 811 
 812     JNIEnv *env = [ThreadUtilities getJNIEnv];
 813     GET_ACCESSIBLEINDEXINPARENT_STATIC_METHOD_RETURN(0);
 814     jint returnValue =
 815         (*env)->CallStaticIntMethod( env,
 816                                 sjc_CAccessibility,
 817                                 sjm_getAccessibleIndexInParent,
 818                                 ((JavaComponentAccessibility *)child)->fAccessible,
 819                                 ((JavaComponentAccessibility *)child)->fComponent );
 820     CHECK_EXCEPTION();
 821     return (returnValue == -1) ? NSNotFound : returnValue;
 822 }
 823 
 824 // Without this optimization accessibilityChildrenAttribute is called in order to get the entire array of children.
 825 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount {
 826     if ( (maxCount == 1) && [attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
 827         // Children codes for ALL, SELECTED, VISIBLE are <0. If the code is >=0, we treat it as an index to a single child
 828         NSArray *child = [JavaComponentAccessibility childrenOfParent:self withEnv:[ThreadUtilities getJNIEnv] withChildrenCode:(NSInteger)index allowIgnored:NO];
 829         if ([child count] > 0) {
 830             return child;
 831         }
 832     }
 833     return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
 834 }
 835 
 836 // Flag indicating enabled state of element (NSNumber)
 837 - (NSNumber *)accessibilityEnabledAttribute
 838 {


 839     JNIEnv* env = [ThreadUtilities getJNIEnv];
 840     GET_CACCESSIBILITY_CLASS_RETURN(nil);
 841     DECLARE_STATIC_METHOD_RETURN(jm_isEnabled, sjc_CAccessibility, "isEnabled", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z", nil);
 842 
 843     NSNumber *value = [NSNumber numberWithBool:(*env)->CallStaticBooleanMethod(env, sjc_CAccessibility, jm_isEnabled, fAccessible, fComponent)];
 844     CHECK_EXCEPTION();
 845     if (value == nil) {
 846         NSLog(@"WARNING: %s called on component that has no accessible component: %@", __FUNCTION__, self);
 847     }
 848     return value;
 849 }
 850 
 851 - (BOOL)accessibilityIsEnabledAttributeSettable
 852 {
 853     return NO;
 854 }
 855 
 856 // Flag indicating presence of keyboard focus (NSNumber)
 857 - (NSNumber *)accessibilityFocusedAttribute
 858 {
 859     if ([self accessibilityIsFocusedAttributeSettable]) {
 860         return [NSNumber numberWithBool:[self isEqual:[NSApp accessibilityFocusedUIElement]]];
 861     }
 862     return [NSNumber numberWithBool:NO];
 863 }
 864 
 865 - (BOOL)accessibilityIsFocusedAttributeSettable
 866 {
 867     JNIEnv* env = [ThreadUtilities getJNIEnv];
 868     GET_CACCESSIBILITY_CLASS_RETURN(NO);
 869     DECLARE_STATIC_METHOD_RETURN(sjm_isFocusTraversable, sjc_CAccessibility, "isFocusTraversable",
 870                                  "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z", NO);
 871     // According to javadoc, a component that is focusable will return true from isFocusTraversable,
 872     // as well as having AccessibleState.FOCUSABLE in its AccessibleStateSet.
 873     // We use the former heuristic; if the component focus-traversable, add a focused attribute
 874     // See also initializeAttributeNamesWithEnv:
 875     if ((*env)->CallStaticBooleanMethod(env, sjc_CAccessibility, sjm_isFocusTraversable, fAccessible, fComponent)) {
 876         return YES;
 877     }
 878     CHECK_EXCEPTION();
 879 
 880     return NO;
 881 }
 882 
 883 - (void)accessibilitySetFocusedAttribute:(id)value
 884 {
 885     JNIEnv* env = [ThreadUtilities getJNIEnv];
 886 
 887     GET_CACCESSIBILITY_CLASS();
 888     DECLARE_STATIC_METHOD(jm_requestFocus, sjc_CAccessibility, "requestFocus", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)V");
 889 
 890     if ([(NSNumber*)value boolValue])
 891     {
 892         (*env)->CallStaticVoidMethod(env, sjc_CAccessibility, jm_requestFocus, fAccessible, fComponent);
 893         CHECK_EXCEPTION();
 894     }
 895 }
 896 
 897 // Instance description, such as a help tag string (NSString)
 898 - (NSString *)accessibilityHelpAttribute
 899 {
 900     JNIEnv* env = [ThreadUtilities getJNIEnv];
 901 
 902     GET_CACCESSIBILITY_CLASS_RETURN(nil);
 903     DECLARE_STATIC_METHOD_RETURN(sjm_getAccessibleDescription, sjc_CAccessibility, "getAccessibleDescription",
 904                                  "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil);
 905     jobject val = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
 906                                    sjm_getAccessibleDescription, fAccessible, fComponent);
 907     CHECK_EXCEPTION();
 908     if (val == NULL) {
 909         return nil;
 910     }
 911     NSString* str = JavaStringToNSString(env, val);
 912     (*env)->DeleteLocalRef(env, val);
 913     return str;
 914 }
 915 
 916 - (BOOL)accessibilityIsHelpAttributeSettable
 917 {
 918     return NO;
 919 }
 920 
 921 - (NSValue *)accessibilityIndexAttribute
 922 {
 923     NSInteger index = fIndex;
 924     NSValue *returnValue = [NSValue value:&index withObjCType:@encode(NSInteger)];
 925     return returnValue;
 926 }
 927 
 928 - (BOOL)accessibilityIsIndexAttributeSettable
 929 {
 930     return NO;
 931 }
 932 
 933 /*
 934  * The java/lang/Number concrete class could be for any of the Java primitive
 935  * numerical types or some other subclass.
 936  * All existing A11Y code uses Integer so that is what we look for first
 937  * But all must be able to return a double and NSNumber accepts a double,
 938  * so that's the fall back.
 939  */
 940 static NSNumber* JavaNumberToNSNumber(JNIEnv *env, jobject jnumber) {
 941     if (jnumber == NULL) {
 942         return nil;
 943     }
 944     DECLARE_CLASS_RETURN(jnumber_Class, "java/lang/Number", nil);
 945     DECLARE_CLASS_RETURN(jinteger_Class, "java/lang/Integer", nil);
 946     DECLARE_METHOD_RETURN(jm_intValue, jnumber_Class, "intValue", "()I", nil);
 947     DECLARE_METHOD_RETURN(jm_doubleValue, jnumber_Class, "doubleValue", "()D", nil);
 948     if ((*env)->IsInstanceOf(env, jnumber, jinteger_Class)) {
 949         jint i = (*env)->CallIntMethod(env, jnumber, jm_intValue);
 950         CHECK_EXCEPTION();
 951         return [NSNumber numberWithInteger:i];
 952     } else {
 953         jdouble d = (*env)->CallDoubleMethod(env, jnumber, jm_doubleValue);
 954         CHECK_EXCEPTION();
 955         return [NSNumber numberWithDouble:d];
 956     }
 957 }
 958 
 959 // Element's maximum value (id)
 960 - (id)accessibilityMaxValueAttribute
 961 {


 962     JNIEnv* env = [ThreadUtilities getJNIEnv];
 963     GET_CACCESSIBILITY_CLASS_RETURN(nil);
 964     DECLARE_STATIC_METHOD_RETURN(jm_getMaximumAccessibleValue, sjc_CAccessibility, "getMaximumAccessibleValue",
 965                                   "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/Number;", nil);
 966 
 967     jobject axValue = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getMaximumAccessibleValue, fAccessible, fComponent);
 968     CHECK_EXCEPTION();
 969     if (axValue == NULL) {
 970         return [NSNumber numberWithInt:0];
 971     }
 972     NSNumber* num = JavaNumberToNSNumber(env, axValue);
 973     (*env)->DeleteLocalRef(env, axValue);
 974     return num;
 975 }
 976 
 977 - (BOOL)accessibilityIsMaxValueAttributeSettable
 978 {
 979     return NO;
 980 }
 981 
 982 // Element's minimum value (id)
 983 - (id)accessibilityMinValueAttribute
 984 {


 985     JNIEnv* env = [ThreadUtilities getJNIEnv];
 986     GET_CACCESSIBILITY_CLASS_RETURN(nil);
 987     DECLARE_STATIC_METHOD_RETURN(jm_getMinimumAccessibleValue, sjc_CAccessibility, "getMinimumAccessibleValue",
 988                                   "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/Number;", nil);
 989 
 990     jobject axValue = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getMinimumAccessibleValue, fAccessible, fComponent);
 991     CHECK_EXCEPTION();
 992     if (axValue == NULL) {
 993         return [NSNumber numberWithInt:0];
 994     }
 995     NSNumber* num = JavaNumberToNSNumber(env, axValue);
 996     (*env)->DeleteLocalRef(env, axValue);
 997     return num;
 998 }
 999 
1000 - (BOOL)accessibilityIsMinValueAttributeSettable
1001 {
1002     return NO;
1003 }
1004 
1005 - (id)accessibilityOrientationAttribute
1006 {
1007     JNIEnv* env = [ThreadUtilities getJNIEnv];
1008     jobject axContext = [self axContextWithEnv:env];
1009 
1010     // cmcnote - should batch these two calls into one that returns an array of two bools, one for vertical and one for horiz
1011     if (isVertical(env, axContext, fComponent)) {
1012         (*env)->DeleteLocalRef(env, axContext);
1013         return NSAccessibilityVerticalOrientationValue;
1014     }
1015 


1025 - (BOOL)accessibilityIsOrientationAttributeSettable
1026 {
1027     return NO;
1028 }
1029 
1030 // Element containing current element (id)
1031 - (id)accessibilityParentAttribute
1032 {
1033     return NSAccessibilityUnignoredAncestor([self parent]);
1034 }
1035 
1036 - (BOOL)accessibilityIsParentAttributeSettable
1037 {
1038     return NO;
1039 }
1040 
1041 // Screen position of element's lower-left corner in lower-left relative screen coordinates (NSValue)
1042 - (NSValue *)accessibilityPositionAttribute
1043 {
1044     JNIEnv* env = [ThreadUtilities getJNIEnv];
1045     GET_ACCESSIBLECOMPONENT_STATIC_METHOD_RETURN(nil);
1046     jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleComponent,
1047                            fAccessible, fComponent);
1048     CHECK_EXCEPTION();
1049 
1050     // NSAccessibility wants the bottom left point of the object in
1051     // bottom left based screen coords
1052 
1053     // Get the java screen coords, and make a NSPoint of the bottom left of the AxComponent.
1054     NSSize size = getAxComponentSize(env, axComponent, fComponent);
1055     NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
1056     (*env)->DeleteLocalRef(env, axComponent);
1057 
1058     point.y += size.height;
1059 
1060     // Now make it into Cocoa screen coords.
1061     point.y = [[[[self view] window] screen] frame].size.height - point.y;
1062 
1063     return [NSValue valueWithPoint:point];
1064 }
1065 
1066 - (BOOL)accessibilityIsPositionAttributeSettable
1067 {
1068     // In AppKit, position is only settable for a window (NSAccessibilityWindowRole). Our windows are taken care of natively, so we don't need to deal with this here


1089             fNSRole = javaRole;
1090         }
1091         [fNSRole retain];
1092     }
1093     return fNSRole;
1094 }
1095 
1096 - (BOOL)accessibilityIsRoleAttributeSettable
1097 {
1098     return NO;
1099 }
1100 
1101 // Localized, user-readable description of role, such as radio button (NSString)
1102 - (NSString *)accessibilityRoleDescriptionAttribute
1103 {
1104     // first ask AppKit for its accessible role description for a given AXRole
1105     NSString *value = NSAccessibilityRoleDescription([self accessibilityRoleAttribute], nil);
1106 
1107     if (value == nil) {
1108         // query java if necessary


1109         JNIEnv* env = [ThreadUtilities getJNIEnv];
1110         GET_CACCESSIBILITY_CLASS_RETURN(nil);
1111         DECLARE_STATIC_METHOD_RETURN(jm_getAccessibleRoleDisplayString, sjc_CAccessibility, "getAccessibleRoleDisplayString",
1112                                      "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil);
1113 
1114 
1115         jobject axRole = (*env)->CallStaticObjectMethod(env, jm_getAccessibleRoleDisplayString, fAccessible, fComponent);
1116         CHECK_EXCEPTION();
1117         if (axRole != NULL) {
1118             value = JavaStringToNSString(env, axRole);
1119             (*env)->DeleteLocalRef(env, axRole);
1120         } else {
1121             value = @"unknown";
1122         }
1123     }
1124 
1125     return value;
1126 }
1127 
1128 - (BOOL)accessibilityIsRoleDescriptionAttributeSettable
1129 {
1130     return NO;
1131 }
1132 
1133 // Currently selected children (NSArray)
1134 - (NSArray *)accessibilitySelectedChildrenAttribute
1135 {
1136     JNIEnv* env = [ThreadUtilities getJNIEnv];
1137     NSArray *selectedChildren = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_SELECTED_CHILDREN allowIgnored:NO];
1138     if ([selectedChildren count] > 0) {


1146 {
1147     return NO; // cmcnote: actually it should be. so need to write accessibilitySetSelectedChildrenAttribute also
1148 }
1149 
1150 - (NSNumber *)accessibilitySelectedAttribute
1151 {
1152     return [NSNumber numberWithBool:[self isSelected:[ThreadUtilities getJNIEnv]]];
1153 }
1154 
1155 - (BOOL)accessibilityIsSelectedAttributeSettable
1156 {
1157     if ([self isSelectable:[ThreadUtilities getJNIEnv]]) {
1158         return YES;
1159     } else {
1160         return NO;
1161     }
1162 }
1163 
1164 - (void)accessibilitySetSelectedAttribute:(id)value
1165 {
1166    JNIEnv* env = [ThreadUtilities getJNIEnv];
1167     GET_CACCESSIBILITY_CLASS();
1168     DECLARE_STATIC_METHOD(jm_requestSelection,
1169                           sjc_CAccessibility,
1170                           "requestSelection",
1171                           "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)V");
1172 
1173     if ([(NSNumber*)value boolValue]) {
1174         (*env)->CallStaticVoidMethod(env, sjc_CAccessibility, jm_requestSelection, fAccessible, fComponent);
1175         CHECK_EXCEPTION();
1176     }
1177 }
1178 
1179 // Element size (NSValue)
1180 - (NSValue *)accessibilitySizeAttribute {
1181     JNIEnv* env = [ThreadUtilities getJNIEnv];
1182     GET_ACCESSIBLECOMPONENT_STATIC_METHOD_RETURN(nil);
1183     jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
1184                            sjm_getAccessibleComponent, fAccessible, fComponent);
1185     CHECK_EXCEPTION();
1186     NSValue* size = [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
1187     (*env)->DeleteLocalRef(env, axComponent);
1188     return size;
1189 }
1190 
1191 - (BOOL)accessibilityIsSizeAttributeSettable
1192 {
1193     // SIZE is settable in windows if [self styleMask] & NSResizableWindowMask - but windows are heavyweight so we're ok here
1194     // SIZE is settable in columns if [[self tableValue] allowsColumnResizing - haven't dealt with columns yet
1195     return NO;
1196 }
1197 
1198 // Element subrole type, such as NSAccessibilityTableRowSubrole (NSString). See the subrole attribute table at
1199 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
1200 - (NSString *)accessibilitySubroleAttribute
1201 {
1202     NSString *value = nil;
1203     if ([[self javaRole] isEqualToString:@"passwordtext"]) {
1204         value = NSAccessibilitySecureTextFieldSubrole;
1205     }


1225      NSAccessibilitySearchFieldSubrole    //no
1226      */
1227     return value;
1228 }
1229 
1230 - (BOOL)accessibilityIsSubroleAttributeSettable
1231 {
1232     return NO;
1233 }
1234 
1235 // Title of element, such as button text (NSString)
1236 - (NSString *)accessibilityTitleAttribute
1237 {
1238     // Return empty string for labels, since their value and tile end up being the same thing and this leads to repeated text.
1239     if ([[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityStaticTextRole]) {
1240         return @"";
1241     }
1242 
1243     JNIEnv* env = [ThreadUtilities getJNIEnv];
1244 
1245     GET_ACCESSIBLENAME_METHOD_RETURN(nil);
1246     jobject val = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleName, fAccessible, fComponent);
1247     CHECK_EXCEPTION();
1248     if (val == NULL) {
1249         return nil;
1250     }
1251     NSString* str = JavaStringToNSString(env, val);
1252     (*env)->DeleteLocalRef(env, val);
1253     return str;
1254 }
1255 
1256 - (BOOL)accessibilityIsTitleAttributeSettable
1257 {
1258     return NO;
1259 }
1260 
1261 - (NSWindow *)accessibilityTopLevelUIElementAttribute
1262 {
1263     return [self window];
1264 }
1265 
1266 - (BOOL)accessibilityIsTopLevelUIElementAttributeSettable
1267 {
1268     return NO;
1269 }
1270 
1271 // Element's value (id)
1272 // note that the appKit meaning of "accessibilityValue" is different from the java
1273 // meaning of "accessibleValue", which is specific to numerical values
1274 // (https://docs.oracle.com/javase/8/docs/api/javax/accessibility/AccessibleValue.html#setCurrentAccessibleValue-java.lang.Number-)
1275 - (id)accessibilityValueAttribute
1276 {


1277     JNIEnv* env = [ThreadUtilities getJNIEnv];
1278 
1279     // Need to handle popupmenus differently.
1280     //
1281     // At least for now don't handle combo box menus.
1282     // This may change when later fixing issues which currently
1283     // exist for combo boxes, but for now the following is only
1284     // for JPopupMenus, not for combobox menus.
1285     id parent = [self parent];
1286     if ( [[self javaRole] isEqualToString:@"popupmenu"] &&
1287          ![[parent javaRole] isEqualToString:@"combobox"] ) {
1288         NSArray *children =
1289             [JavaComponentAccessibility childrenOfParent:self
1290                                         withEnv:env
1291                                         withChildrenCode:JAVA_AX_ALL_CHILDREN
1292                                         allowIgnored:YES];
1293         if ([children count] > 0) {
1294             // handle case of AXMenuItem
1295             // need to ask menu what is selected
1296             NSArray *selectedChildrenOfMenu =
1297                 [self accessibilitySelectedChildrenAttribute];
1298             JavaComponentAccessibility *selectedMenuItem =
1299                 [selectedChildrenOfMenu objectAtIndex:0];
1300             if (selectedMenuItem != nil) {
1301                 GET_CACCESSIBILITY_CLASS_RETURN(nil);
1302                 GET_ACCESSIBLENAME_METHOD_RETURN(nil);
1303                 jobject itemValue =
1304                         (*env)->CallStaticObjectMethod( env,
1305                                                    sjm_getAccessibleName,
1306                                                    selectedMenuItem->fAccessible,
1307                                                    selectedMenuItem->fComponent );
1308                 CHECK_EXCEPTION();
1309                 if (itemValue == NULL) {
1310                     return nil;
1311                 }
1312                 NSString* itemString = JavaStringToNSString(env, itemValue);
1313                 (*env)->DeleteLocalRef(env, itemValue);
1314                 return itemString;
1315             } else {
1316                 return nil;
1317             }
1318         }
1319     }
1320 
1321     // ask Java for the component's accessibleValue. In java, the "accessibleValue" just means a numerical value
1322     // a text value is taken care of in JavaTextAccessibility
1323 
1324     // cmcnote should coalesce these calls into one java call
1325     NSNumber *num = nil;
1326     GET_CACCESSIBILITY_CLASS_RETURN(nil);
1327     DECLARE_STATIC_METHOD_RETURN(sjm_getAccessibleValue, sjc_CAccessibility, "getAccessibleValue",
1328                 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleValue;", nil);
1329     jobject axValue = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleValue, fAccessible, fComponent);
1330     CHECK_EXCEPTION();
1331     if (axValue != NULL) {
1332         DECLARE_STATIC_METHOD_RETURN(jm_getCurrentAccessibleValue, sjc_CAccessibility, "getCurrentAccessibleValue",
1333                                      "(Ljavax/accessibility/AccessibleValue;Ljava/awt/Component;)Ljava/lang/Number;", nil);
1334         jobject str = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getCurrentAccessibleValue, axValue, fComponent);
1335         CHECK_EXCEPTION();
1336         if (str != NULL) {
1337             num = JavaNumberToNSNumber(env, str);
1338             (*env)->DeleteLocalRef(env, str);
1339         }
1340         (*env)->DeleteLocalRef(env, axValue);
1341     }
1342     if (num == nil) {
1343         num = [NSNumber numberWithInt:0];
1344     }
1345     return num;
1346 }
1347 
1348 - (BOOL)accessibilityIsValueAttributeSettable
1349 {
1350     // according ot AppKit sources, in general the value attribute is not settable, except in the cases
1351     // of an NSScroller, an NSSplitView, and text that's both enabled & editable
1352     BOOL isSettable = NO;
1353     NSString *role = [self accessibilityRoleAttribute];
1354 
1355     if ([role isEqualToString:NSAccessibilityScrollBarRole] || // according to NSScrollerAccessibility
1356         [role isEqualToString:NSAccessibilitySplitGroupRole] ) // according to NSSplitViewAccessibility
1357     {


1413 {
1414     AWT_ASSERT_APPKIT_THREAD;
1415 
1416     JNIEnv *env = [ThreadUtilities getJNIEnv];
1417     [(id <JavaAccessibilityAction>)[[self getActions:env] objectForKey:action] perform];
1418 }
1419 
1420 
1421 // -- misc accessibility --
1422 - (BOOL)accessibilityIsIgnored
1423 {
1424 #ifdef JAVA_AX_NO_IGNORES
1425     return NO;
1426 #else
1427     return [[self accessibilityRoleAttribute] isEqualToString:JavaAccessibilityIgnore];
1428 #endif /* JAVA_AX_NO_IGNORES */
1429 }
1430 
1431 - (id)accessibilityHitTest:(NSPoint)point withEnv:(JNIEnv *)env
1432 {
1433     DECLARE_CLASS_RETURN(jc_Container, "java/awt/Container", nil);
1434     DECLARE_STATIC_METHOD_RETURN(jm_accessibilityHitTest, sjc_CAccessibility, "accessibilityHitTest",
1435                                  "(Ljava/awt/Container;FF)Ljavax/accessibility/Accessible;", nil);
1436 
1437     // Make it into java screen coords
1438     point.y = [[[[self view] window] screen] frame].size.height - point.y;
1439 
1440     jobject jparent = fComponent;
1441 
1442     id value = nil;
1443     if ((*env)->IsInstanceOf(env, jparent, jc_Container)) {
1444         jobject jaccessible = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_accessibilityHitTest,
1445                                jparent, (jfloat)point.x, (jfloat)point.y);
1446         CHECK_EXCEPTION();
1447         if (jaccessible != NULL) {
1448             value = [JavaComponentAccessibility createWithAccessible:jaccessible withEnv:env withView:fView];
1449             (*env)->DeleteLocalRef(env, jaccessible);
1450         }
1451     }
1452 
1453     if (value == nil) {
1454         value = self;
1455     }
1456 
1457     if ([value accessibilityIsIgnored]) {
1458         value = NSAccessibilityUnignoredAncestor(value);
1459     }
1460 
1461 #ifdef JAVA_AX_DEBUG
1462     NSLog(@"%s: %@", __FUNCTION__, value);
1463 #endif
1464     return value;
1465 }
1466 
1467 - (id)accessibilityFocusedUIElement
1468 {


1469     JNIEnv *env = [ThreadUtilities getJNIEnv];
1470     GET_CACCESSIBILITY_CLASS_RETURN(nil);
1471     DECLARE_STATIC_METHOD_RETURN(jm_getFocusOwner, sjc_CAccessibility, "getFocusOwner",
1472                                   "(Ljava/awt/Component;)Ljavax/accessibility/Accessible;", nil);
1473     id value = nil;
1474 
1475     NSWindow* hostWindow = [[self->fView window] retain];
1476     jobject focused = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getFocusOwner, fComponent);
1477     [hostWindow release];
1478     CHECK_EXCEPTION();
1479 
1480     if (focused != NULL) {
1481         DECLARE_CLASS_RETURN(sjc_Accessible, "javax/accessibility/Accessible", nil);
1482         if ((*env)->IsInstanceOf(env, focused, sjc_Accessible)) {
1483             value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
1484         }
1485         CHECK_EXCEPTION();
1486         (*env)->DeleteLocalRef(env, focused);
1487     }
1488 
1489     if (value == nil) {
1490         value = self;
1491     }
1492 #ifdef JAVA_AX_DEBUG
1493     NSLog(@"%s: %@", __FUNCTION__, value);
1494 #endif
1495     return value;
1496 }
1497 
1498 @end
1499 
1500 /*
1501  * Class:     sun_lwawt_macosx_CAccessibility
1502  * Method:    focusChanged
1503  * Signature: ()V
1504  */
1505 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
1506 (JNIEnv *env, jobject jthis)
1507 {
1508 JNI_COCOA_ENTER(env);
1509     [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO];
1510 JNI_COCOA_EXIT(env);
1511 }
1512 
1513 /*
1514  * Class:     sun_lwawt_macosx_CAccessible
1515  * Method:    valueChanged
1516  * Signature: (I)V
1517  */
1518 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged
1519 (JNIEnv *env, jclass jklass, jlong element)
1520 {
1521 JNI_COCOA_ENTER(env);
1522     [ThreadUtilities performOnMainThread:@selector(postValueChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1523 JNI_COCOA_EXIT(env);
1524 }
1525 
1526 /*
1527  * Class:     sun_lwawt_macosx_CAccessible
1528  * Method:    selectedTextChanged
1529  * Signature: (I)V
1530  */
1531 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectedTextChanged
1532 (JNIEnv *env, jclass jklass, jlong element)
1533 {
1534 JNI_COCOA_ENTER(env);
1535     [ThreadUtilities performOnMainThread:@selector(postSelectedTextChanged)
1536                      on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1537                      withObject:nil
1538                      waitUntilDone:NO];
1539 JNI_COCOA_EXIT(env);
1540 }
1541 
1542 /*
1543  * Class:     sun_lwawt_macosx_CAccessible
1544  * Method:    selectionChanged
1545  * Signature: (I)V
1546  */
1547 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged
1548 (JNIEnv *env, jclass jklass, jlong element)
1549 {
1550 JNI_COCOA_ENTER(env);
1551     [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1552 JNI_COCOA_EXIT(env);
1553 }
1554 
1555 /*
1556  * Class:     sun_lwawt_macosx_CAccessible
1557  * Method:    menuOpened
1558  * Signature: (I)V
1559  */
1560 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened
1561 (JNIEnv *env, jclass jklass, jlong element)
1562 {
1563 JNI_COCOA_ENTER(env);
1564     [ThreadUtilities performOnMainThread:@selector(postMenuOpened)
1565                      on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1566                      withObject:nil
1567                      waitUntilDone:NO];
1568 JNI_COCOA_EXIT(env);
1569 }
1570 
1571 /*
1572  * Class:     sun_lwawt_macosx_CAccessible
1573  * Method:    menuClosed
1574  * Signature: (I)V
1575  */
1576 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed
1577 (JNIEnv *env, jclass jklass, jlong element)
1578 {
1579 JNI_COCOA_ENTER(env);
1580     [ThreadUtilities performOnMainThread:@selector(postMenuClosed)
1581                      on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1582                      withObject:nil
1583                      waitUntilDone:NO];
1584 JNI_COCOA_EXIT(env);
1585 }
1586 
1587 /*
1588  * Class:     sun_lwawt_macosx_CAccessible
1589  * Method:    menuItemSelected
1590  * Signature: (I)V
1591  */
1592 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected
1593 (JNIEnv *env, jclass jklass, jlong element)
1594 {
1595 JNI_COCOA_ENTER(env);
1596     [ThreadUtilities performOnMainThread:@selector(postMenuItemSelected)
1597                      on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1598                      withObject:nil
1599                      waitUntilDone:NO];
1600 JNI_COCOA_EXIT(env);
1601 }
1602 
1603 /*
1604  * Class:     sun_lwawt_macosx_CAccessible
1605  * Method:    unregisterFromCocoaAXSystem
1606  * Signature: (I)V
1607  */
1608 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSystem
1609 (JNIEnv *env, jclass jklass, jlong element)
1610 {
1611 JNI_COCOA_ENTER(env);
1612     [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1613 JNI_COCOA_EXIT(env);
1614 }
1615 
1616 @implementation TabGroupAccessibility
1617 
1618 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
1619 {
1620     self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
1621     if (self) {
1622         _numTabs = -1; //flag for uninitialized numTabs
1623     }
1624     return self;
1625 }
1626 
1627 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
1628 {
1629     NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
1630 
1631     [names addObject:NSAccessibilityTabsAttribute];
1632     [names addObject:NSAccessibilityContentsAttribute];
1633     [names addObject:NSAccessibilityValueAttribute];


1643     jobject selAccessible = getAxContextSelection(env, axContext, 0, fComponent);
1644     if (selAccessible == NULL) return nil;
1645 
1646     // Go through the tabs and find selAccessible
1647     _numTabs = [tabs count];
1648     JavaComponentAccessibility *aTab;
1649     NSInteger i;
1650     for (i = 0; i < _numTabs; i++) {
1651         aTab = (JavaComponentAccessibility *)[tabs objectAtIndex:i];
1652         if ([aTab isAccessibleWithEnv:env forAccessible:selAccessible]) {
1653             (*env)->DeleteLocalRef(env, selAccessible);
1654             return aTab;
1655         }
1656     }
1657     (*env)->DeleteLocalRef(env, selAccessible);
1658     return nil;
1659 }
1660 
1661 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
1662 {
1663     GET_CHILDRENANDROLES_METHOD_RETURN(nil);
1664     jobjectArray jtabsAndRoles = (jobjectArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getChildrenAndRoles,
1665                                   fAccessible, fComponent, whichTabs, allowIgnored);
1666     CHECK_EXCEPTION();
1667     if(jtabsAndRoles == NULL) return nil;
1668 
1669     jsize arrayLen = (*env)->GetArrayLength(env, jtabsAndRoles);
1670     if (arrayLen == 0) {
1671         (*env)->DeleteLocalRef(env, jtabsAndRoles);
1672         return nil;
1673     }
1674     NSMutableArray *tabs = [NSMutableArray arrayWithCapacity:(arrayLen/2)];
1675 
1676     // all of the tabs have the same role, so we can just find out what that is here and use it for all the tabs
1677     jobject jtabJavaRole = (*env)->GetObjectArrayElement(env, jtabsAndRoles, 1); // the array entries alternate between tab/role, starting with tab. so the first role is entry 1.
1678     if (jtabJavaRole == NULL) {
1679         (*env)->DeleteLocalRef(env, jtabsAndRoles);
1680         return nil;
1681     }
1682     DECLARE_CLASS_RETURN(sjc_AccessibleRole, "javax/accessibility/AccessibleRole", nil);
1683     DECLARE_FIELD_RETURN(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;", nil);
1684     jobject jkey = (*env)->GetObjectField(env, jtabJavaRole, sjf_key);
1685     CHECK_EXCEPTION();
1686     NSString *tabJavaRole = JavaStringToNSString(env, jkey);
1687     (*env)->DeleteLocalRef(env, jkey);
1688 
1689     NSInteger i;
1690     NSUInteger tabIndex = (whichTabs >= 0) ? whichTabs : 0; // if we're getting one particular child, make sure to set its index correctly
1691     for(i = 0; i < arrayLen; i+=2) {
1692         jobject jtab = (*env)->GetObjectArrayElement(env, jtabsAndRoles, i);
1693         JavaComponentAccessibility *tab = [[[TabGroupControlAccessibility alloc] initWithParent:self withEnv:env withAccessible:jtab withIndex:tabIndex withTabGroup:axContext withView:[self view] withJavaRole:tabJavaRole] autorelease];
1694         (*env)->DeleteLocalRef(env, jtab);
1695         [tabs addObject:tab];
1696         tabIndex++;
1697     }
1698     (*env)->DeleteLocalRef(env, jtabsAndRoles);
1699     return tabs;
1700 }
1701 
1702 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
1703 {
1704     // Contents are the children of the selected tab.
1705     id currentTab = [self currentTabWithEnv:env withAxContext:axContext];
1706     if (currentTab == nil) return nil;


1808         }
1809         (*env)->DeleteLocalRef(env, axContext);
1810     } else {
1811         result = [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
1812     }
1813     return result;
1814 }
1815 
1816 @end
1817 
1818 
1819 static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
1820 
1821 @implementation TabGroupControlAccessibility
1822 
1823 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
1824 {
1825     self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
1826     if (self) {
1827         if (tabGroup != NULL) {
1828             fTabGroupAxContext = (*env)->NewWeakGlobalRef(env, tabGroup);
1829             CHECK_EXCEPTION();
1830         } else {
1831             fTabGroupAxContext = NULL;
1832         }
1833     }
1834     return self;
1835 }
1836 
1837 - (void)dealloc
1838 {
1839     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
1840 
1841     if (fTabGroupAxContext != NULL) {
1842         (*env)->DeleteWeakGlobalRef(env, fTabGroupAxContext);
1843         fTabGroupAxContext = NULL;
1844     }
1845 
1846     [super dealloc];
1847 }
1848 
1849 - (id)accessibilityValueAttribute
1850 {
1851     JNIEnv *env = [ThreadUtilities getJNIEnv];
1852     jobject axContext = [self axContextWithEnv:env];
1853     jobject selAccessible = getAxContextSelection(env, [self tabGroup], fIndex, fComponent);
1854 
1855     // Returns the current selection of the page tab list
1856     id val = [NSNumber numberWithBool:ObjectEquals(env, axContext, selAccessible, fComponent)];
1857 
1858     (*env)->DeleteLocalRef(env, selAccessible);
1859     (*env)->DeleteLocalRef(env, axContext);
1860     return val;
1861 }
1862 
1863 - (void)getActionsWithEnv:(JNIEnv *)env
1864 {
1865     TabGroupAction *action = [[TabGroupAction alloc] initWithEnv:env withTabGroup:[self tabGroup] withIndex:fIndex withComponent:fComponent];
1866     [fActions setObject:action forKey:NSAccessibilityPressAction];
1867     [action release];
1868 }
1869 
1870 - (jobject)tabGroup
1871 {
1872     if (fTabGroupAxContext == NULL) {
1873         JNIEnv* env = [ThreadUtilities getJNIEnv];
1874         jobject tabGroupAxContext = [(JavaComponentAccessibility *)[self parent] axContextWithEnv:env];
1875         fTabGroupAxContext = (*env)->NewWeakGlobalRef(env, tabGroupAxContext);
1876         CHECK_EXCEPTION();
1877         (*env)->DeleteLocalRef(env, tabGroupAxContext);
1878     }
1879     return fTabGroupAxContext;
1880 }
1881 
1882 @end
1883 
1884 
1885 @implementation ScrollAreaAccessibility
1886 
1887 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
1888 {
1889     NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
1890 
1891     [names addObject:NSAccessibilityHorizontalScrollBarAttribute];
1892     [names addObject:NSAccessibilityVerticalScrollBarAttribute];
1893     [names addObject:NSAccessibilityContentsAttribute];
1894 
1895     return names;
1896 }


1969             // no scroll bars in contents
1970             [(NSMutableArray *)contents addObject:aElement];
1971         }
1972     }
1973 
1974     return contents;
1975 }
1976 
1977 - (BOOL)accessibilityIsContentsAttributeSettable
1978 {
1979     return NO;
1980 }
1981 
1982 @end
1983 
1984 /*
1985  * Returns Object.equals for the two items
1986  * This may use LWCToolkit.invokeAndWait(); don't call while holding fLock
1987  * and try to pass a component so the event happens on the correct thread.
1988  */

1989 static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component)
1990 {
1991     DECLARE_CLASS_RETURN(sjc_Object, "java/lang/Object", NO);
1992     DECLARE_METHOD_RETURN(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z", NO);
1993 
1994     if ((a == NULL) && (b == NULL)) return YES;
1995     if ((a == NULL) || (b == NULL)) return NO;
1996 
1997     if (pthread_main_np() != 0) {
1998         // If we are on the AppKit thread
1999         DECLARE_CLASS_RETURN(sjc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit", NO);
2000         DECLARE_STATIC_METHOD_RETURN(jm_doEquals, sjc_LWCToolkit, "doEquals",
2001                                      "(Ljava/lang/Object;Ljava/lang/Object;Ljava/awt/Component;)Z", NO);
2002         return (*env)->CallStaticBooleanMethod(env, sjc_LWCToolkit, jm_doEquals, a, b, component);
2003         CHECK_EXCEPTION();
2004     }
2005 
2006     jboolean jb = (*env)->CallBooleanMethod(env, a, jm_equals, b);
2007     CHECK_EXCEPTION();
2008     return jb;
2009 }
< prev index next >