Compare commits

...

6 Commits

Author SHA1 Message Date
Artem Semenov
b907eb8eee [a11y] Renderer lists are not spoken: JBR-2457 2020-06-04 18:55:16 +03:00
Anton Tarasov
81df074ef3 [a11y] Rename JavaAxObjectProvider and PlatformAxObject
Renamed:
  JavaAxObjectProvider -> JavaBaseProvider
  PlatformAxObject -> PlatformAxElement
  PlatformAxObjectProvider -> PlatformAxElementProvider

Reasoning:
  JavaBaseProvider provides JavaBaseAccessibility and subclasses
  PlatformAxElement inherits from NSAccessibilityElement
2020-06-04 12:09:07 +03:00
Anton Tarasov
95c706659c [a11y] Add getAccessibilityWindow to PlatformAxObject 2020-06-04 12:09:07 +03:00
Anton Tarasov
cede93ba6f [a11y] Add JavaElementAccessibility for all NSAccessibilityElement subclasses
- JavaElementAccessibility (and respective PlatformAxObject) is the base class for elements conforming to the new a11y protocol
2020-06-04 12:09:07 +03:00
Anton Tarasov
3677f6e8ad [a11y] Split NSElementAccessibilty and NSObject hierarchies
- Mixing the two hierarchies does not work, so split it
- Implement binding b/w associated objects of the two hierarchies via new protocols: JavaAxObjectProvider, PlatformAxObjectProvider
2020-06-04 12:09:07 +03:00
Anton Tarasov
9bebb2eec0 [a11y] Separate base part from JavaComponentAccessibility
- Create JavaBaseAccessibility and JavaListAccessibility for the new a11y
- Adopt NSAccessibilityList protocol (based on investigations by Artem Semenov)
- Use JavaComponentAccessibility for the legacy a11y
2020-06-04 12:09:07 +03:00
10 changed files with 1040 additions and 603 deletions

View File

@@ -0,0 +1,78 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#include "jni.h"
#import <AppKit/AppKit.h>
//#define JAVA_AX_DEBUG 1
//#define JAVA_AX_NO_IGNORES 1
//#define JAVA_AX_DEBUG_PARMS 1
// these constants are duplicated in CAccessibility.java
#define JAVA_AX_ALL_CHILDREN (-1)
#define JAVA_AX_SELECTED_CHILDREN (-2)
#define JAVA_AX_VISIBLE_CHILDREN (-3)
// If the value is >=0, it's an index
@class JavaBaseAccessibility;
@protocol JavaBaseProvider
@property (nonatomic, retain) JavaBaseAccessibility *javaBase;
@end
@protocol PlatformAxElementProvider
@required
- (NSString *)getPlatformAxElementClassName;
@property (nonatomic, retain) NSObject <JavaBaseProvider> *platformAxElement;
@end
@interface JavaBaseAccessibility : NSObject <JavaBaseProvider, PlatformAxElementProvider> {
NSView *fView;
NSObject *fParent;
NSString *fNSRole;
NSString *fJavaRole;
jint fIndex;
jobject fAccessible;
jobject fComponent;
}
- (id)initWithParent:(NSObject*)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole;
- (void)unregisterFromCocoaAXSystem;
- (void)postValueChanged;
- (void)postSelectedTextChanged;
- (void)postSelectionChanged;
- (BOOL)isEqual:(id)anObject;
- (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible;
+ (void)postFocusChanged:(id)message;
+ (NSArray*)childrenOfParent:(JavaBaseAccessibility*)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored;
+ (JavaBaseAccessibility *) createWithParent:(JavaBaseAccessibility *)parent accessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view;
+ (JavaBaseAccessibility *) createWithAccessible:(jobject)jaccessible role:(NSString *)role index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view;
+ (JavaBaseAccessibility *) createWithAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env withView:(NSView *)view;
@property(readonly) jobject accessible;
@property(readonly) jobject component;
@property(readonly) jint index;
- (jobject)axContextWithEnv:(JNIEnv *)env;
- (NSView*)view;
- (NSWindow*)window;
- (id)parent;
- (NSString *)javaRole;
- (BOOL)isMenu;
- (BOOL)isSelected:(JNIEnv *)env;
- (BOOL)isSelectable:(JNIEnv *)env;
- (BOOL)isVisible:(JNIEnv *)env;
- (NSSize)getSize;
- (NSRect)getBounds;
- (id)getFocusedElement;
@end

View File

@@ -0,0 +1,611 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#import "JavaBaseAccessibility.h"
#import "sun_lwawt_macosx_CAccessibility.h"
#import <AppKit/AppKit.h>
#import <JavaNativeFoundation/JavaNativeFoundation.h>
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
#import <dlfcn.h>
#import "JavaBaseAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "JavaTextAccessibility.h"
#import "JavaListAccessibility.h"
#import "JavaRowAccessibility.h"
#import "JavaComponentAccessibility.h"
#import "ThreadUtilities.h"
#import "AWTView.h"
static JNF_STATIC_MEMBER_CACHE(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;");
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleComponent, sjc_CAccessibility, "getAccessibleComponent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleComponent;");
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleValue, sjc_CAccessibility, "getAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleValue;");
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleDescription, sjc_CAccessibility, "getAccessibleDescription", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
static JNF_STATIC_MEMBER_CACHE(sjm_isFocusTraversable, sjc_CAccessibility, "isFocusTraversable", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z");
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleIndexInParent, sjc_CAccessibility, "getAccessibleIndexInParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I");
static JNF_CLASS_CACHE(sjc_CAccessible, "sun/lwawt/macosx/CAccessible");
static JNF_MEMBER_CACHE(jf_ptr, sjc_CAccessible, "ptr", "J");
static JNF_STATIC_MEMBER_CACHE(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;");
static jobject sAccessibilityClass = NULL;
@implementation JavaBaseAccessibility
@synthesize platformAxElement;
@synthesize javaBase;
- (id)init
{
self = [super init];
if (self) {
NSString *className = [self getPlatformAxElementClassName];
self.platformAxElement = className != NULL ? [[NSClassFromString(className) alloc] init] : self; // defaults to [self]
self.platformAxElement.javaBase = self;
}
return self;
}
// to override in subclasses
- (NSString *)getPlatformAxElementClassName
{
return NULL;
}
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
{
self = [self init];
if (self) {
fParent = [parent retain];
fView = [view retain];
fJavaRole = [javaRole retain];
fAccessible = (*env)->NewWeakGlobalRef(env, accessible);
(*env)->ExceptionClear(env); // in case of OOME
jobject jcomponent = [(AWTView *)fView awtComponent:env];
fComponent = (*env)->NewWeakGlobalRef(env, jcomponent);
(*env)->DeleteLocalRef(env, jcomponent);
fIndex = index;
}
return self;
}
- (void)unregisterFromCocoaAXSystem
{
AWT_ASSERT_APPKIT_THREAD;
static dispatch_once_t initialize_unregisterUniqueId_once;
static void (*unregisterUniqueId)(id);
dispatch_once(&initialize_unregisterUniqueId_once, ^{
void *jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL);
unregisterUniqueId = dlsym(jrsFwk, "JRSAccessibilityUnregisterUniqueIdForUIElement");
});
if (unregisterUniqueId) unregisterUniqueId(self);
}
- (void)dealloc
{
[self unregisterFromCocoaAXSystem];
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
(*env)->DeleteWeakGlobalRef(env, fAccessible);
fAccessible = NULL;
(*env)->DeleteWeakGlobalRef(env, fComponent);
fComponent = NULL;
[fParent release];
fParent = nil;
[fNSRole release];
fNSRole = nil;
[fJavaRole release];
fJavaRole = nil;
[fView release];
fView = nil;
if (self.platformAxElement != self) {
[self.platformAxElement dealloc];
}
[super dealloc];
}
- (void)postValueChanged
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self.platformAxElement, NSAccessibilityValueChangedNotification);
}
- (void)postSelectedTextChanged
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self.platformAxElement, NSAccessibilitySelectedTextChangedNotification);
}
- (void)postSelectionChanged
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self.platformAxElement, NSAccessibilitySelectedChildrenChangedNotification);
}
- (void)postMenuOpened
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self.platformAxElement, (NSString *)kAXMenuOpenedNotification);
}
- (void)postMenuClosed
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self.platformAxElement, (NSString *)kAXMenuClosedNotification);
}
- (void)postMenuItemSelected
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self.platformAxElement, (NSString *)kAXMenuItemSelectedNotification);
}
- (BOOL)isEqual:(id)anObject
{
if (![anObject isKindOfClass:[self class]]) return NO;
JavaBaseAccessibility *accessibility = (JavaBaseAccessibility *)anObject;
JNIEnv* env = [ThreadUtilities getJNIEnv];
return (*env)->IsSameObject(env, accessibility->fAccessible, fAccessible);
}
- (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible
{
return (*env)->IsSameObject(env, fAccessible, accessible);
}
+ (void)initialize
{
if (sRoles == nil) {
initializeRoles();
}
if (sAccessibilityClass == NULL) {
JNF_STATIC_MEMBER_CACHE(jm_getAccessibility, sjc_CAccessibility, "getAccessibility", "([Ljava/lang/String;)Lsun/lwawt/macosx/CAccessibility;");
#ifdef JAVA_AX_NO_IGNORES
NSArray *ignoredKeys = [NSArray array];
#else
NSArray *ignoredKeys = [sRoles allKeysForObject:JavaAccessibilityIgnore];
#endif
jobjectArray result = NULL;
jsize count = [ignoredKeys count];
JNIEnv *env = [ThreadUtilities getJNIEnv];
static JNF_CLASS_CACHE(jc_String, "java/lang/String");
result = JNFNewObjectArray(env, &jc_String, count);
if (!result) {
NSLog(@"In %s, can't create Java array of String objects", __FUNCTION__);
return;
}
NSInteger i;
for (i = 0; i < count; i++) {
jstring jString = JNFNSToJavaString(env, [ignoredKeys objectAtIndex:i]);
(*env)->SetObjectArrayElement(env, result, i, jString);
(*env)->DeleteLocalRef(env, jString);
}
sAccessibilityClass = JNFCallStaticObjectMethod(env, jm_getAccessibility, result); // AWT_THREADING Safe (known object)
}
}
+ (void)postFocusChanged:(id)message
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification([NSApp accessibilityFocusedUIElement], NSAccessibilityFocusedUIElementChangedNotification);
}
+ (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {
return jaccessible;
} else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);
}
return NULL;
}
+ (NSArray *)childrenOfParent:(JavaBaseAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
{
if (parent->fAccessible == NULL) return nil;
jobjectArray jchildrenAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
if (jchildrenAndRoles == NULL) return nil;
jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
NSMutableArray *children = [NSMutableArray arrayWithCapacity:arrayLen/2]; //childrenAndRoles array contains two elements (child, role) for each child
NSInteger i;
NSUInteger childIndex = (whichChildren >= 0) ? whichChildren : 0; // if we're getting one particular child, make sure to set its index correctly
for(i = 0; i < arrayLen; i+=2)
{
jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
NSString *childJavaRole = nil;
if (jchildJavaRole != NULL) {
jobject jkey = JNFGetObjectField(env, jchildJavaRole, sjf_key);
childJavaRole = JNFJavaToNSString(env, jkey);
(*env)->DeleteLocalRef(env, jkey);
}
JavaBaseAccessibility *child = [self createWithParent:parent accessible:jchild role:childJavaRole index:childIndex withEnv:env withView:parent->fView];
(*env)->DeleteLocalRef(env, jchild);
(*env)->DeleteLocalRef(env, jchildJavaRole);
[children addObject:child.platformAxElement];
childIndex++;
}
(*env)->DeleteLocalRef(env, jchildrenAndRoles);
return children;
}
+ (JavaBaseAccessibility *)createWithAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env withView:(NSView *)view
{
JavaBaseAccessibility *ret = nil;
jobject jcomponent = [(AWTView *)view awtComponent:env];
jint index = JNFCallStaticIntMethod(env, sjm_getAccessibleIndexInParent, jaccessible, jcomponent);
if (index >= 0) {
NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
ret = [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
}
(*env)->DeleteLocalRef(env, jcomponent);
return ret;
}
+ (JavaBaseAccessibility *) createWithAccessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
{
return [self createWithParent:nil accessible:jaccessible role:javaRole index:index withEnv:env withView:view];
}
+ (JavaBaseAccessibility *) createWithParent:(JavaBaseAccessibility *)parent accessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
{
// try to fetch the jCAX from Java, and return autoreleased
jobject jCAX = [JavaBaseAccessibility getCAccessible:jaccessible withEnv:env];
if (jCAX == NULL) return nil;
JavaBaseAccessibility *value = (JavaBaseAccessibility *) jlong_to_ptr(JNFGetLongField(env, jCAX, jf_ptr));
if (value != nil) {
(*env)->DeleteLocalRef(env, jCAX);
return [[value retain] autorelease];
}
// otherwise, create a new instance
JavaBaseAccessibility *newChild = nil;
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupAccessibility alloc];
} else if ([javaRole isEqualToString:@"scrollpane"]) {
newChild = [ScrollAreaAccessibility alloc];
} else if ([[sRoles objectForKey:[parent javaRole]] isEqualToString:NSAccessibilityListRole]) {
newChild = [JavaRowAccessibility alloc];
} else {
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
} else if ([nsRole isEqualToString:NSAccessibilityListRole]) {
newChild = [JavaListAccessibility alloc];
} else {
newChild = [JavaComponentAccessibility alloc];
}
}
// must init freshly -alloc'd object
[newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
// If creating a JPopupMenu (not a combobox popup list) need to fire menuOpened.
// This is the only way to know if the menu is opening; visible state change
// can't be caught because the listeners are not set up in time.
if ( [javaRole isEqualToString:@"popupmenu"] &&
![[parent javaRole] isEqualToString:@"combobox"] ) {
[newChild postMenuOpened];
}
// must hard retain pointer poked into Java object
[newChild retain];
JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
(*env)->DeleteLocalRef(env, jCAX);
// return autoreleased instance
return [newChild autorelease];
}
- (jobject)axContextWithEnv:(JNIEnv *)env
{
return getAxContext(env, fAccessible, fComponent);
}
- (id)parent
{
static JNF_CLASS_CACHE(sjc_Window, "java/awt/Window");
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleParent, sjc_CAccessibility, "getAccessibleParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
static JNF_STATIC_MEMBER_CACHE(sjm_getSwingAccessible, sjc_CAccessible, "getSwingAccessible", "(Ljavax/accessibility/Accessible;)Ljavax/accessibility/Accessible;");
if(fParent == nil) {
JNIEnv* env = [ThreadUtilities getJNIEnv];
jobject jparent = JNFCallStaticObjectMethod(env, sjm_getAccessibleParent, fAccessible, fComponent);
if (jparent == NULL) {
fParent = fView;
} else {
AWTView *view = fView;
jobject jax = JNFCallStaticObjectMethod(env, sjm_getSwingAccessible, fAccessible);
if (JNFIsInstanceOf(env, jax, &sjc_Window)) {
// In this case jparent is an owner toplevel and we should retrieve its own view
view = [AWTView awtView:env ofAccessible:jparent];
}
if (view != nil) {
fParent = [JavaBaseAccessibility createWithAccessible:jparent withEnv:env withView:view];
}
if (fParent == nil) {
fParent = fView;
}
(*env)->DeleteLocalRef(env, jparent);
(*env)->DeleteLocalRef(env, jax );
}
[fParent retain];
}
return fParent;
}
- (NSView *)view
{
return fView;
}
- (NSWindow *)window
{
return [[self view] window];
}
- (NSString *)javaRole
{
if(fJavaRole == nil) {
JNIEnv* env = [ThreadUtilities getJNIEnv];
fJavaRole = getJavaRole(env, fAccessible, fComponent);
[fJavaRole retain];
}
return fJavaRole;
}
- (BOOL)isMenu
{
id role = [self accessibilityRoleAttribute];
return [role isEqualToString:NSAccessibilityMenuBarRole] || [role isEqualToString:NSAccessibilityMenuRole] || [role isEqualToString:NSAccessibilityMenuItemRole];
}
- (BOOL)isSelected:(JNIEnv *)env
{
if (fIndex == -1) {
return NO;
}
return isChildSelected(env, ((JavaBaseAccessibility *)[self parent])->fAccessible, fIndex, fComponent);
}
- (BOOL)isSelectable:(JNIEnv *)env
{
jobject axContext = [self axContextWithEnv:env];
BOOL selectable = isSelectable(env, axContext, fComponent);
(*env)->DeleteLocalRef(env, axContext);
return selectable;
}
- (BOOL)isVisible:(JNIEnv *)env
{
if (fIndex == -1) {
return NO;
}
jobject axContext = [self axContextWithEnv:env];
BOOL showing = isShowing(env, axContext, fComponent);
(*env)->DeleteLocalRef(env, axContext);
return showing;
}
- (NSSize)getSize
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
NSSize size = getAxComponentSize(env, axComponent, fComponent);
(*env)->DeleteLocalRef(env, axComponent);
return size;
}
- (NSRect)getBounds
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
// NSAccessibility wants the bottom left point of the object in
// bottom left based screen coords
// Get the java screen coords, and make a NSPoint of the bottom left of the AxComponent.
NSSize size = getAxComponentSize(env, axComponent, fComponent);
NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
(*env)->DeleteLocalRef(env, axComponent);
point.y += size.height;
// Now make it into Cocoa screen coords.
point.y = [[[[self view] window] screen] frame].size.height - point.y;
return NSMakeRect(point.x, point.y, size.width, size.height);
}
- (id)getFocusedElement
{
static JNF_STATIC_MEMBER_CACHE(jm_getFocusOwner, sjc_CAccessibility, "getFocusOwner", "(Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
JNIEnv *env = [ThreadUtilities getJNIEnv];
id value = nil;
NSWindow* hostWindow = [[self->fView window] retain];
jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop)
[hostWindow release];
if (focused != NULL) {
if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) {
value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
value = ((JavaBaseAccessibility *)value).platformAxElement;
}
(*env)->DeleteLocalRef(env, focused);
}
if (value == nil) {
value = self;
}
#ifdef JAVA_AX_DEBUG
NSLog(@"%s: %@", __FUNCTION__, value);
#endif
return value;
}
- (jobject)accessible {
return fAccessible;
}
- (jobject)component {
return fComponent;
}
-(jint)index {
return fIndex;
}
@end
/*
* Class: sun_lwawt_macosx_CAccessibility
* Method: focusChanged
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
(JNIEnv *env, jobject jthis)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaBaseAccessibility class] withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: valueChanged
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postValueChanged) on:(JavaBaseAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: selectedTextChanged
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectedTextChanged
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postSelectedTextChanged)
on:(JavaBaseAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: selectionChanged
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaBaseAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuOpened
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuOpened)
on:(JavaBaseAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuClosed
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuClosed)
on:(JavaBaseAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuItemSelected
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuItemSelected)
on:(JavaBaseAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: unregisterFromCocoaAXSystem
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSystem
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaBaseAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}

View File

@@ -26,55 +26,16 @@
#include "jni.h"
#import <AppKit/AppKit.h>
#import "JavaBaseAccessibility.h"
//#define JAVA_AX_DEBUG 1
//#define JAVA_AX_NO_IGNORES 1
//#define JAVA_AX_DEBUG_PARMS 1
@interface JavaComponentAccessibility : NSObject {
NSView *fView;
NSObject *fParent;
NSString *fNSRole;
NSString *fJavaRole;
jint fIndex;
jobject fAccessible;
jobject fComponent;
@interface JavaComponentAccessibility : JavaBaseAccessibility {
NSMutableDictionary *fActions;
NSObject *fActionsLOCK;
}
- (id)initWithParent:(NSObject*)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole;
- (void)unregisterFromCocoaAXSystem;
- (void)postValueChanged;
- (void)postSelectedTextChanged;
- (void)postSelectionChanged;
- (BOOL)isEqual:(id)anObject;
- (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible;
+ (void)postFocusChanged:(id)message;
+ (NSArray*)childrenOfParent:(JavaComponentAccessibility*)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored;
+ (JavaComponentAccessibility *) createWithParent:(JavaComponentAccessibility *)parent accessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view;
+ (JavaComponentAccessibility *) createWithAccessible:(jobject)jaccessible role:(NSString *)role index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view;
+ (JavaComponentAccessibility *) createWithAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env withView:(NSView *)view;
- (NSDictionary*)getActions:(JNIEnv *)env;
- (void)getActionsWithEnv:(JNIEnv *)env;
- (jobject)axContextWithEnv:(JNIEnv *)env;
- (NSView*)view;
- (NSWindow*)window;
- (id)parent;
- (NSString *)javaRole;
- (BOOL)isMenu;
- (BOOL)isSelected:(JNIEnv *)env;
- (BOOL)isSelectable:(JNIEnv *)env;
- (BOOL)isVisible:(JNIEnv *)env;
// attribute names
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
- (NSArray *)accessibilityAttributeNames;
@@ -143,3 +104,44 @@
- (id)accessibilityFocusedUIElement;
@end
@interface TabGroupAccessibility : JavaComponentAccessibility {
NSInteger _numTabs;
}
- (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
- (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
- (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
- (NSArray *)accessibilityChildrenAttribute;
- (id) accessibilityTabsAttribute;
- (BOOL)accessibilityIsTabsAttributeSettable;
- (NSArray *)accessibilityContentsAttribute;
- (BOOL)accessibilityIsContentsAttributeSettable;
- (id) accessibilityValueAttribute;
@end
@interface TabGroupControlAccessibility : JavaComponentAccessibility {
jobject fTabGroupAxContext;
}
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole;
- (jobject)tabGroup;
- (void)getActionsWithEnv:(JNIEnv *)env;
- (id)accessibilityValueAttribute;
@end
@interface ScrollAreaAccessibility : JavaComponentAccessibility {
}
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
- (NSArray *)accessibilityContentsAttribute;
- (BOOL)accessibilityIsContentsAttributeSettable;
- (id)accessibilityVerticalScrollBarAttribute;
- (BOOL)accessibilityIsVerticalScrollBarAttributeSettable;
- (id)accessibilityHorizontalScrollBarAttribute;
- (BOOL)accessibilityIsHorizontalScrollBarAttributeSettable;
@end

View File

@@ -66,58 +66,12 @@ static JNF_CLASS_CACHE(sjc_CAccessible, "sun/lwawt/macosx/CAccessible");
static JNF_MEMBER_CACHE(jf_ptr, sjc_CAccessible, "ptr", "J");
static JNF_STATIC_MEMBER_CACHE(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;");
static jobject sAccessibilityClass = NULL;
// sAttributeNamesForRoleCache holds the names of the attributes to which each java
// AccessibleRole responds (see AccessibleRole.java).
// This cache is queried before attempting to access a given attribute for a particular role.
static NSMutableDictionary *sAttributeNamesForRoleCache = nil;
static NSObject *sAttributeNamesLOCK = nil;
@interface TabGroupAccessibility : JavaComponentAccessibility {
NSInteger _numTabs;
}
- (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
- (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
- (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
- (NSArray *)accessibilityChildrenAttribute;
- (id) accessibilityTabsAttribute;
- (BOOL)accessibilityIsTabsAttributeSettable;
- (NSArray *)accessibilityContentsAttribute;
- (BOOL)accessibilityIsContentsAttributeSettable;
- (id) accessibilityValueAttribute;
@end
@interface TabGroupControlAccessibility : JavaComponentAccessibility {
jobject fTabGroupAxContext;
}
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole;
- (jobject)tabGroup;
- (void)getActionsWithEnv:(JNIEnv *)env;
- (id)accessibilityValueAttribute;
@end
@interface ScrollAreaAccessibility : JavaComponentAccessibility {
}
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
- (NSArray *)accessibilityContentsAttribute;
- (BOOL)accessibilityIsContentsAttributeSettable;
- (id)accessibilityVerticalScrollBarAttribute;
- (BOOL)accessibilityIsVerticalScrollBarAttributeSettable;
- (id)accessibilityHorizontalScrollBarAttribute;
- (BOOL)accessibilityIsHorizontalScrollBarAttributeSettable;
@end
@implementation JavaComponentAccessibility
- (NSString *)description
@@ -128,63 +82,17 @@ static NSObject *sAttributeNamesLOCK = nil;
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
{
self = [super init];
self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
if (self)
{
fParent = [parent retain];
fView = [view retain];
fJavaRole = [javaRole retain];
fAccessible = (*env)->NewWeakGlobalRef(env, accessible);
(*env)->ExceptionClear(env); // in case of OOME
jobject jcomponent = [(AWTView *)fView awtComponent:env];
fComponent = (*env)->NewWeakGlobalRef(env, jcomponent);
(*env)->DeleteLocalRef(env, jcomponent);
fIndex = index;
fActions = nil;
fActionsLOCK = [[NSObject alloc] init];
}
return self;
}
- (void)unregisterFromCocoaAXSystem
{
AWT_ASSERT_APPKIT_THREAD;
static dispatch_once_t initialize_unregisterUniqueId_once;
static void (*unregisterUniqueId)(id);
dispatch_once(&initialize_unregisterUniqueId_once, ^{
void *jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL);
unregisterUniqueId = dlsym(jrsFwk, "JRSAccessibilityUnregisterUniqueIdForUIElement");
});
if (unregisterUniqueId) unregisterUniqueId(self);
}
- (void)dealloc
{
[self unregisterFromCocoaAXSystem];
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
(*env)->DeleteWeakGlobalRef(env, fAccessible);
fAccessible = NULL;
(*env)->DeleteWeakGlobalRef(env, fComponent);
fComponent = NULL;
[fParent release];
fParent = nil;
[fNSRole release];
fNSRole = nil;
[fJavaRole release];
fJavaRole = nil;
[fView release];
fView = nil;
[fActions release];
fActions = nil;
@@ -194,211 +102,12 @@ static NSObject *sAttributeNamesLOCK = nil;
[super dealloc];
}
- (void)postValueChanged
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, NSAccessibilityValueChangedNotification);
}
- (void)postSelectedTextChanged
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, NSAccessibilitySelectedTextChangedNotification);
}
- (void)postSelectionChanged
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, NSAccessibilitySelectedChildrenChangedNotification);
}
- (void)postMenuOpened
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, (NSString *)kAXMenuOpenedNotification);
}
- (void)postMenuClosed
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, (NSString *)kAXMenuClosedNotification);
}
- (void)postMenuItemSelected
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, (NSString *)kAXMenuItemSelectedNotification);
}
- (BOOL)isEqual:(id)anObject
{
if (![anObject isKindOfClass:[self class]]) return NO;
JavaComponentAccessibility *accessibility = (JavaComponentAccessibility *)anObject;
JNIEnv* env = [ThreadUtilities getJNIEnv];
return (*env)->IsSameObject(env, accessibility->fAccessible, fAccessible);
}
- (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible
{
return (*env)->IsSameObject(env, fAccessible, accessible);
}
+ (void)initialize
{
if (sAttributeNamesForRoleCache == nil) {
sAttributeNamesLOCK = [[NSObject alloc] init];
sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:60];
}
if (sRoles == nil) {
initializeRoles();
}
if (sAccessibilityClass == NULL) {
JNF_STATIC_MEMBER_CACHE(jm_getAccessibility, sjc_CAccessibility, "getAccessibility", "([Ljava/lang/String;)Lsun/lwawt/macosx/CAccessibility;");
#ifdef JAVA_AX_NO_IGNORES
NSArray *ignoredKeys = [NSArray array];
#else
NSArray *ignoredKeys = [sRoles allKeysForObject:JavaAccessibilityIgnore];
#endif
jobjectArray result = NULL;
jsize count = [ignoredKeys count];
JNIEnv *env = [ThreadUtilities getJNIEnv];
static JNF_CLASS_CACHE(jc_String, "java/lang/String");
result = JNFNewObjectArray(env, &jc_String, count);
if (!result) {
NSLog(@"In %s, can't create Java array of String objects", __FUNCTION__);
return;
}
NSInteger i;
for (i = 0; i < count; i++) {
jstring jString = JNFNSToJavaString(env, [ignoredKeys objectAtIndex:i]);
(*env)->SetObjectArrayElement(env, result, i, jString);
(*env)->DeleteLocalRef(env, jString);
}
sAccessibilityClass = JNFCallStaticObjectMethod(env, jm_getAccessibility, result); // AWT_THREADING Safe (known object)
}
}
+ (void)postFocusChanged:(id)message
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification([NSApp accessibilityFocusedUIElement], NSAccessibilityFocusedUIElementChangedNotification);
}
+ (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {
return jaccessible;
} else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);
}
return NULL;
}
+ (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
{
if (parent->fAccessible == NULL) return nil;
jobjectArray jchildrenAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
if (jchildrenAndRoles == NULL) return nil;
jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
NSMutableArray *children = [NSMutableArray arrayWithCapacity:arrayLen/2]; //childrenAndRoles array contains two elements (child, role) for each child
NSInteger i;
NSUInteger childIndex = (whichChildren >= 0) ? whichChildren : 0; // if we're getting one particular child, make sure to set its index correctly
for(i = 0; i < arrayLen; i+=2)
{
jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
NSString *childJavaRole = nil;
if (jchildJavaRole != NULL) {
jobject jkey = JNFGetObjectField(env, jchildJavaRole, sjf_key);
childJavaRole = JNFJavaToNSString(env, jkey);
(*env)->DeleteLocalRef(env, jkey);
}
JavaComponentAccessibility *child = [self createWithParent:parent accessible:jchild role:childJavaRole index:childIndex withEnv:env withView:parent->fView];
(*env)->DeleteLocalRef(env, jchild);
(*env)->DeleteLocalRef(env, jchildJavaRole);
[children addObject:child];
childIndex++;
}
(*env)->DeleteLocalRef(env, jchildrenAndRoles);
return children;
}
+ (JavaComponentAccessibility *)createWithAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env withView:(NSView *)view
{
JavaComponentAccessibility *ret = nil;
jobject jcomponent = [(AWTView *)view awtComponent:env];
jint index = JNFCallStaticIntMethod(env, sjm_getAccessibleIndexInParent, jaccessible, jcomponent);
if (index >= 0) {
NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
ret = [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
}
(*env)->DeleteLocalRef(env, jcomponent);
return ret;
}
+ (JavaComponentAccessibility *) createWithAccessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
{
return [self createWithParent:nil accessible:jaccessible role:javaRole index:index withEnv:env withView:view];
}
+ (JavaComponentAccessibility *) createWithParent:(JavaComponentAccessibility *)parent accessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
{
// try to fetch the jCAX from Java, and return autoreleased
jobject jCAX = [JavaComponentAccessibility getCAccessible:jaccessible withEnv:env];
if (jCAX == NULL) return nil;
JavaComponentAccessibility *value = (JavaComponentAccessibility *) jlong_to_ptr(JNFGetLongField(env, jCAX, jf_ptr));
if (value != nil) {
(*env)->DeleteLocalRef(env, jCAX);
return [[value retain] autorelease];
}
// otherwise, create a new instance
JavaComponentAccessibility *newChild = nil;
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupAccessibility alloc];
} else if ([javaRole isEqualToString:@"scrollpane"]) {
newChild = [ScrollAreaAccessibility alloc];
} else {
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
} else {
newChild = [JavaComponentAccessibility alloc];
}
}
// must init freshly -alloc'd object
[newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
// If creating a JPopupMenu (not a combobox popup list) need to fire menuOpened.
// This is the only way to know if the menu is opening; visible state change
// can't be caught because the listeners are not set up in time.
if ( [javaRole isEqualToString:@"popupmenu"] &&
![[parent javaRole] isEqualToString:@"combobox"] ) {
[newChild postMenuOpened];
}
// must hard retain pointer poked into Java object
[newChild retain];
JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
(*env)->DeleteLocalRef(env, jCAX);
// return autoreleased instance
return [newChild autorelease];
}
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
@@ -533,101 +242,6 @@ static NSObject *sAttributeNamesLOCK = nil;
}
}
- (jobject)axContextWithEnv:(JNIEnv *)env
{
return getAxContext(env, fAccessible, fComponent);
}
- (id)parent
{
static JNF_CLASS_CACHE(sjc_Window, "java/awt/Window");
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleParent, sjc_CAccessibility, "getAccessibleParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
static JNF_STATIC_MEMBER_CACHE(sjm_getSwingAccessible, sjc_CAccessible, "getSwingAccessible", "(Ljavax/accessibility/Accessible;)Ljavax/accessibility/Accessible;");
if(fParent == nil) {
JNIEnv* env = [ThreadUtilities getJNIEnv];
jobject jparent = JNFCallStaticObjectMethod(env, sjm_getAccessibleParent, fAccessible, fComponent);
if (jparent == NULL) {
fParent = fView;
} else {
AWTView *view = fView;
jobject jax = JNFCallStaticObjectMethod(env, sjm_getSwingAccessible, fAccessible);
if (JNFIsInstanceOf(env, jax, &sjc_Window)) {
// In this case jparent is an owner toplevel and we should retrieve its own view
view = [AWTView awtView:env ofAccessible:jparent];
}
if (view != nil) {
fParent = [JavaComponentAccessibility createWithAccessible:jparent withEnv:env withView:view];
}
if (fParent == nil) {
fParent = fView;
}
(*env)->DeleteLocalRef(env, jparent);
(*env)->DeleteLocalRef(env, jax );
}
[fParent retain];
}
return fParent;
}
- (NSView *)view
{
return fView;
}
- (NSWindow *)window
{
return [[self view] window];
}
- (NSString *)javaRole
{
if(fJavaRole == nil) {
JNIEnv* env = [ThreadUtilities getJNIEnv];
fJavaRole = getJavaRole(env, fAccessible, fComponent);
[fJavaRole retain];
}
return fJavaRole;
}
- (BOOL)isMenu
{
id role = [self accessibilityRoleAttribute];
return [role isEqualToString:NSAccessibilityMenuBarRole] || [role isEqualToString:NSAccessibilityMenuRole] || [role isEqualToString:NSAccessibilityMenuItemRole];
}
- (BOOL)isSelected:(JNIEnv *)env
{
if (fIndex == -1) {
return NO;
}
return isChildSelected(env, ((JavaComponentAccessibility *)[self parent])->fAccessible, fIndex, fComponent);
}
- (BOOL)isSelectable:(JNIEnv *)env
{
jobject axContext = [self axContextWithEnv:env];
BOOL selectable = isSelectable(env, axContext, fComponent);
(*env)->DeleteLocalRef(env, axContext);
return selectable;
}
- (BOOL)isVisible:(JNIEnv *)env
{
if (fIndex == -1) {
return NO;
}
jobject axContext = [self axContextWithEnv:env];
BOOL showing = isShowing(env, axContext, fComponent);
(*env)->DeleteLocalRef(env, axContext);
return showing;
}
// the array of names for each role is cached in the sAttributeNamesForRoleCache
- (NSArray *)accessibilityAttributeNames
{
@@ -932,7 +546,11 @@ static NSObject *sAttributeNamesLOCK = nil;
// Element containing current element (id)
- (id)accessibilityParentAttribute
{
return NSAccessibilityUnignoredAncestor([self parent]);
id parent = [self parent];
if ([parent isKindOfClass:[JavaBaseAccessibility class]]) {
parent = ((JavaBaseAccessibility *)parent).platformAxElement;
}
return NSAccessibilityUnignoredAncestor(parent);
}
- (BOOL)accessibilityIsParentAttributeSettable
@@ -943,23 +561,8 @@ static NSObject *sAttributeNamesLOCK = nil;
// Screen position of element's lower-left corner in lower-left relative screen coordinates (NSValue)
- (NSValue *)accessibilityPositionAttribute
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
// NSAccessibility wants the bottom left point of the object in
// bottom left based screen coords
// Get the java screen coords, and make a NSPoint of the bottom left of the AxComponent.
NSSize size = getAxComponentSize(env, axComponent, fComponent);
NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
(*env)->DeleteLocalRef(env, axComponent);
point.y += size.height;
// Now make it into Cocoa screen coords.
point.y = [[[[self view] window] screen] frame].size.height - point.y;
return [NSValue valueWithPoint:point];
NSRect bounds = [self getBounds];
return [NSValue valueWithPoint:NSMakePoint(bounds.origin.x, bounds.origin.y)];
}
- (BOOL)accessibilityIsPositionAttributeSettable
@@ -1072,11 +675,7 @@ static NSObject *sAttributeNamesLOCK = nil;
// Element size (NSValue)
- (NSValue *)accessibilitySizeAttribute {
JNIEnv* env = [ThreadUtilities getJNIEnv];
jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
NSValue* size = [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
(*env)->DeleteLocalRef(env, axComponent);
return size;
return [NSValue valueWithSize:[self getSize]];
}
- (BOOL)accessibilityIsSizeAttributeSettable
@@ -1323,7 +922,8 @@ static NSObject *sAttributeNamesLOCK = nil;
if (JNFIsInstanceOf(env, jparent, &jc_Container)) {
jobject jaccessible = JNFCallStaticObjectMethod(env, jm_accessibilityHitTest, jparent, (jfloat)point.x, (jfloat)point.y); // AWT_THREADING Safe (AWTRunLoop)
if (jaccessible != NULL) {
value = [JavaComponentAccessibility createWithAccessible:jaccessible withEnv:env withView:fView];
value = [JavaBaseAccessibility createWithAccessible:jaccessible withEnv:env withView:fView];
value = ((JavaBaseAccessibility *)value).platformAxElement;
(*env)->DeleteLocalRef(env, jaccessible);
}
}
@@ -1344,149 +944,11 @@ static NSObject *sAttributeNamesLOCK = nil;
- (id)accessibilityFocusedUIElement
{
static JNF_STATIC_MEMBER_CACHE(jm_getFocusOwner, sjc_CAccessibility, "getFocusOwner", "(Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
JNIEnv *env = [ThreadUtilities getJNIEnv];
id value = nil;
NSWindow* hostWindow = [[self->fView window] retain];
jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop)
[hostWindow release];
if (focused != NULL) {
if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) {
value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
}
(*env)->DeleteLocalRef(env, focused);
}
if (value == nil) {
value = self;
}
#ifdef JAVA_AX_DEBUG
NSLog(@"%s: %@", __FUNCTION__, value);
#endif
return value;
return [self getFocusedElement];
}
@end
/*
* Class: sun_lwawt_macosx_CAccessibility
* Method: focusChanged
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
(JNIEnv *env, jobject jthis)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: valueChanged
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postValueChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: selectedTextChanged
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectedTextChanged
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postSelectedTextChanged)
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: selectionChanged
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuOpened
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuOpened)
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuClosed
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuClosed)
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuItemSelected
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuItemSelected)
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: unregisterFromCocoaAXSystem
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSystem
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
@implementation TabGroupAccessibility
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
@@ -1769,16 +1231,18 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
if ([children count] <= 0) return nil;
// The scroll bars are in the children.
JavaComponentAccessibility *aElement;
NSObject *aElement;
NSEnumerator *enumerator = [children objectEnumerator];
while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
jobject elementAxContext = [aElement axContextWithEnv:env];
if (isHorizontal(env, elementAxContext, fComponent)) {
while ((aElement = [enumerator nextObject])) {
if ([aElement respondsToSelector:@selector(accessibilityRoleAttribute)]) {
if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
jobject elementAxContext = [((NSObject <JavaBaseProvider> *)aElement).javaBase axContextWithEnv:env];
if (isHorizontal(env, elementAxContext, fComponent)) {
(*env)->DeleteLocalRef(env, elementAxContext);
return aElement;
}
(*env)->DeleteLocalRef(env, elementAxContext);
return aElement;
}
(*env)->DeleteLocalRef(env, elementAxContext);
}
}
@@ -1829,11 +1293,13 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
// The scroll bars are in the children. children less the scroll bars is the contents
NSEnumerator *enumerator = [children objectEnumerator];
JavaComponentAccessibility *aElement;
while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
if (![[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
// no scroll bars in contents
[(NSMutableArray *)contents addObject:aElement];
NSObject *aElement;
while ((aElement = [enumerator nextObject])) {
if ([aElement respondsToSelector:@selector(accessibilityRoleAttribute)]) {
if (![[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
// no scroll bars in contents
[(NSMutableArray *) contents addObject:aElement];
}
}
}

View File

@@ -0,0 +1,23 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#import "JavaBaseAccessibility.h"
@interface JavaElementAccessibility : JavaBaseAccessibility
@end
@interface PlatformAxElement : NSAccessibilityElement <JavaBaseProvider>
// begin of NSAccessibility protocol methods
- (BOOL)isAccessibilityElement;
- (NSString *)accessibilityLabel;
- (NSArray *)accessibilityChildren;
- (NSArray *)accessibilitySelectedChildren;
- (NSRect)accessibilityFrame;
- (id)accessibilityParent;
- (BOOL)accessibilityIsIgnored;
- (BOOL)isAccessibilityEnabled;
- (id)accessibilityApplicationFocusedUIElement;
- (id)getAccessibilityWindow;
// end of NSAccessibility protocol methods
@end

View File

@@ -0,0 +1,104 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#import "JavaElementAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
static void RaiseMustOverrideException(NSString *method)
{
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:@"You must override %@ in a subclass", method]
userInfo:nil];
};
@implementation JavaElementAccessibility
- (NSString *)getPlatformAxElementClassName
{
RaiseMustOverrideException(@"getPlatformAxElementClassName");
return NULL;
}
@end
@implementation PlatformAxElement
@synthesize javaBase;
- (BOOL)isAccessibilityElement
{
return YES;
}
- (NSString *)accessibilityLabel
{
// RaiseMustOverrideException(@"accessibilityLabel");
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axName = JNFCallStaticObjectMethod(env, sjm_getAccessibleName, [javaBase accessible], [javaBase component]);
NSString* str = JNFJavaToNSString(env, axName);
(*env)->DeleteLocalRef(env, axName);
return str;
}
- (NSArray *)accessibilityChildren
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
NSArray *children = [JavaBaseAccessibility childrenOfParent:self.javaBase
withEnv:env
withChildrenCode:JAVA_AX_ALL_CHILDREN
allowIgnored:[[self accessibilityRole] isEqualToString:NSAccessibilityListRole]];
if ([children count] > 0) {
return children;
}
return NULL;
}
- (NSArray *)accessibilitySelectedChildren
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
NSArray *selectedChildren = [JavaBaseAccessibility childrenOfParent:self.javaBase
withEnv:env
withChildrenCode:JAVA_AX_SELECTED_CHILDREN
allowIgnored:[[self accessibilityRole] isEqualToString:NSAccessibilityListRole]];
if ([selectedChildren count] > 0) {
return selectedChildren;
}
return NULL;
}
- (NSRect)accessibilityFrame
{
return [self.javaBase getBounds];
}
- (id)accessibilityParent
{
JavaBaseAccessibility *parent = (JavaBaseAccessibility *) [self.javaBase parent];
return parent.platformAxElement;
}
- (BOOL)accessibilityIsIgnored
{
RaiseMustOverrideException(@"accessibilityIsIgnored");
return NO;
}
- (BOOL)isAccessibilityEnabled
{
RaiseMustOverrideException(@"isAccessibilityEnabled");
return YES;
}
- (id)accessibilityApplicationFocusedUIElement
{
return [self.javaBase getFocusedElement];
}
- (id)getAccessibilityWindow
{
return [self.javaBase window];
}
@end

View File

@@ -0,0 +1,14 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#ifndef NATIVE_JAVALISTACCESSIBILITY_H
#define NATIVE_JAVALISTACCESSIBILITY_H
#endif // NATIVE_JAVALISTACCESSIBILITY_H
#import "JavaElementAccessibility.h"
@interface JavaListAccessibility : JavaElementAccessibility
@end
@interface PlatformAxList : PlatformAxElement <NSAccessibilityList>
@end

View File

@@ -0,0 +1,56 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#import "JavaListAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
@implementation JavaListAccessibility
- (NSString *)getPlatformAxElementClassName
{
return @"PlatformAxList";
}
@end
@implementation PlatformAxList
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilityRows
{
return [self accessibilityChildren];
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedRows
{
return [self accessibilitySelectedChildren];
}
- (NSString *)accessibilityLabel
{
return @"List";
}
- (BOOL)accessibilityIsIgnored
{
return NO;
}
- (BOOL)isAccessibilityEnabled
{
return YES;
}
// to avoid warning (why?): method in protocol 'NSAccessibilityElement' not implemented
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
// to avoid warning (why?): method in protocol 'NSAccessibilityElement' not implemented
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

View File

@@ -0,0 +1,11 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#import "JavaElementAccessibility.h"
@interface JavaRowAccessibility : JavaElementAccessibility
@end
@interface PlatformAxRow : PlatformAxElement <NSAccessibilityRow> {
BOOL enabled;
}
@end

View File

@@ -0,0 +1,72 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
#include "jni.h"
#import "JavaRowAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "JavaTextAccessibility.h"
#import "JavaListAccessibility.h"
#import "ThreadUtilities.h"
@implementation JavaRowAccessibility
- (NSString *)getPlatformAxElementClassName {
return @"PlatformAxRow";
}
@end
@implementation PlatformAxRow
- (NSArray *)accessibilityChildren {
NSArray *children = [super accessibilityChildren];
if (children == NULL) {
NSString *javaRole = [[self javaBase] javaRole];
JavaBaseAccessibility *newChild = nil;
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupAccessibility alloc];
} else if ([javaRole isEqualToString:@"scrollpane"]) {
newChild = [ScrollAreaAccessibility alloc];
} else {
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
} else if ([nsRole isEqualToString:NSAccessibilityListRole]) {
newChild = [JavaListAccessibility alloc];
} else {
newChild = [JavaComponentAccessibility alloc];
}
}
[newChild initWithParent:[self javaBase]
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:[[self javaBase] accessible]
withIndex:[[self javaBase] index]
withView:[[self javaBase] view]
withJavaRole:javaRole];
return [NSArray arrayWithObject:[newChild autorelease]];
} else {
return children;
}
}
- (NSInteger)accessibilityIndex {
return [[self accessibilityParent] accessibilityIndexOfChild:self];
}
- (NSString *)accessibilityLabel {
return [super accessibilityLabel];
}
// to avoid warning (why?): method in protocol 'NSAccessibilityElement' not implemented
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
// to avoid warning (why?): method in protocol 'NSAccessibilityElement' not implemented
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end