Compare commits

..

12 Commits
72 ... jb17-b87

Author SHA1 Message Date
Artem Semenov
efabfd0370 8267385: Create NSAccessibilityElement implementation for JavaComponentAccessibility
8262031: Create implementation for NSAccessibilityNavigableStaticText protocol
8264287: Create implementation for NSAccessibilityComboBox protocol peer
8264303: Create implementation for NSAccessibilityTabGroup protocol peer
8264292: Create implementation for NSAccessibilityList protocol peer
8267387: Create implementation for NSAccessibilityOutline protocol
8267388: Create implementation for NSAccessibilityTable protocol
8264286: Create implementation for NSAccessibilityColumn protocol peer
8264298: Create implementation for NSAccessibilityRow protocol peer
8264291: Create implementation for NSAccessibilityCell protocol peer

Reviewed-by: kizune, pbansal, serb
2021-09-11 06:08:56 +07:00
Dmitry Batrak
f757a39090 JBR-3504 a11y focus is set on the wrong element when opening popups
(cherry-picked from commit a69e12e0d2)
2021-09-10 17:49:14 +03:00
Dmitry Batrak
1039653b97 JBR-3726 Modal windows 'disappear' on minimize in KDE
restrict change to KDE only, as it causes problems on GNOME (JBR-3750)

(cherry picked from commit 9c2841028f)
2021-09-10 17:49:09 +03:00
Maxim Kartashev
65fa801231 JBR-3665 Typing is slow in remote X session
Only call XGetKeyboardMapping() once for all valid codes and cache the
resulting table. Use the cache on the subsequent calls to
keycodeToKeysym().
2021-09-10 12:35:45 +03:00
Nikita Gubarkov
3d9ae4dbe8 JBR-3638 Adjust subpixel glyph positions for correct rounding in CStrike#getGlyphImageBounds 2021-09-08 04:23:24 +03:00
Maxim Kartashev
ef8e01b0d4 JBR-2273 JBR musl port
Detect if we're running on a musl-based system by checking for the presence
of the libgcompat.so glibc compatibility library in the process' map.
If so, java is re-started with LD_LIBRARY_PATH set to point to the right
directory with libjvm.so. This works around the problem with the musl
dynamic library loader.

(based on commit 13a904ddb5)
2021-09-07 15:02:17 +03:00
Alexey Ushakov
eaa9c1618e JBR-3727 JBR17-Metal: Flickering on tooltip appearance
Used setOpaque() method to set correct background of platform window
2021-09-03 15:14:58 +02:00
Maxim Kartashev
ee3c7edd84 JBR-3664 Logging for communications with X server
Introduced logging controlled with -Dsun.awt.x11.trace.
Currently, only looks at the AWT lock and reports methods holding it
sorted by average hold time.

(based on commit 792a58ea0e)
(based on commit 770b4dc9c1)
2021-09-01 23:02:37 -07:00
Dmitry Batrak
8a19c38728 JBR-3726 Modal windows 'disappear' on minimize in KDE
(cherry picked from commit d9baf2d9db)
2021-09-01 16:19:38 +03:00
Maxim Kartashev
4fcd80acf0 JBR-3712 Add project creation instructions to JBR README 2021-08-31 14:21:38 +03:00
Maxim Kartashev
6f5dd836de 8269223: -Xcheck:jni WARNINGs working with fonts on Linux
Reviewed-by: prr, serb

(AKA JBR-3542 Fix -Xcheck:jni warnings)
(Based on commit 9bc023220f, includes additional fixes for JBR-specific code)
2021-08-31 13:12:36 +03:00
Maxim Kartashev
2ff21b425e 8267307: Introduce new client property for XAWT: xawt.mwm_decor_title
Reviewed-by: azvegint, serb

(AKA JBR-3416 Introduce new client property for Linux: xawt.mwm_decor_title)
2021-08-30 06:50:11 -07:00
78 changed files with 5688 additions and 259 deletions

View File

@@ -16,6 +16,7 @@ It includes a number enhancements in font rendering, HiDPI support, ligatures, p
- [Ubuntu Linux](#ubuntu-linux)
- [Windows](#build-windows)
- [macOS](#macos)
- [Developing](#developing)
- [Contributing](#contributing)
- [Resources](#resources)
@@ -130,6 +131,31 @@ $ make images
```
This will build the release configuration under `./build/macosx-x86_64-server-release/`.
## Developing
You can use [CLion](https://www.jetbrains.com/clion/) to develop native parts of the JetBrains Runtime and
[IntelliJ IDEA](https://www.jetbrains.com/idea/) for the parts written in Java.
Both require projects to be created.
### CLion
Run
```
$ make compile-commands
```
in the git root and open the resulting `build/.../compile_commands.json` file as a project.
Then use `Tools | Compilation Database | Change Project Root` to point to git root of this repository.
See also this detailed step-by-step tutorial for all platforms:
[How to develop OpenJDK with CLion](https://blog.jetbrains.com/clion/2020/03/openjdk-with-clion/).
### IDEA
Run
```
$ sh ./bin/idea.sh
```
in the git root to generate project files (add `--help` for options). If you have multiple
configurations (for example, `release` and `fastdebug`), supply the `--conf <conf_name>` argument.
Then open the git root directory as a project in IDEA.
## Contributing
We are happy to receive your pull requests!
Before you submit one, please sign our [Contributor License Agreement (CLA)](https://www.jetbrains.com/agreements/cla/).

View File

@@ -27,6 +27,7 @@
#include "jvm_md.h"
#include <dirent.h>
#include <dlfcn.h>
#include <link.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
@@ -220,6 +221,39 @@ ContainsLibJVM(const char *env) {
return JNI_FALSE;
}
static int
HaveGLibCCompatLibrary(struct dl_phdr_info* info, size_t size, void* data)
{
static const char * const GLIBC_COMPAT_LIBRARY_NAME = "libgcompat.so";
const char * const so_pathname = info->dlpi_name;
if (so_pathname != NULL && so_pathname[0] != 0) {
const char * const last_slash = JLI_StrRChr(so_pathname, '/');
const char * const so_basename = (last_slash != NULL) ? last_slash + 1 : so_pathname;
if (JLI_StrNCmp(so_basename, GLIBC_COMPAT_LIBRARY_NAME, JLI_StrLen(GLIBC_COMPAT_LIBRARY_NAME)) == 0) {
return JNI_TRUE;
}
}
return 0; /* also means continue to iterate */
}
static jboolean
UsingMusl(void) {
const jlong start = CurrentTimeMicros();
const int found_gcompat = dl_iterate_phdr(HaveGLibCCompatLibrary, NULL);
if (JLI_IsTraceLauncher()) {
const jlong end = CurrentTimeMicros();
JLI_TraceLauncher("%ld micro seconds to check for the musl compatibility layer for glibc\n",
(long)(end - start));
}
return (found_gcompat != 0);
}
/*
* Test whether the environment variable needs to be set, see flowchart.
*/
@@ -243,6 +277,10 @@ RequiresSetenv(const char *jvmpath) {
return JNI_TRUE;
#endif
if (UsingMusl()) {
return JNI_TRUE;
}
llp = getenv("LD_LIBRARY_PATH");
/* no environment variable is a good environment variable */
if (llp == NULL && dmllp == NULL) {

View File

@@ -32,6 +32,7 @@ import java.awt.geom.*;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import sun.lwawt.macosx.CThreading;
import static sun.awt.SunHints.*;
public final class CStrike extends PhysicalStrike {
@@ -205,7 +206,15 @@ public final class CStrike extends PhysicalStrike {
return;
}
result.setRect(floatRect.x + pt.x, floatRect.y + pt.y, floatRect.width, floatRect.height);
boolean subpixel = desc.aaHint == INTVAL_TEXT_ANTIALIAS_ON &&
desc.fmHint == INTVAL_FRACTIONALMETRICS_ON;
float subpixelResolutionX = subpixel ? FontUtilities.subpixelResolution.width : 1;
float subpixelResolutionY = subpixel ? FontUtilities.subpixelResolution.height : 1;
// Before rendering, glyph positions are offset by 0.5 pixels, take into consideration
float x = ((int) (pt.x * subpixelResolutionX + 0.5f)) / subpixelResolutionX;
float y = ((int) (pt.y * subpixelResolutionY + 0.5f)) / subpixelResolutionY;
result.setRect(floatRect.x + x, floatRect.y + y, floatRect.width, floatRect.height);
}
private void getGlyphImageBounds(int glyphCode, float x, float y, Rectangle2D.Float floatRect) {

View File

@@ -291,6 +291,10 @@ public class LWWindowPeer
updateFocusableWindowState();
super.setVisibleImpl(visible);
// TODO: update graphicsConfig, see 4868278
if (visible) {
// Set correct background for a window before making it visible
platformWindow.setOpaque(!isTranslucent());
}
platformWindow.setVisible(visible);
}

View File

@@ -35,12 +35,14 @@ import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.annotation.Native;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Arrays;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleAction;
@@ -59,6 +61,8 @@ import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JTextArea;
import javax.swing.JList;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import sun.awt.AWTAccessor;
@@ -128,7 +132,7 @@ class CAccessibility implements PropertyChangeListener {
static <T> T invokeAndWait(final Callable<T> callable, final Component c) {
if (c != null) {
try {
return EventQueue.isDispatchThread() ? callable.call() : LWCToolkit.invokeAndWait(callable, c);
return EventQueue.isDispatchThread() ? callable.call() : invokeAndWait(callable, c, (T)null);
} catch (final Exception e) { e.printStackTrace(); }
}
return null;
@@ -561,6 +565,10 @@ class CAccessibility implements PropertyChangeListener {
if (pac == null) return;
AccessibleSelection as = pac.getAccessibleSelection();
if (as == null) return;
if (parent instanceof JList) {
((JList) parent).setSelectedIndex(i);
return;
}
as.addAccessibleSelection(i);
}
}, c);
@@ -661,77 +669,148 @@ class CAccessibility implements PropertyChangeListener {
// Duplicated from JavaComponentAccessibility
// Note that values >=0 are indexes into the child array
static final int JAVA_AX_ALL_CHILDREN = -1;
static final int JAVA_AX_SELECTED_CHILDREN = -2;
static final int JAVA_AX_VISIBLE_CHILDREN = -3;
@Native static final int JAVA_AX_ALL_CHILDREN = -1;
@Native static final int JAVA_AX_SELECTED_CHILDREN = -2;
@Native static final int JAVA_AX_VISIBLE_CHILDREN = -3;
// Each child takes up two entries in the array: one for itself and one for its role
public static Object[] getChildrenAndRoles(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored) {
if (a == null) return null;
return invokeAndWait(new Callable<Object[]>() {
public Object[] call() throws Exception {
ArrayList<Object> childrenAndRoles = new ArrayList<Object>();
_addChildren(a, whichChildren, allowIgnored, childrenAndRoles);
/* In the case of fetching a selection, need to check to see if
* the active descendant is at the beginning of the list. If it
* is not it needs to be moved to the beginning of the list so
* VoiceOver will annouce it correctly. The list returned
* from Java is always in order from top to bottom, but when shift
* selecting downward (extending the list) or multi-selecting using
* the VO keys control+option+command+return the active descendant
* is not at the top of the list in the shift select down case and
* may not be in the multi select case.
*/
if (whichChildren == JAVA_AX_SELECTED_CHILDREN) {
if (!childrenAndRoles.isEmpty()) {
AccessibleContext activeDescendantAC =
CAccessible.getActiveDescendant(a);
if (activeDescendantAC != null) {
String activeDescendantName =
activeDescendantAC.getAccessibleName();
AccessibleRole activeDescendantRole =
activeDescendantAC.getAccessibleRole();
// Move active descendant to front of list.
// List contains pairs of each selected item's
// Accessible and AccessibleRole.
ArrayList<Object> newArray = new ArrayList<Object>();
int count = childrenAndRoles.size();
Accessible currentAccessible = null;
AccessibleContext currentAC = null;
String currentName = null;
AccessibleRole currentRole = null;
for (int i = 0; i < count; i+=2) {
// Is this the active descendant?
currentAccessible = (Accessible)childrenAndRoles.get(i);
currentAC = currentAccessible.getAccessibleContext();
currentName = currentAC.getAccessibleName();
currentRole = (AccessibleRole)childrenAndRoles.get(i+1);
if (currentName != null && currentName.equals(activeDescendantName) &&
currentRole.equals(activeDescendantRole) ) {
newArray.add(0, currentAccessible);
newArray.add(1, currentRole);
} else {
newArray.add(currentAccessible);
newArray.add(currentRole);
}
}
childrenAndRoles = newArray;
}
}
}
if ((whichChildren < 0) || (whichChildren * 2 >= childrenAndRoles.size())) {
return childrenAndRoles.toArray();
}
return new Object[] { childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1) };
return getChildrenAndRolesImpl(a, c, whichChildren, allowIgnored);
}
}, c);
}
private static final int JAVA_AX_ROWS = 1;
private static final int JAVA_AX_COLS = 2;
private static Object[] getChildrenAndRolesImpl(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored) {
if (a == null) return null;
ArrayList<Object> childrenAndRoles = new ArrayList<Object>();
_addChildren(a, whichChildren, allowIgnored, childrenAndRoles);
/* In case of fetching a selection, we need to check if
* the active descendant is at the beginning of the list, or
* otherwise move it, so that VoiceOver announces it correctly.
* The java list is always in order from top to bottom, but when
* (1) shift-selecting downward (extending the list) or (2) multi-selecting with
* the VO keys (CTRL+ALT+CMD+RETURN) the active descendant
* is not at the top of the list in the 1st case and may not be in the 2nd.
*/
if (whichChildren == JAVA_AX_SELECTED_CHILDREN) {
if (!childrenAndRoles.isEmpty()) {
AccessibleContext activeDescendantAC =
CAccessible.getActiveDescendant(a);
if (activeDescendantAC != null) {
String activeDescendantName =
activeDescendantAC.getAccessibleName();
AccessibleRole activeDescendantRole =
activeDescendantAC.getAccessibleRole();
// Move active descendant to front of list.
// List contains pairs of each selected item's
// Accessible and AccessibleRole.
ArrayList<Object> newArray = new ArrayList<Object>();
int count = childrenAndRoles.size();
Accessible currentAccessible = null;
AccessibleContext currentAC = null;
String currentName = null;
AccessibleRole currentRole = null;
for (int i = 0; i < count; i += 2) {
// Is this the active descendant?
currentAccessible = (Accessible) childrenAndRoles.get(i);
currentAC = currentAccessible.getAccessibleContext();
currentName = currentAC.getAccessibleName();
currentRole = (AccessibleRole) childrenAndRoles.get(i + 1);
if (currentName != null && currentName.equals(activeDescendantName) &&
currentRole.equals(activeDescendantRole)) {
newArray.add(0, currentAccessible);
newArray.add(1, currentRole);
} else {
newArray.add(currentAccessible);
newArray.add(currentRole);
}
}
childrenAndRoles = newArray;
}
}
}
if ((whichChildren < 0) || (whichChildren * 2 >= childrenAndRoles.size())) {
return childrenAndRoles.toArray();
}
return new Object[]{childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1)};
}
// This method is called from the native
// Each child takes up three entries in the array: one for itself, one for its role, and one for the recursion level
private static Object[] getChildrenAndRolesRecursive(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored, final int level) {
if (a == null) return null;
return invokeAndWait(new Callable<Object[]>() {
public Object[] call() throws Exception {
ArrayList<Object> currentLevelChildren = new ArrayList<Object>();
ArrayList<Object> allChildren = new ArrayList<Object>();
ArrayList<Accessible> parentStack = new ArrayList<Accessible>();
parentStack.add(a);
ArrayList<Integer> indexses = new ArrayList<Integer>();
Integer index = 0;
int currentLevel = level;
while (!parentStack.isEmpty()) {
Accessible p = parentStack.get(parentStack.size() - 1);
currentLevelChildren.addAll(Arrays.asList(getChildrenAndRolesImpl(p, c, JAVA_AX_ALL_CHILDREN, allowIgnored)));
if ((currentLevelChildren.size() == 0) || (index >= currentLevelChildren.size())) {
if (!parentStack.isEmpty()) parentStack.remove(parentStack.size() - 1);
if (!indexses.isEmpty()) index = indexses.remove(indexses.size() - 1);
currentLevel -= 1;
currentLevelChildren.clear();
continue;
}
Accessible ca = null;
Object obj = currentLevelChildren.get(index);
if (!(obj instanceof Accessible)) {
index += 2;
currentLevelChildren.clear();
continue;
}
ca = (Accessible) obj;
Object role = currentLevelChildren.get(index + 1);
currentLevelChildren.clear();
AccessibleContext cac = ca.getAccessibleContext();
if (cac == null) {
index += 2;
continue;
}
if ((cac.getAccessibleStateSet().contains(AccessibleState.SELECTED) && (whichChildren == JAVA_AX_SELECTED_CHILDREN)) ||
(cac.getAccessibleStateSet().contains(AccessibleState.VISIBLE) && (whichChildren == JAVA_AX_VISIBLE_CHILDREN)) ||
(whichChildren == JAVA_AX_ALL_CHILDREN)) {
allChildren.add(ca);
allChildren.add(role);
allChildren.add(String.valueOf(currentLevel));
}
index += 2;
if (cac.getAccessibleStateSet().contains(AccessibleState.EXPANDED)) {
parentStack.add(ca);
indexses.add(index);
index = 0;
currentLevel += 1;
continue;
}
}
return allChildren.toArray();
}
}, c);
}
@Native private static final int JAVA_AX_ROWS = 1;
@Native private static final int JAVA_AX_COLS = 2;
public static int getTableInfo(final Accessible a, final Component c,
final int info) {
@@ -750,6 +829,23 @@ class CAccessibility implements PropertyChangeListener {
}, c);
}
private static int[] getTableSelectedInfo(final Accessible a, final Component c,
final int info) {
if (a == null) return null;
return invokeAndWait(() -> {
AccessibleContext ac = a.getAccessibleContext();
AccessibleTable table = ac.getAccessibleTable();
if (table != null) {
if (info == JAVA_AX_COLS) {
return table.getSelectedAccessibleColumns();
} else if (info == JAVA_AX_ROWS) {
return table.getSelectedAccessibleRows();
}
}
return null;
}, c);
}
private static AccessibleRole getAccessibleRoleForLabel(JLabel l, AccessibleRole fallback) {
String text = l.getText();
if (text != null && text.length() > 0) {
@@ -868,4 +964,18 @@ class CAccessibility implements PropertyChangeListener {
}
}, (Component)ax);
}
private static boolean isTreeRootVisible(Accessible a, Component c) {
if (a == null) return false;
return invokeAndWait(new Callable<Boolean>() {
public Boolean call() throws Exception {
Accessible sa = CAccessible.getSwingAccessible(a);
if (sa instanceof JTree) {
return ((JTree) sa).isRootVisible();
}
return false;
}
}, c);
}
}

View File

@@ -31,11 +31,7 @@ import java.beans.PropertyChangeListener;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.JProgressBar;
import javax.swing.JTabbedPane;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_CARET_PROPERTY;
@@ -75,6 +71,8 @@ class CAccessible extends CFRetainedResource implements Accessible {
private static native void menuOpened(long ptr);
private static native void menuClosed(long ptr);
private static native void menuItemSelected(long ptr);
private static native void treeNodeExpanded(long ptr);
private static native void treeNodeCollapsed(long ptr);
private Accessible accessible;
@@ -137,6 +135,13 @@ class CAccessible extends CFRetainedResource implements Accessible {
if (parentAccessible != null) {
parentRole = parentAccessible.getAccessibleContext().getAccessibleRole();
}
if (newValue == AccessibleState.EXPANDED) {
treeNodeExpanded(ptr);
} else if (newValue == AccessibleState.COLLAPSED) {
treeNodeCollapsed(ptr);
}
// At least for now don't handle combo box menu state changes.
// This may change when later fixing issues which currently
// exist for combo boxes, but for now the following is only

View File

@@ -422,15 +422,15 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
protected int getInitialStyleBits() {
// defaults style bits
int styleBits = DECORATED | HAS_SHADOW | CLOSEABLE | MINIMIZABLE | ZOOMABLE | RESIZABLE | TITLE_VISIBLE;
int styleBits = DECORATED | HAS_SHADOW | CLOSEABLE | ZOOMABLE | RESIZABLE | TITLE_VISIBLE;
styleBits |= getFocusableStyleBits();
final boolean isFrame = (target instanceof Frame);
final boolean isDialog = (target instanceof Dialog);
final boolean isPopup = (target.getType() == Window.Type.POPUP);
if (isDialog) {
styleBits = SET(styleBits, MINIMIZABLE, false);
if (isFrame) {
styleBits = SET(styleBits, MINIMIZABLE, true);
}
// Either java.awt.Frame or java.awt.Dialog can be undecorated, however java.awt.Window always is undecorated.

View File

@@ -27,8 +27,7 @@
#import "CGLGraphicsConfig.h"
#import "AWTView.h"
#import "AWTWindow.h"
#import "JavaComponentAccessibility.h"
#import "JavaTextAccessibility.h"
#import "a11y/CommonComponentAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "GeomUtilities.h"
#import "ThreadUtilities.h"
@@ -698,42 +697,29 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
- (id)getAxData:(JNIEnv*)env
{
jobject jcomponent = [self awtComponent:env];
id ax = [[[JavaComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:jcomponent withIndex:-1 withView:self withJavaRole:nil] autorelease];
id ax = [[[CommonComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:jcomponent withIndex:-1 withView:self withJavaRole:nil] autorelease];
(*env)->DeleteLocalRef(env, jcomponent);
return ax;
}
- (NSArray *)accessibilityAttributeNames
{
return [[super accessibilityAttributeNames] arrayByAddingObject:NSAccessibilityChildrenAttribute];
}
// NSAccessibility messages
// attribute methods
- (id)accessibilityAttributeValue:(NSString *)attribute
- (id)accessibilityChildren
{
AWT_ASSERT_APPKIT_THREAD;
JNIEnv *env = [ThreadUtilities getJNIEnv];
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
(*env)->PushLocalFrame(env, 4);
(*env)->PushLocalFrame(env, 4);
id result = NSAccessibilityUnignoredChildrenForOnlyChild([self getAxData:env]);
id result = NSAccessibilityUnignoredChildrenForOnlyChild([self getAxData:env]);
(*env)->PopLocalFrame(env, NULL);
(*env)->PopLocalFrame(env, NULL);
return result;
}
else
{
return [super accessibilityAttributeValue:attribute];
}
return result;
}
- (BOOL)accessibilityIsIgnored
- (BOOL)isAccessibilityElement
{
return YES;
return NO;
}
- (id)accessibilityHitTest:(NSPoint)point
@@ -743,7 +729,7 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
(*env)->PushLocalFrame(env, 4);
id result = [[self getAxData:env] accessibilityHitTest:point withEnv:env];
id result = [[self getAxData:env] accessibilityHitTest:point];
(*env)->PopLocalFrame(env, NULL);
@@ -768,17 +754,24 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
// --- Services menu support for lightweights ---
// finds the focused accessible element, and if it is a text element, obtains the text from it
- (NSString *)accessibleSelectedText
- (NSString *)accessibilitySelectedText
{
id focused = [self accessibilityFocusedUIElement];
if (![focused isKindOfClass:[JavaTextAccessibility class]]) return nil;
return [(JavaTextAccessibility *)focused accessibilitySelectedTextAttribute];
if (![focused respondsToSelector:@selector(accessibilitySelectedText)]) return nil;
return [focused accessibilitySelectedText];
}
- (void)setAccessibilitySelectedText:(NSString *)accessibilitySelectedText {
id focused = [self accessibilityFocusedUIElement];
if ([focused respondsToSelector:@selector(setAccessibilitySelectedText:)]) {
[focused setAccessibilitySelectedText:accessibilitySelectedText];
}
}
// same as above, but converts to RTFD
- (NSData *)accessibleSelectedTextAsRTFD
{
NSString *selectedText = [self accessibleSelectedText];
NSString *selectedText = [self accessibilitySelectedText];
NSAttributedString *styledText = [[NSAttributedString alloc] initWithString:selectedText];
NSData *rtfdData = [styledText RTFDFromRange:NSMakeRange(0, [styledText length])
documentAttributes:
@@ -791,8 +784,8 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
- (BOOL)replaceAccessibleTextSelection:(NSString *)text
{
id focused = [self accessibilityFocusedUIElement];
if (![focused isKindOfClass:[JavaTextAccessibility class]]) return NO;
[(JavaTextAccessibility *)focused accessibilitySetSelectedTextAttribute:text];
if (![focused respondsToSelector:@selector(setAccessibilitySelectedText)]) return NO;
[focused setAccessibilitySelectedText:text];
return YES;
}
@@ -802,7 +795,7 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
if ([[self window] firstResponder] != self) return nil; // let AWT components handle themselves
if ([sendType isEqual:NSStringPboardType] || [returnType isEqual:NSStringPboardType]) {
NSString *selectedText = [self accessibleSelectedText];
NSString *selectedText = [self accessibilitySelectedText];
if (selectedText) return self;
}
@@ -815,7 +808,7 @@ extern bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, N
if ([types containsObject:NSStringPboardType])
{
[pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
return [pboard setString:[self accessibleSelectedText] forType:NSStringPboardType];
return [pboard setString:[self accessibilitySelectedText] forType:NSStringPboardType];
}
if ([types containsObject:NSRTFDPboardType])

View File

@@ -635,6 +635,7 @@ AWT_ASSERT_APPKIT_THREAD;
DECLARE_CLASS(jc_CCursorManager, "sun/lwawt/macosx/CCursorManager");
DECLARE_STATIC_METHOD(sjm_resetCurrentCursor, jc_CCursorManager, "resetCurrentCursor", "()V");
(*env)->CallStaticVoidMethod(env, jc_CCursorManager, sjm_resetCurrentCursor);
CHECK_EXCEPTION();
}
- (BOOL) canBecomeMainWindow {

View File

@@ -129,6 +129,7 @@ JNI_COCOA_ENTER(env);
JNI_COCOA_ENTER(blockEnv);
// call the user's runnable
(*blockEnv)->CallVoidMethod(blockEnv, runnableRef, jm_run);
CHECK_EXCEPTION_IN_ENV(blockEnv);
(*blockEnv)->DeleteGlobalRef(blockEnv, runnableRef);
JNI_COCOA_EXIT(blockEnv);
});

View File

@@ -26,6 +26,10 @@
#import <AppKit/AppKit.h>
#import <jni.h>
extern NSMutableDictionary *sActions;
extern NSMutableDictionary *sActionSelectors;
extern NSMutableArray *sAllActionSelectors;
void initializeActions();
@protocol JavaAccessibilityAction

View File

@@ -29,6 +29,10 @@
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
NSMutableDictionary *sActions = nil;
NSMutableDictionary *sActionSelectors = nil;
NSMutableArray *sAllActionSelectors = nil;
void initializeActions();
@implementation JavaAxAction
@@ -148,3 +152,31 @@
}
@end
void initializeActions() {
int actionsCount = 5;
sActions = [[NSMutableDictionary alloc] initWithCapacity:actionsCount];
[sActions setObject:NSAccessibilityPressAction forKey:@"click"];
[sActions setObject:NSAccessibilityIncrementAction forKey:@"increment"];
[sActions setObject:NSAccessibilityDecrementAction forKey:@"decrement"];
[sActions setObject:NSAccessibilityShowMenuAction forKey:@"togglePopup"];
[sActions setObject:NSAccessibilityPressAction forKey:@"toggleExpand"];
sActionSelectors = [[NSMutableDictionary alloc] initWithCapacity:actionsCount];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformPress)) forKey:NSAccessibilityPressAction];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformShowMenu)) forKey:NSAccessibilityShowMenuAction];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformDecrement)) forKey:NSAccessibilityDecrementAction];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformIncrement)) forKey:NSAccessibilityIncrementAction];
[sActionSelectors setObject:NSStringFromSelector(@selector(accessibilityPerformPick)) forKey:NSAccessibilityPickAction];
sAllActionSelectors = [[NSMutableArray alloc] initWithCapacity:actionsCount];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformPick))];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformIncrement))];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformDecrement))];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformShowMenu))];
[sAllActionSelectors addObject:NSStringFromSelector(@selector(accessibilityPerformPress))];
}

View File

@@ -48,6 +48,7 @@ BOOL isVertical(JNIEnv *env, jobject axContext, jobject component);
BOOL isHorizontal(JNIEnv *env, jobject axContext, jobject component);
BOOL isShowing(JNIEnv *env, jobject axContext, jobject component);
BOOL isSelectable(JNIEnv *env, jobject axContext, jobject component);
BOOL isExpanded(JNIEnv *env, jobject axContext, jobject component);
NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject component);
jint getAxTextCharCount(JNIEnv *env, jobject axText, jobject component);
@@ -60,3 +61,6 @@ void JavaAccessibilitySetAttributeValue(id element, NSString *attribute, id valu
void JavaAccessibilityRaiseSetAttributeToIllegalTypeException(const char *functionName, id element, NSString *attribute, id value);
void JavaAccessibilityRaiseUnimplementedAttributeException(const char *functionName, id element, NSString *attribute);
void JavaAccessibilityRaiseIllegalParameterTypeException(const char *functionName, id element, NSString *attribute, id parameter);
BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
NSNumber* JavaNumberToNSNumber(JNIEnv *env, jobject jnumber);
NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array);

View File

@@ -27,6 +27,7 @@
#import "JNIUtilities.h"
#import <AppKit/AppKit.h>
#import "ThreadUtilities.h"
static BOOL JavaAccessibilityIsSupportedAttribute(id element, NSString *attribute);
static void JavaAccessibilityLogError(NSString *message);
@@ -199,6 +200,20 @@ BOOL isSelectable(JNIEnv *env, jobject axContext, jobject component)
return selectable;
}
BOOL isExpanded(JNIEnv *env, jobject axContext, jobject component)
{
GET_ACCESSIBLESTATE_CLASS_RETURN(NO);
DECLARE_STATIC_FIELD_RETURN(jm_EXPANDED,
sjc_AccessibleState,
"EXPANDED",
"Ljavax/accessibility/AccessibleState;", NO );
jobject axExpandedState = (*env)->GetStaticObjectField(env, sjc_AccessibleState, jm_EXPANDED);
CHECK_EXCEPTION_NULL_RETURN(axExpandedState, NO);
BOOL expanded = containsAxState(env, axContext, axExpandedState, component);
(*env)->DeleteLocalRef(env, axExpandedState);
return expanded;
}
NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject component)
{
GET_CACCESSIBILITY_CLASS_RETURN(NSZeroPoint);
@@ -348,6 +363,75 @@ static void JavaAccessibilityLogError(NSString *message)
NSLog(@"!!! %@", message);
}
/*
* Returns Object.equals for the two items
* This may use LWCToolkit.invokeAndWait(); don't call while holding fLock
* and try to pass a component so the event happens on the correct thread.
*/
BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component)
{
DECLARE_CLASS_RETURN(sjc_Object, "java/lang/Object", NO);
DECLARE_METHOD_RETURN(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z", NO);
if ((a == NULL) && (b == NULL)) return YES;
if ((a == NULL) || (b == NULL)) return NO;
if (pthread_main_np() != 0) {
// If we are on the AppKit thread
DECLARE_CLASS_RETURN(sjc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit", NO);
DECLARE_STATIC_METHOD_RETURN(jm_doEquals, sjc_LWCToolkit, "doEquals",
"(Ljava/lang/Object;Ljava/lang/Object;Ljava/awt/Component;)Z", NO);
return (*env)->CallStaticBooleanMethod(env, sjc_LWCToolkit, jm_doEquals, a, b, component);
CHECK_EXCEPTION();
}
jboolean jb = (*env)->CallBooleanMethod(env, a, jm_equals, b);
CHECK_EXCEPTION();
return jb;
}
/*
* The java/lang/Number concrete class could be for any of the Java primitive
* numerical types or some other subclass.
* All existing A11Y code uses Integer so that is what we look for first
* But all must be able to return a double and NSNumber accepts a double,
* so that's the fall back.
*/
NSNumber* JavaNumberToNSNumber(JNIEnv *env, jobject jnumber) {
if (jnumber == NULL) {
return nil;
}
DECLARE_CLASS_RETURN(jnumber_Class, "java/lang/Number", nil);
DECLARE_CLASS_RETURN(jinteger_Class, "java/lang/Integer", nil);
DECLARE_METHOD_RETURN(jm_intValue, jnumber_Class, "intValue", "()I", nil);
DECLARE_METHOD_RETURN(jm_doubleValue, jnumber_Class, "doubleValue", "()D", nil);
if ((*env)->IsInstanceOf(env, jnumber, jinteger_Class)) {
jint i = (*env)->CallIntMethod(env, jnumber, jm_intValue);
CHECK_EXCEPTION();
return [NSNumber numberWithInteger:i];
} else {
jdouble d = (*env)->CallDoubleMethod(env, jnumber, jm_doubleValue);
CHECK_EXCEPTION();
return [NSNumber numberWithDouble:d];
}
}
/*
* Converts an int array to an NSRange wrapped inside an NSValue
* takes [start, end] values and returns [start, end - start]
*/
NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
jint *values = (*env)->GetIntArrayElements(env, array, 0);
if (values == NULL) {
// Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
NSLog(@"%s failed calling GetIntArrayElements", __FUNCTION__);
return nil;
};
NSValue *value = [NSValue valueWithRange:NSMakeRange(values[0], values[1] - values[0])];
(*env)->ReleaseIntArrayElements(env, array, values, 0);
return value;
}
// end appKit copies
/*
@@ -417,13 +501,13 @@ void initializeRoles()
[sRoles setObject:NSAccessibilitySplitGroupRole forKey:@"splitpane"];
[sRoles setObject:NSAccessibilityValueIndicatorRole forKey:@"statusbar"];
[sRoles setObject:NSAccessibilityGroupRole forKey:@"swingcomponent"];
[sRoles setObject:NSAccessibilityGridRole forKey:@"table"];
[sRoles setObject:NSAccessibilityTableRole forKey:@"table"];
[sRoles setObject:NSAccessibilityTextFieldRole forKey:@"text"];
[sRoles setObject:NSAccessibilityTextAreaRole forKey:@"textarea"]; // supports top/bottom of document notifications: CAccessability.getAccessibleRole()
[sRoles setObject:NSAccessibilityCheckBoxRole forKey:@"togglebutton"];
[sRoles setObject:NSAccessibilityToolbarRole forKey:@"toolbar"];
[sRoles setObject:JavaAccessibilityIgnore forKey:@"tooltip"];
[sRoles setObject:NSAccessibilityBrowserRole forKey:@"tree"];
[sRoles setObject:NSAccessibilityOutlineRole forKey:@"tree"];
[sRoles setObject:NSAccessibilityUnknownRole forKey:@"unknown"];
[sRoles setObject:JavaAccessibilityIgnore forKey:@"viewport"];
[sRoles setObject:JavaAccessibilityIgnore forKey:@"window"];

View File

@@ -29,7 +29,6 @@
// <https://www.ibm.com/able/guidelines/java/snsjavagjfc.html>
#import "JavaComponentAccessibility.h"
#import "a11y/CommonComponentAccessibility.h"
#import "sun_lwawt_macosx_CAccessibility.h"
#import <AppKit/AppKit.h>
@@ -45,6 +44,12 @@
#import "JNIUtilities.h"
#import "AWTView.h"
// 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
// GET* macros defined in JavaAccessibilityUtilities.h, so they can be shared.
static jclass sjc_CAccessibility = NULL;
@@ -82,7 +87,7 @@ static jclass sjc_CAccessible = NULL;
static NSMutableDictionary *sAttributeNamesForRoleCache = nil;
static NSObject *sAttributeNamesLOCK = nil;
@interface TabGroupAccessibility : JavaComponentAccessibility {
@interface TabGroupLegacyAccessibility : JavaComponentAccessibility {
NSInteger _numTabs;
}
@@ -112,7 +117,7 @@ static NSObject *sAttributeNamesLOCK = nil;
- (id)accessibilityValueAttribute;
@end
@interface TableAccessibility : JavaComponentAccessibility {
@interface TableLegacyAccessibility : JavaComponentAccessibility {
}
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
@@ -362,21 +367,18 @@ static NSObject *sAttributeNamesLOCK = nil;
// otherwise, create a new instance
JavaComponentAccessibility *newChild = nil;
newChild = [CommonComponentAccessibility getComponentAccessibility:javaRole];
if (newChild == nil) {
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupAccessibility alloc];
} else if ([javaRole isEqualToString:@"table"]) {
newChild = [TableAccessibility alloc];
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupLegacyAccessibility alloc];
} else if ([javaRole isEqualToString:@"table"]) {
newChild = [TableLegacyAccessibility alloc];
} else {
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] ||
[nsRole isEqualToString:NSAccessibilityTextAreaRole] ||
[nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
} else {
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] ||
[nsRole isEqualToString:NSAccessibilityTextAreaRole] ||
[nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
} else {
newChild = [JavaComponentAccessibility alloc];
}
newChild = [JavaComponentAccessibility alloc];
}
}
@@ -387,7 +389,7 @@ static NSObject *sAttributeNamesLOCK = nil;
// 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"] ) {
![[parent javaRole] isEqualToString:@"combobox"] ) {
[newChild postMenuOpened];
}
@@ -904,32 +906,6 @@ static NSObject *sAttributeNamesLOCK = nil;
return index;
}
/*
* The java/lang/Number concrete class could be for any of the Java primitive
* numerical types or some other subclass.
* All existing A11Y code uses Integer so that is what we look for first
* But all must be able to return a double and NSNumber accepts a double,
* so that's the fall back.
*/
static NSNumber* JavaNumberToNSNumber(JNIEnv *env, jobject jnumber) {
if (jnumber == NULL) {
return nil;
}
DECLARE_CLASS_RETURN(jnumber_Class, "java/lang/Number", nil);
DECLARE_CLASS_RETURN(jinteger_Class, "java/lang/Integer", nil);
DECLARE_METHOD_RETURN(jm_intValue, jnumber_Class, "intValue", "()I", nil);
DECLARE_METHOD_RETURN(jm_doubleValue, jnumber_Class, "doubleValue", "()D", nil);
if ((*env)->IsInstanceOf(env, jnumber, jinteger_Class)) {
jint i = (*env)->CallIntMethod(env, jnumber, jm_intValue);
CHECK_EXCEPTION();
return [NSNumber numberWithInteger:i];
} else {
jdouble d = (*env)->CallDoubleMethod(env, jnumber, jm_doubleValue);
CHECK_EXCEPTION();
return [NSNumber numberWithDouble:d];
}
}
// Element's maximum value (id)
- (id)accessibilityMaxValueAttribute
{
@@ -1600,7 +1576,7 @@ JNI_COCOA_ENTER(env);
JNI_COCOA_EXIT(env);
}
@implementation TabGroupAccessibility
@implementation TabGroupLegacyAccessibility
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
{
@@ -1802,9 +1778,6 @@ JNI_COCOA_EXIT(env);
@end
static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
@implementation TabGroupControlAccessibility
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
@@ -1873,7 +1846,7 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
#define JAVA_AX_ROWS (1)
#define JAVA_AX_COLS (2)
@implementation TableAccessibility
@implementation TableLegacyAccessibility
- (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
{
@@ -1907,30 +1880,3 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
return [self getTableInfo:JAVA_AX_COLS];
}
@end
/*
* Returns Object.equals for the two items
* This may use LWCToolkit.invokeAndWait(); don't call while holding fLock
* and try to pass a component so the event happens on the correct thread.
*/
static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component)
{
DECLARE_CLASS_RETURN(sjc_Object, "java/lang/Object", NO);
DECLARE_METHOD_RETURN(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z", NO);
if ((a == NULL) && (b == NULL)) return YES;
if ((a == NULL) || (b == NULL)) return NO;
if (pthread_main_np() != 0) {
// If we are on the AppKit thread
DECLARE_CLASS_RETURN(sjc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit", NO);
DECLARE_STATIC_METHOD_RETURN(jm_doEquals, sjc_LWCToolkit, "doEquals",
"(Ljava/lang/Object;Ljava/lang/Object;Ljava/awt/Component;)Z", NO);
return (*env)->CallStaticBooleanMethod(env, sjc_LWCToolkit, jm_doEquals, a, b, component);
CHECK_EXCEPTION();
}
jboolean jb = (*env)->CallBooleanMethod(env, a, jm_equals, b);
CHECK_EXCEPTION();
return jb;
}

View File

@@ -53,23 +53,6 @@ static jmethodID sjm_getAccessibleEditableText = NULL;
GET_STATIC_METHOD_RETURN(sjm_getAccessibleEditableText, sjc_CAccessibleText, "getAccessibleEditableText", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleEditableText;", ret);
/*
* Converts an int array to an NSRange wrapped inside an NSValue
* takes [start, end] values and returns [start, end - start]
*/
NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
jint *values = (*env)->GetIntArrayElements(env, array, 0);
if (values == NULL) {
// Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
NSLog(@"%s failed calling GetIntArrayElements", __FUNCTION__);
return nil;
};
NSValue *value = [NSValue valueWithRange:NSMakeRange(values[0], values[1] - values[0])];
(*env)->ReleaseIntArrayElements(env, array, values, 0);
return value;
}
@implementation JavaTextAccessibility
// based strongly upon NSTextViewAccessibility:accessibilityAttributeNames

View File

@@ -36,7 +36,7 @@
- (NSString * _Nullable)accessibilityLabel
{
return [self accessibilityTitleAttribute];
return [super accessibilityLabel];
}
- (BOOL)accessibilityPerformPress
@@ -44,4 +44,14 @@
return [self performAccessibleAction:0];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface CellAccessibility : CommonComponentAccessibility
@end

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CellAccessibility.h"
#import "ThreadUtilities.h"
#import "TableAccessibility.h"
@implementation CellAccessibility
// NSAccessibilityElement protocol methods
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityCellRole;;
}
- (NSArray *)accessibilityChildren
{
NSArray *children = [super accessibilityChildren];
if (children == NULL) {
NSString *javaRole = [self javaRole];
CommonComponentAccessibility *newChild = [CommonComponentAccessibility createWithParent:self
accessible:self->fAccessible
role:javaRole
index:self->fIndex
withEnv:[ThreadUtilities getJNIEnv]
withView:self->fView
isWrapped:NO];
return [NSArray arrayWithObject:newChild];
} else {
return children;
}
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
- (NSRange)accessibilityRowIndexRange {
NSInteger location = -1;
if ([[(CommonComponentAccessibility *)fParent accessibilityParent] isKindOfClass:[TableAccessibility class]]) {
TableAccessibility *table = [(CommonComponentAccessibility *)fParent accessibilityParent];
location = [table accessibleRowAtIndex:fIndex];
}
return NSMakeRange(location, 1);
}
- (NSRange)accessibilityColumnIndexRange {
NSInteger location = -1;
if ([[(CommonComponentAccessibility *)fParent accessibilityParent] isKindOfClass:[TableAccessibility class]]) {
TableAccessibility *table = [(CommonComponentAccessibility *)fParent accessibilityParent];
location = [table accessibleColumnAtIndex:fIndex];
}
return NSMakeRange(location, 1);
}
@end

View File

@@ -39,7 +39,7 @@
- (id _Nonnull) accessibilityValue
{
AWT_ASSERT_APPKIT_THREAD;
return [self accessibilityValueAttribute];
return [super accessibilityValue];
}
@end

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface ColumnAccessibility : CommonComponentAccessibility
@property(readonly) NSUInteger columnNumberInTable;
@end

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "CellAccessibility.h"
#import "ColumnAccessibility.h"
#import "TableAccessibility.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID jm_getChildrenAndRoles = NULL;
#define GET_CHILDRENANDROLES_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles",\
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;", ret);
@implementation ColumnAccessibility
// NSAccessibilityElement protocol methods
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityColumnRole;
}
- (NSArray *)accessibilityChildren
{
NSArray *children = [super accessibilityChildren];
if (children == NULL) {
JNIEnv *env = [ThreadUtilities getJNIEnv];
CommonComponentAccessibility *parent = [self accessibilityParent];
if (parent->fAccessible == NULL) return nil;
GET_CHILDRENANDROLES_METHOD_RETURN(nil);
jobjectArray jchildrenAndRoles = (jobjectArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getChildrenAndRoles,
parent->fAccessible, parent->fComponent, sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN, NO);
CHECK_EXCEPTION();
if (jchildrenAndRoles == NULL) return nil;
jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
NSMutableArray *childrenCells = [NSMutableArray arrayWithCapacity:arrayLen/2];
NSUInteger childIndex = fIndex;
int inc = [(TableAccessibility *)[self accessibilityParent] accessibilityRowCount] * 2;
NSInteger i = childIndex * 2;
for(i; i < arrayLen; i += inc)
{
jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
NSString *childJavaRole = nil;
if (jchildJavaRole != NULL) {
DECLARE_CLASS_RETURN(sjc_AccessibleRole, "javax/accessibility/AccessibleRole", nil);
DECLARE_FIELD_RETURN(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;", nil);
jobject jkey = (*env)->GetObjectField(env, jchildJavaRole, sjf_key);
CHECK_EXCEPTION();
childJavaRole = JavaStringToNSString(env, jkey);
(*env)->DeleteLocalRef(env, jkey);
}
CellAccessibility *child = [[CellAccessibility alloc] initWithParent:self
withEnv:env
withAccessible:jchild
withIndex:childIndex
withView:self->fView
withJavaRole:childJavaRole];
[childrenCells addObject:[[child retain] autorelease]];
(*env)->DeleteLocalRef(env, jchild);
(*env)->DeleteLocalRef(env, jchildJavaRole);
childIndex += (inc / 2);
}
(*env)->DeleteLocalRef(env, jchildrenAndRoles);
return childrenCells;
} else {
return children;
}
}
- (NSInteger)accessibilityIndex
{
return fIndex;
}
@end

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface ComboBoxAccessibility : CommonComponentAccessibility
@end

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "ComboBoxAccessibility.h"
#import "../JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID sjm_getAccessibleName = NULL;
#define GET_ACCESSIBLENAME_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", ret);
@implementation ComboBoxAccessibility
// NSAccessibilityElement protocol methods
- (id)accessibilityValue {
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
if (axContext == NULL) return nil;
jclass axContextClass = (*env)->GetObjectClass(env, axContext);
DECLARE_METHOD_RETURN(jm_getAccessibleSelection, axContextClass, "getAccessibleSelection", "(I)Ljavax/accessibility/Accessible;", nil);
jobject axSelectedChild = (*env)->CallObjectMethod(env, axContext, jm_getAccessibleSelection, 0);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, axContext);
if (axSelectedChild == NULL) {
return nil;
}
GET_CACCESSIBILITY_CLASS_RETURN(nil);
GET_ACCESSIBLENAME_METHOD_RETURN(nil);
jobject childName = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleName, axSelectedChild, fComponent);
CHECK_EXCEPTION();
if (childName == NULL) {
(*env)->DeleteLocalRef(env, axSelectedChild);
return nil;
}
NSString *selectedText = JavaStringToNSString(env, childName);
(*env)->DeleteLocalRef(env, axSelectedChild);
(*env)->DeleteLocalRef(env, childName);
return selectedText;
}
@end

View File

@@ -26,23 +26,83 @@
#ifndef JAVA_COMPONENT_ACCESSIBILITY
#define JAVA_COMPONENT_ACCESSIBILITY
#import "JavaComponentAccessibility.h"
#include "jni.h"
#import <AppKit/AppKit.h>
#import "JavaAccessibilityUtilities.h"
// 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
@interface CommonComponentAccessibility : NSAccessibilityElement {
NSView *fView;
NSObject *fParent;
@interface CommonComponentAccessibility : JavaComponentAccessibility <NSAccessibilityElement> {
NSString *fNSRole;
NSString *fJavaRole;
jint fIndex;
jobject fAccessible;
jobject fComponent;
NSMutableDictionary *fActions;
NSMutableArray *fActionSelectors;
NSObject *fActionsLOCK;
}
@property(nonnull, readonly) NSArray *actionSelectors;
- (id _Nonnull)initWithParent:(NSObject* _Nonnull)parent withEnv:(JNIEnv _Nonnull * _Nonnull)env withAccessible:(jobject _Nullable)accessible withIndex:(jint)index withView:(NSView* _Nonnull)view withJavaRole:(NSString* _Nullable)javaRole;
- (void)unregisterFromCocoaAXSystem;
- (void)postValueChanged;
- (void)postSelectedTextChanged;
- (void)postSelectionChanged;
- (void)postTitleChanged;
- (void)postTreeNodeExpanded;
- (void)postTreeNodeCollapsed;
- (BOOL)isEqual:(nonnull id)anObject;
- (BOOL)isAccessibleWithEnv:(JNIEnv _Nonnull * _Nonnull)env forAccessible:(nonnull jobject)accessible;
+ (void)postFocusChanged:(nullable id)message;
+ (void) initializeRolesMap;
+ (JavaComponentAccessibility * _Nullable) getComponentAccessibility:(NSString * _Nonnull)role;
+ (CommonComponentAccessibility* _Nullable) getComponentAccessibility:(NSString* _Nonnull)role;
+ (CommonComponentAccessibility * _Nullable) getComponentAccessibility:(NSString * _Nonnull)role andParent:(CommonComponentAccessibility * _Nonnull)parent;
+ (NSArray* _Nullable)childrenOfParent:(CommonComponentAccessibility* _Nonnull)parent withEnv:(JNIEnv _Nonnull * _Nonnull)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored;
+ (NSArray* _Nullable)childrenOfParent:(CommonComponentAccessibility* _Nonnull)parent withEnv:(JNIEnv _Nonnull * _Nonnull)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored recursive:(BOOL)recursive;
+ (CommonComponentAccessibility* _Nullable) createWithParent:(CommonComponentAccessibility* _Nullable)parent accessible:(jobject _Nonnull)jaccessible role:(NSString* _Nonnull)javaRole index:(jint)index withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view;
+ (CommonComponentAccessibility* _Nullable) createWithAccessible:(jobject _Nonnull)jaccessible role:(NSString* _Nonnull)role index:(jint)index withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view;
+ (CommonComponentAccessibility* _Nullable) createWithAccessible:(jobject _Nonnull)jaccessible withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view;
// If the isWraped parameter is true, then the object passed as a parent was created based on the same java component,
// but performs a different NSAccessibilityRole of a table cell, or a list row, or tree row,
// and we need to create an element whose role corresponds to the role in Java.
+ (CommonComponentAccessibility* _Nullable) createWithParent:(CommonComponentAccessibility* _Nullable)parent accessible:(jobject _Nonnull)jaccessible role:(NSString* _Nonnull)javaRole index:(jint)index withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view isWrapped:(BOOL)wrapped;
// The current parameter is used to bypass the check for an item's index on the parent so that the item is created. This is necessary,
// for example, for AccessibleJTreeNode, whose currentComponent has index -1
+ (CommonComponentAccessibility* _Nullable) createWithAccessible:(jobject _Nonnull)jaccessible withEnv:(JNIEnv _Nonnull * _Nonnull)env withView:(NSView* _Nonnull)view isCurrent:(BOOL)current;
- (jobject _Nullable)axContextWithEnv:(JNIEnv _Nonnull * _Nonnull)env;
- (NSView* _Nonnull)view;
- (NSWindow* _Nonnull)window;
- (id _Nonnull)parent;
- (NSString* _Nonnull)javaRole;
- (BOOL)isMenu;
- (BOOL)isSelected:(JNIEnv _Nonnull * _Nonnull)env;
- (BOOL)isSelectable:(JNIEnv _Nonnull * _Nonnull)env;
- (BOOL)isVisible:(JNIEnv _Nonnull * _Nonnull)env;
- (NSArray* _Nullable)accessibleChildrenWithChildCode:(NSInteger)childCode;
- (NSDictionary* _Nullable)getActions:(JNIEnv _Nonnull * _Nonnull)env;
- (void)getActionsWithEnv:(JNIEnv _Nonnull * _Nonnull)env;
- (BOOL)accessiblePerformAction:(NSAccessibilityActionName _Nonnull)actionName;
- (BOOL)performAccessibleAction:(int)index;
- (NSRect)accessibilityFrame;
- (id _Nullable)accessibilityParent;
- (BOOL)performAccessibleAction:(int)index;
- (BOOL)isAccessibilityElement;
@end

View File

@@ -70,7 +70,7 @@ static NSRange javaIntArrayToNSRange(JNIEnv* env, jintArray array) {
GET_CACCESSIBILITY_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil);
if ([[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityStaticTextRole]) {
if ([[self accessibilityRole] isEqualToString:NSAccessibilityStaticTextRole]) {
jobject axName = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
sjm_getAccessibleName, fAccessible, fComponent);
CHECK_EXCEPTION();

View File

@@ -26,6 +26,7 @@
#import "GroupAccessibility.h"
#import "JNIUtilities.h"
#import "ThreadUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
/*
* This is the protocol for the components that contain children.
* Basic logic of accessibilityChildren might be overridden in the specific implementing
@@ -43,9 +44,9 @@
- (NSArray *)accessibilityChildren {
JNIEnv *env = [ThreadUtilities getJNIEnv];
NSArray *children = [JavaComponentAccessibility childrenOfParent:self
NSArray *children = [CommonComponentAccessibility childrenOfParent:self
withEnv:env
withChildrenCode:JAVA_AX_ALL_CHILDREN
withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN
allowIgnored:NO];
if ([children count] == 0) {
@@ -55,4 +56,14 @@
}
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

View File

@@ -36,7 +36,17 @@
- (NSString * _Nullable)accessibilityLabel
{
return [self accessibilityTitleAttribute];
return [super accessibilityLabel];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface ListAccessibility : CommonComponentAccessibility <NSAccessibilityList>
@end

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "ListAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
@implementation ListAccessibility
// NSAccessibilityElement protocol methods
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilityRows
{
return [self accessibilityChildren];
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedRows
{
return [self accessibilitySelectedChildren];
}
- (NSString *)accessibilityLabel
{
return [super accessibilityLabel] == NULL ? @"list" : [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

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface ListRowAccessibility : CommonComponentAccessibility <NSAccessibilityRow>
@end

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#import "ListRowAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "ListAccessibility.h"
#import "ThreadUtilities.h"
@implementation ListRowAccessibility
// NSAccessibilityElement protocol methods
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityRowRole;
}
- (NSArray *)accessibilityChildren
{
NSArray *children = [super accessibilityChildren];
if (children == NULL) {
// Since the row element has already been created, we should no create it again, but just retrieve it by a pointer, that's why isWrapped is set to YES.
CommonComponentAccessibility *newChild = [CommonComponentAccessibility createWithParent:self
accessible:self->fAccessible
role:self->fJavaRole
index:self->fIndex
withEnv:[ThreadUtilities getJNIEnv]
withView:self->fView
isWrapped:YES];
return [NSArray arrayWithObject:newChild];
} else {
return children;
}
}
- (NSInteger)accessibilityIndex
{
return [[self accessibilityParent] accessibilityIndexOfChild:self];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
@end

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface NavigableTextAccessibility : CommonComponentAccessibility <NSAccessibilityNavigableStaticText>
@property(readonly) BOOL accessibleIsPasswordText;
@end

View File

@@ -0,0 +1,316 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "NavigableTextAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
static jclass sjc_CAccessibility = NULL;
#define GET_CACCESSIBLITY_CLASS() \
GET_CLASS(sjc_CAccessibility, "sun/lwawt/macosx/CAccessibility");
#define GET_CACCESSIBLITY_CLASS_RETURN(ret) \
GET_CLASS_RETURN(sjc_CAccessibility, "sun/lwawt/macosx/CAccessibility", ret);
static jmethodID sjm_getAccessibleText = NULL;
#define GET_ACCESSIBLETEXT_METHOD_RETURN(ret) \
GET_CACCESSIBLITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleText, sjc_CAccessibility, "getAccessibleText", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleText;", ret);
static jclass sjc_CAccessibleText = NULL;
#define GET_CACCESSIBLETEXT_CLASS() \
GET_CLASS(sjc_CAccessibleText, "sun/lwawt/macosx/CAccessibleText");
#define GET_CACCESSIBLETEXT_CLASS_RETURN(ret) \
GET_CLASS_RETURN(sjc_CAccessibleText, "sun/lwawt/macosx/CAccessibleText", ret);
static jmethodID sjm_getAccessibleEditableText = NULL;
#define GET_ACCESSIBLEEDITABLETEXT_METHOD_RETURN(ret) \
GET_CACCESSIBLETEXT_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleEditableText, sjc_CAccessibleText, "getAccessibleEditableText", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleEditableText;", ret);
@implementation NavigableTextAccessibility
- (BOOL)accessibleIsPasswordText {
return [fJavaRole isEqualToString:@"passwordtext"];
}
// NSAccessibilityElement protocol methods
- (NSRect)accessibilityFrameForRange:(NSRange)range
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSMakeRect(0, 0, 0, 0));
DECLARE_STATIC_METHOD_RETURN(jm_getBoundsForRange, sjc_CAccessibleText, "getBoundsForRange",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)[D", NSMakeRect(0, 0, 0, 0));
jdoubleArray axBounds = (jdoubleArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getBoundsForRange,
fAccessible, fComponent, range.location, range.length);
CHECK_EXCEPTION();
if (axBounds == NULL) return NSMakeRect(0, 0, 0, 0);
// We cheat because we know that the array is 4 elements long (x, y, width, height)
jdouble *values = (*env)->GetDoubleArrayElements(env, axBounds, 0);
CHECK_EXCEPTION();
NSRect bounds;
bounds.origin.x = values[0];
bounds.origin.y = [[[[self view] window] screen] frame].size.height - values[1] - values[3]; //values[1] is y-coord from top-left of screen. Flip. Account for the height (values[3]) when flipping
bounds.size.width = values[2];
bounds.size.height = values[3];
(*env)->ReleaseDoubleArrayElements(env, axBounds, values, 0);
return bounds;
}
- (NSInteger)accessibilityLineForIndex:(NSInteger)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(-1);
DECLARE_STATIC_METHOD_RETURN(jm_getLineNumberForIndex, sjc_CAccessibleText, "getLineNumberForIndex",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)I", -1);
jint row = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText, jm_getLineNumberForIndex,
fAccessible, fComponent, index);
CHECK_EXCEPTION();
if (row < 0) return -1;
return row;
}
- (NSRange)accessibilityRangeForLine:(NSInteger)line
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSRangeFromString(@""));
DECLARE_STATIC_METHOD_RETURN(jm_getRangeForLine, sjc_CAccessibleText, "getRangeForLine",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I", NSRangeFromString(@""));
jintArray axTextRange = (jintArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText,
jm_getRangeForLine, fAccessible, fComponent, line);
CHECK_EXCEPTION();
if (axTextRange == NULL) return NSRangeFromString(@"");
NSRange range = [javaIntArrayToNSRangeValue(env,axTextRange) rangeValue];
(*env)->DeleteLocalRef(env, axTextRange);
return range;
}
- (NSString *)accessibilityStringForRange:(NSRange)range
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(jm_getStringForRange, sjc_CAccessibleText, "getStringForRange",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)Ljava/lang/String;", nil);
jstring jstringForRange = (jstring)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getStringForRange,
fAccessible, fComponent, range.location, range.length);
CHECK_EXCEPTION();
if (jstringForRange == NULL) return @"";
NSString* str = JavaStringToNSString(env, jstringForRange);
(*env)->DeleteLocalRef(env, jstringForRange);
return str;
}
- (id)accessibilityValue
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLITY_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil);
// cmcnote: inefficient to make three distinct JNI calls. Coalesce. radr://3951923
GET_ACCESSIBLETEXT_METHOD_RETURN(@"");
jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
sjm_getAccessibleText, fAccessible, fComponent);
CHECK_EXCEPTION();
if (axText == NULL) return nil;
(*env)->DeleteLocalRef(env, axText);
GET_ACCESSIBLEEDITABLETEXT_METHOD_RETURN(nil);
jobject axEditableText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText,
sjm_getAccessibleEditableText, fAccessible, fComponent);
CHECK_EXCEPTION();
if (axEditableText == NULL) return nil;
DECLARE_STATIC_METHOD_RETURN(jm_getTextRange, sjc_CAccessibleText, "getTextRange",
"(Ljavax/accessibility/AccessibleEditableText;IILjava/awt/Component;)Ljava/lang/String;", nil);
jobject jrange = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getTextRange,
axEditableText, 0, getAxTextCharCount(env, axEditableText, fComponent), fComponent);
CHECK_EXCEPTION();
NSString *string = JavaStringToNSString(env, jrange);
(*env)->DeleteLocalRef(env, jrange);
(*env)->DeleteLocalRef(env, axEditableText);
if (string == nil) string = @"";
return string;
}
- (NSAccessibilitySubrole)accessibilitySubrole {
if ([self accessibleIsPasswordText]) {
return NSAccessibilitySecureTextFieldSubrole;
}
return nil;
}
- (NSRange)accessibilityRangeForIndex:(NSInteger)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSRangeFromString(@""));
DECLARE_STATIC_METHOD_RETURN(jm_getRangeForIndex, sjc_CAccessibleText, "getRangeForIndex",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I", NSRangeFromString(@""));
jintArray axTextRange = (jintArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getRangeForIndex,
fAccessible, fComponent, index);
CHECK_EXCEPTION();
if (axTextRange == NULL) return NSRangeFromString(@"");
return [javaIntArrayToNSRangeValue(env, axTextRange) rangeValue];
}
- (NSAccessibilityRole)accessibilityRole {
return [sRoles objectForKey:self.javaRole];
}
- (NSRange)accessibilityRangeForPosition:(NSPoint)point
{
point.y = [[[[self view] window] screen] frame].size.height - point.y; // flip into java screen coords (0 is at upper-left corner of screen)
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSRangeFromString(@""));
DECLARE_STATIC_METHOD_RETURN(jm_getCharacterIndexAtPosition, sjc_CAccessibleText, "getCharacterIndexAtPosition",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)I", NSRangeFromString(@""));
jint charIndex = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText, jm_getCharacterIndexAtPosition,
fAccessible, fComponent, point.x, point.y);
CHECK_EXCEPTION();
if (charIndex == -1) return NSRangeFromString(@"");
// AccessibleText.getIndexAtPoint returns -1 for an invalid point
NSRange range = NSMakeRange(charIndex, 1); //range's length is 1 - one-character range
return range;
}
- (NSString *)accessibilitySelectedText
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(jm_getSelectedText, sjc_CAccessibleText, "getSelectedText",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil);
jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getSelectedText,
fAccessible, fComponent);
CHECK_EXCEPTION();
if (axText == NULL) return @"";
NSString* str = JavaStringToNSString(env, axText);
(*env)->DeleteLocalRef(env, axText);
return str;
}
- (NSRange)accessibilitySelectedTextRange
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(NSRangeFromString(@""));
DECLARE_STATIC_METHOD_RETURN(jm_getSelectedTextRange, sjc_CAccessibleText, "getSelectedTextRange",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[I", NSRangeFromString(@""));
jintArray axTextRange = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText,
jm_getSelectedTextRange, fAccessible, fComponent);
CHECK_EXCEPTION();
if (axTextRange == NULL) return NSRangeFromString(@"");
return [javaIntArrayToNSRangeValue(env, axTextRange) rangeValue];
}
- (NSInteger)accessibilityNumberOfCharacters
{
// cmcnote: should coalesce these two calls - radr://3951923
// also, static text doesn't always have accessibleText. if axText is null, should get the charcount of the accessibleName instead
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_ACCESSIBLETEXT_METHOD_RETURN(0);
jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
sjm_getAccessibleText, fAccessible, fComponent);
CHECK_EXCEPTION();
NSInteger num = getAxTextCharCount(env, axText, fComponent);
(*env)->DeleteLocalRef(env, axText);
return num;
}
- (NSInteger)accessibilityInsertionPointLineNumber
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS_RETURN(0);
DECLARE_STATIC_METHOD_RETURN(jm_getLineNumberForInsertionPoint, sjc_CAccessibleText,
"getLineNumberForInsertionPoint", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I", 0);
jint row = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText,
jm_getLineNumberForInsertionPoint, fAccessible, fComponent);
CHECK_EXCEPTION();
return row >= 0 ? row : 0;
}
- (void)setAccessibilitySelectedText:(NSString *)accessibilitySelectedText
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jstring jstringValue = NSStringToJavaString(env, accessibilitySelectedText);
GET_CACCESSIBLETEXT_CLASS();
DECLARE_STATIC_METHOD(jm_setSelectedText, sjc_CAccessibleText, "setSelectedText",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;Ljava/lang/String;)V");
(*env)->CallStaticVoidMethod(env, sjc_CAccessibleText, jm_setSelectedText,
fAccessible, fComponent, jstringValue);
CHECK_EXCEPTION();
}
- (void)setAccessibilitySelectedTextRange:(NSRange)accessibilitySelectedTextRange
{
jint startIndex = accessibilitySelectedTextRange.location;
jint endIndex = startIndex + accessibilitySelectedTextRange.length;
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBLETEXT_CLASS();
DECLARE_STATIC_METHOD(jm_setSelectedTextRange, sjc_CAccessibleText, "setSelectedTextRange",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)V");
(*env)->CallStaticVoidMethod(env, sjc_CAccessibleText, jm_setSelectedTextRange,
fAccessible, fComponent, startIndex, endIndex);
CHECK_EXCEPTION();
}
- (BOOL)isAccessibilityEdited {
return YES;
}
- (BOOL)isAccessibilityEnabled {
return YES;
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
/*
* Other text methods
- (NSRange)accessibilitySharedCharacterRange;
- (NSArray *)accessibilitySharedTextUIElements;
- (NSData *)accessibilityRTFForRange:(NSRange)range;
- (NSRange)accessibilityStyleRangeForIndex:(NSInteger)index;
*/
@end

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "ListAccessibility.h"
// This is a tree representation. See: https://developer.apple.com/documentation/appkit/nsoutlineview
@interface OutlineAccessibility : ListAccessibility <NSAccessibilityOutline>
@property(readonly) BOOL isTreeRootVisible;
@end

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "OutlineAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID sjm_isTreeRootVisible = NULL;
#define GET_ISTREEROOTVISIBLE_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_isTreeRootVisible, sjc_CAccessibility, "isTreeRootVisible", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z", ret);
@implementation OutlineAccessibility
- (BOOL)isTreeRootVisible
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
GET_ISTREEROOTVISIBLE_METHOD_RETURN(NO);
bool isTreeRootVisible = (*env)->CallStaticBooleanMethod(env, sjc_CAccessibility, sjm_isTreeRootVisible, fAccessible, fComponent);
CHECK_EXCEPTION();
return isTreeRootVisible;
}
// NSAccessibilityElement protocol methods
- (NSString *)accessibilityLabel
{
return [[super accessibilityLabel] isEqualToString:@"list"] ? @"tree" : [super accessibilityLabel];
}
@end

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "ListRowAccessibility.h"
@interface OutlineRowAccessibility : ListRowAccessibility
@property(readwrite) int accessibleLevel;
- (jobject)currentAccessibleWithENV:(JNIEnv *)env;
@end

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#import "OutlineRowAccessibility.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "OutlineAccessibility.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessible = NULL;
#define GET_CACCESSIBLE_CLASS_RETURN(ret) \
GET_CLASS_RETURN(sjc_CAccessible, "sun/lwawt/macosx/CAccessible", ret);
@implementation OutlineRowAccessibility
@synthesize accessibleLevel;
- (jobject)currentAccessibleWithENV:(JNIEnv *)env
{
jobject jAxContext = getAxContext(env, fAccessible, fComponent);
if (jAxContext == NULL) return NULL;
jclass axContextClass = (*env)->GetObjectClass(env, jAxContext);
DECLARE_METHOD_RETURN(jm_getCurrentComponent, axContextClass, "getCurrentComponent", "()Ljava/awt/Component;", NULL);
jobject newComponent = (*env)->CallObjectMethod(env, jAxContext, jm_getCurrentComponent);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, jAxContext);
if (newComponent != NULL) {
GET_CACCESSIBLE_CLASS_RETURN(NULL);
DECLARE_STATIC_METHOD_RETURN(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;", NULL);
jobject currentAccessible = (*env)->CallStaticObjectMethod(env, sjc_CAccessible, sjm_getCAccessible, newComponent);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, newComponent);
return currentAccessible;
} else {
return NULL;
}
}
// NSAccessibilityElement protocol methods
- (NSArray *)accessibilityChildren
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject currentAccessible = [self currentAccessibleWithENV:env];
if (currentAccessible != NULL) {
CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:currentAccessible withEnv:env withView:self->fView isCurrent:YES];
NSArray *children = [CommonComponentAccessibility childrenOfParent:currentElement withEnv:env withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:YES];
if ([children count] != 0) {
return children;
}
}
return [NSArray arrayWithObject:[CommonComponentAccessibility createWithParent:self
accessible:self->fAccessible
role:self->fJavaRole
index:self->fIndex
withEnv:env
withView:self->fView
isWrapped:YES]];
}
- (NSInteger)accessibilityDisclosureLevel
{
int level = [self accessibleLevel];
return [(OutlineAccessibility *)[self accessibilityParent] isTreeRootVisible] ? level - 1 : level;
}
- (BOOL)isAccessibilityDisclosed
{
return isExpanded([ThreadUtilities getJNIEnv], [self axContextWithEnv:[ThreadUtilities getJNIEnv]], self->fComponent);
}
- (NSAccessibilitySubrole)accessibilitySubrole
{
return NSAccessibilityOutlineRowSubrole;;
}
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityRowRole;;
}
- (BOOL)isAccessibilitySelected
{
return YES;
}
@end

View File

@@ -39,7 +39,7 @@
- (id _Nonnull) accessibilityValue
{
AWT_ASSERT_APPKIT_THREAD;
return [self accessibilityValueAttribute];
return [super accessibilityValue];
}
@end

View File

@@ -26,6 +26,7 @@
#import "ScrollAreaAccessibility.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
/*
* Implementation of the accessibility peer for the ScrollArea role
@@ -35,16 +36,16 @@
- (NSArray * _Nullable)accessibilityContentsAttribute
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
NSArray *children = [CommonComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:YES];
if ([children count] <= 0) return nil;
NSArray *contents = [NSMutableArray arrayWithCapacity:[children count]];
// 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]) {
CommonComponentAccessibility *aElement;
while ((aElement = (CommonComponentAccessibility *)[enumerator nextObject])) {
if (![[aElement accessibilityRole] isEqualToString:NSAccessibilityScrollBarRole]) {
// no scroll bars in contents
[(NSMutableArray *)contents addObject:aElement];
}
@@ -56,14 +57,14 @@
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
NSArray *children = [CommonComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:YES];
if ([children count] <= 0) return nil;
// The scroll bars are in the children.
JavaComponentAccessibility *aElement;
CommonComponentAccessibility *aElement;
NSEnumerator *enumerator = [children objectEnumerator];
while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
while ((aElement = (CommonComponentAccessibility *)[enumerator nextObject])) {
if ([[aElement accessibilityRole] isEqualToString:NSAccessibilityScrollBarRole]) {
jobject elementAxContext = [aElement axContextWithEnv:env];
if (orientation == NSAccessibilityOrientationHorizontal) {
if (isHorizontal(env, elementAxContext, fComponent)) {

View File

@@ -39,12 +39,12 @@
- (NSString * _Nullable)accessibilityLabel
{
return [self accessibilityTitleAttribute];
return [super accessibilityLabel];
}
- (id _Nullable)accessibilityValue
{
return [self accessibilityValueAttribute];
return [super accessibilityValue];
}
- (BOOL)accessibilityPerformIncrement
@@ -57,4 +57,14 @@
return [self performAccessibleAction:DECREMENT];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

View File

@@ -39,12 +39,12 @@
- (NSString * _Nullable)accessibilityLabel
{
return [self accessibilityTitleAttribute];
return [super accessibilityLabel];
}
- (id _Nullable)accessibilityValue
{
return [self accessibilityValueAttribute];
return [super accessibilityValue];
}
- (BOOL)accessibilityPerformIncrement
@@ -58,4 +58,14 @@
return [self performAccessibleAction:DECREMENT];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

View File

@@ -47,4 +47,14 @@
return [self accessibilityVisibleCharacterRangeAttribute];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
@end

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface TabButtonAccessibility : CommonComponentAccessibility {
jobject fTabGroupAxContext;
}
@property(readonly) jobject tabGroup;
// from TabGroup controller
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole;
- (void)performPressAction;
@end

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "TabButtonAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
@implementation TabButtonAccessibility
- (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
{
self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
if (self) {
if (tabGroup != NULL) {
fTabGroupAxContext = (*env)->NewWeakGlobalRef(env, tabGroup);
CHECK_EXCEPTION();
} else {
fTabGroupAxContext = NULL;
}
}
return self;
}
- (void)dealloc
{
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
if (fTabGroupAxContext != NULL) {
(*env)->DeleteWeakGlobalRef(env, fTabGroupAxContext);
fTabGroupAxContext = NULL;
}
[super dealloc];
}
- (jobject)tabGroup
{
if (fTabGroupAxContext == NULL) {
JNIEnv* env = [ThreadUtilities getJNIEnv];
jobject tabGroupAxContext = [(CommonComponentAccessibility *)[self parent] axContextWithEnv:env];
fTabGroupAxContext = (*env)->NewWeakGlobalRef(env, tabGroupAxContext);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, tabGroupAxContext);
}
return fTabGroupAxContext;
}
- (void)performPressAction {
JNIEnv *env = [ThreadUtilities getJNIEnv];
TabGroupAction *action = [[TabGroupAction alloc] initWithEnv:env withTabGroup:[self tabGroup] withIndex:fIndex withComponent:fComponent];
[action perform];
[action release];
}
// NSAccessibilityElement protocol methods
- (NSAccessibilitySubrole)accessibilitySubrole
{
if (@available(macOS 10.13, *)) {
return NSAccessibilityTabButtonSubrole;
}
return NSAccessibilityUnknownSubrole;
}
- (id)accessibilityValue
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
jobject selAccessible = getAxContextSelection(env, [self tabGroup], fIndex, fComponent);
// Returns the current selection of the page tab list
id val = [NSNumber numberWithBool:ObjectEquals(env, axContext, selAccessible, fComponent)];
(*env)->DeleteLocalRef(env, selAccessible);
(*env)->DeleteLocalRef(env, axContext);
return val;
}
- (BOOL)accessibilityPerformPress {
[self performPressAction];
return YES;
}
@end

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface TabGroupAccessibility : CommonComponentAccessibility {
NSInteger _numTabs;
}
@property(readonly) NSInteger numTabs;
- (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
- (NSArray *)tabButtonsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
- (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
@end

View File

@@ -0,0 +1,204 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "TabGroupAccessibility.h"
#import "TabButtonAccessibility.h"
#import "../JavaAccessibilityUtilities.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID jm_getChildrenAndRoles = NULL;
#define GET_CHILDRENANDROLES_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles",\
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;", ret);
@implementation TabGroupAccessibility
- (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext
{
NSArray *tabs = [self tabButtonsWithEnv:env withTabGroupAxContext:axContext withTabCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:NO];
// Looking at the JTabbedPane sources, there is always one AccessibleSelection.
jobject selAccessible = getAxContextSelection(env, axContext, 0, fComponent);
if (selAccessible == NULL) return nil;
// Go through the tabs and find selAccessible
_numTabs = [tabs count];
CommonComponentAccessibility *aTab;
NSInteger i;
for (i = 0; i < _numTabs; i++) {
aTab = (CommonComponentAccessibility *)[tabs objectAtIndex:i];
if ([aTab isAccessibleWithEnv:env forAccessible:selAccessible]) {
(*env)->DeleteLocalRef(env, selAccessible);
return aTab;
}
}
(*env)->DeleteLocalRef(env, selAccessible);
return nil;
}
- (NSArray *)tabButtonsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
{
GET_CHILDRENANDROLES_METHOD_RETURN(nil);
jobjectArray jtabsAndRoles = (jobjectArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getChildrenAndRoles,
fAccessible, fComponent, whichTabs, allowIgnored);
CHECK_EXCEPTION();
if(jtabsAndRoles == NULL) return nil;
jsize arrayLen = (*env)->GetArrayLength(env, jtabsAndRoles);
if (arrayLen == 0) {
(*env)->DeleteLocalRef(env, jtabsAndRoles);
return nil;
}
NSMutableArray *tabs = [NSMutableArray arrayWithCapacity:(arrayLen/2)];
// 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
jobject jtabJavaRole = (*env)->GetObjectArrayElement(env, jtabsAndRoles, 1); // the array entries alternate between tab/role, starting with tab. so the first role is entry 1.
if (jtabJavaRole == NULL) {
(*env)->DeleteLocalRef(env, jtabsAndRoles);
return nil;
}
DECLARE_CLASS_RETURN(sjc_AccessibleRole, "javax/accessibility/AccessibleRole", nil);
DECLARE_FIELD_RETURN(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;", nil);
jobject jkey = (*env)->GetObjectField(env, jtabJavaRole, sjf_key);
CHECK_EXCEPTION();
NSString *tabJavaRole = JavaStringToNSString(env, jkey);
(*env)->DeleteLocalRef(env, jkey);
NSInteger i;
NSUInteger tabIndex = (whichTabs >= 0) ? whichTabs : 0; // if we're getting one particular child, make sure to set its index correctly
for(i = 0; i < arrayLen; i+=2) {
jobject jtab = (*env)->GetObjectArrayElement(env, jtabsAndRoles, i);
CommonComponentAccessibility *tab = [[[TabButtonAccessibility alloc] initWithParent:self withEnv:env withAccessible:jtab withIndex:tabIndex withTabGroup:axContext withView:[self view] withJavaRole:tabJavaRole] autorelease];
(*env)->DeleteLocalRef(env, jtab);
[tabs addObject:tab];
tabIndex++;
}
(*env)->DeleteLocalRef(env, jtabsAndRoles);
return tabs;
}
- (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
{
// Contents are the children of the selected tab.
id currentTab = [self currentTabWithEnv:env withAxContext:axContext];
if (currentTab == nil) return nil;
NSArray *contents = [CommonComponentAccessibility childrenOfParent:currentTab withEnv:env withChildrenCode:whichTabs allowIgnored:allowIgnored];
if ([contents count] <= 0) return nil;
return contents;
}
- (NSInteger)numTabs
{
if (_numTabs == -1) {
_numTabs = [[self accessibilityTabsAttribute] count];
}
return _numTabs;
}
// NSAccessibilityElement protocol methods
- (NSArray *)accessibilityTabs
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
id tabs = [self tabButtonsWithEnv:env withTabGroupAxContext:axContext withTabCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:NO];
(*env)->DeleteLocalRef(env, axContext);
return tabs;
}
- (NSArray *)accessibilityContents
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
NSArray* cont = [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN allowIgnored:NO];
(*env)->DeleteLocalRef(env, axContext);
return cont;
}
- (id)accessibilityValue
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
id val = [self currentTabWithEnv:env withAxContext:axContext];
(*env)->DeleteLocalRef(env, axContext);
return val;
}
- (NSArray *)accessibilityChildren
{
//children = AXTabs + AXContents
NSArray *tabs = [self accessibilityTabs];
NSArray *contents = [self accessibilityContents];
NSMutableArray *children = [NSMutableArray arrayWithCapacity:[tabs count] + [contents count]];
[children addObjectsFromArray:tabs];
[children addObjectsFromArray:contents];
return (NSArray *)children;
}
- (NSArray *)accessibilityArrayAttributeValues:(NSAccessibilityAttributeName)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
{
NSArray *result = nil;
if ( (maxCount == 1) && [attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
// Children codes for ALL, SELECTED, VISIBLE are <0. If the code is >=0, we treat it as an index to a single child
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
//children = AXTabs + AXContents
NSArray *children = [self tabButtonsWithEnv:env withTabGroupAxContext:axContext withTabCode:index allowIgnored:NO]; // first look at the tabs
if ([children count] > 0) {
result = children;
} else {
children= [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:(index-[self numTabs]) allowIgnored:NO];
if ([children count] > 0) {
result = children;
}
}
(*env)->DeleteLocalRef(env, axContext);
} else {
result = [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
}
return result;
}
- (void)setAccessibilityValue:(id)accessibilityValue
{
// set the current tab
NSNumber *number = (NSNumber *)accessibilityValue;
if (![number boolValue]) return;
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
setAxContextSelection(env, axContext, fIndex, fComponent);
(*env)->DeleteLocalRef(env, axContext);
}
@end

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface TableAccessibility : CommonComponentAccessibility <NSAccessibilityTable>
- (BOOL)isAccessibleChildSelectedFromIndex:(int)index;
- (int) accessibleRowAtIndex:(int)index;
- (int) accessibleColumnAtIndex:(int)index;
@end

View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni.h"
#import "TableRowAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "TableAccessibility.h"
#import "CellAccessibility.h"
#import "ColumnAccessibility.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "CellAccessibility.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID sjm_getAccessibleName = NULL;
#define GET_ACCESSIBLENAME_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", ret);
@implementation TableAccessibility
- (id)getTableInfo:(jint)info
{
if (fAccessible == NULL) return 0;
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBILITY_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(jm_getTableInfo, sjc_CAccessibility, "getTableInfo",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)I", nil);
jint count = (*env)->CallStaticIntMethod(env, sjc_CAccessibility, jm_getTableInfo, fAccessible,
fComponent, info);
CHECK_EXCEPTION();
NSNumber *index = [NSNumber numberWithInt:count];
return index;
}
- (NSArray<NSNumber *> *)getTableSelectedInfo:(jint)info
{
if (fAccessible == NULL) return 0;
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_CACCESSIBILITY_CLASS_RETURN(nil);
DECLARE_STATIC_METHOD_RETURN(jm_getTableSelectedInfo, sjc_CAccessibility, "getTableSelectedInfo",
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I", nil);
jintArray selected = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getTableSelectedInfo, fAccessible,
fComponent, info);
CHECK_EXCEPTION();
if (selected == NULL) {
return nil;
}
jsize arrayLen = (*env)->GetArrayLength(env, selected);
jint *indexsis = (*env)->GetIntArrayElements(env, selected, 0);
NSMutableArray<NSNumber *> *nsArraySelected = [NSMutableArray<NSNumber *> arrayWithCapacity:arrayLen];
for (int i = 0; i < arrayLen; i++) {
[nsArraySelected addObject:[NSNumber numberWithInt:indexsis[i]]];
}
(*env)->DeleteLocalRef(env, selected);
return [NSArray<NSNumber *> arrayWithArray:nsArraySelected];
}
- (int)accessibleRowAtIndex:(int)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
if (axContext == NULL) return 0;
jclass clsInfo = (*env)->GetObjectClass(env, axContext);
DECLARE_METHOD_RETURN(jm_getAccessibleRowAtIndex, clsInfo, "getAccessibleRowAtIndex", "(I)I", -1);
jint rowAtIndex = (*env)->CallIntMethod(env, axContext, jm_getAccessibleRowAtIndex, (jint)index);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, axContext);
return (int)rowAtIndex;
}
- (int)accessibleColumnAtIndex:(int)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
if (axContext == NULL) return 0;
jclass clsInfo = (*env)->GetObjectClass(env, axContext);
DECLARE_METHOD_RETURN(jm_getAccessibleColumnAtIndex, clsInfo, "getAccessibleColumnAtIndex", "(I)I", -1);
jint columnAtIndex = (*env)->CallIntMethod(env, axContext, jm_getAccessibleColumnAtIndex, (jint)index);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, axContext);
return (int)columnAtIndex;
}
- (BOOL) isAccessibleChildSelectedFromIndex:(int)index
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject axContext = [self axContextWithEnv:env];
if (axContext == NULL) return NO;
jclass clsInfo = (*env)->GetObjectClass(env, axContext);
DECLARE_METHOD_RETURN(jm_isAccessibleChildSelected, clsInfo, "isAccessibleChildSelected", "(I)Z", NO);
jboolean isAccessibleChildSelected = (*env)->CallIntMethod(env, axContext, jm_isAccessibleChildSelected, (jint)index);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, axContext);
return isAccessibleChildSelected;
}
// NSAccessibilityElement protocol methods
- (NSArray *)accessibilityChildren
{
return [self accessibilityRows];
}
- (NSArray *)accessibilitySelectedChildren
{
return [self accessibilitySelectedRows];
}
- (NSArray *)accessibilityRows
{
int rowCount = [self accessibilityRowCount];
NSMutableArray *children = [NSMutableArray arrayWithCapacity:rowCount];
for (int i = 0; i < rowCount; i++) {
[children addObject:[[TableRowAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:NULL
withIndex:i
withView:[self view]
withJavaRole:JavaAccessibilityIgnore]];
}
return [NSArray arrayWithArray:children];
}
- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedRows
{
NSArray<NSNumber *> *selectedRowIndexses = [self getTableSelectedInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_ROWS];
NSMutableArray *children = [NSMutableArray arrayWithCapacity:[selectedRowIndexses count]];
for (NSNumber *index in selectedRowIndexses) {
[children addObject:[[TableRowAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:NULL
withIndex:index.unsignedIntValue
withView:[self view]
withJavaRole:JavaAccessibilityIgnore]];
}
return [NSArray arrayWithArray:children];
}
- (NSString *)accessibilityLabel
{
return [super accessibilityLabel] == NULL ? @"table" : [super accessibilityLabel];
}
- (NSRect)accessibilityFrame
{
return [super accessibilityFrame];
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
- (nullable NSArray *)accessibilityColumns
{
int colCount = [self accessibilityColumnCount];
NSMutableArray *columns = [NSMutableArray arrayWithCapacity:colCount];
for (int i = 0; i < colCount; i++) {
[columns addObject:[[ColumnAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:NULL
withIndex:i
withView:self->fView
withJavaRole:JavaAccessibilityIgnore]];
}
return [NSArray arrayWithArray:columns];
}
- (nullable NSArray *)accessibilitySelectedColumns
{
NSArray<NSNumber *> *indexes = [self getTableSelectedInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_COLS];
NSMutableArray *columns = [NSMutableArray arrayWithCapacity:[indexes count]];
for (NSNumber *i in indexes) {
[columns addObject:[[ColumnAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:NULL
withIndex:i.unsignedIntValue
withView:self->fView
withJavaRole:JavaAccessibilityIgnore]];
}
return [NSArray arrayWithArray:columns];
}
- (NSInteger)accessibilityRowCount
{
return [[self getTableInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_ROWS] integerValue];
}
- (NSInteger)accessibilityColumnCount
{
return [[self getTableInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_COLS] integerValue];
}
- (nullable NSArray *)accessibilitySelectedCells
{
NSArray *children = [super accessibilitySelectedChildren];
NSMutableArray *cells = [NSMutableArray arrayWithCapacity:[children count]];
for (CommonComponentAccessibility *child in children) {
[cells addObject:[[CellAccessibility alloc] initWithParent:self
withEnv:[ThreadUtilities getJNIEnv]
withAccessible:child->fAccessible
withIndex:child->fIndex
withView:fView
withJavaRole:child->fJavaRole]];
}
return [NSArray arrayWithArray:cells];
}
- (id)accessibilityCellForColumn:(NSInteger)column row:(NSInteger)row {
return [[(TableRowAccessibility *)[[self accessibilityRows] objectAtIndex:row] accessibilityChildren] objectAtIndex:column];
}
@end

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "CommonComponentAccessibility.h"
@interface TableRowAccessibility : CommonComponentAccessibility <NSAccessibilityRow>
@property(readonly) NSUInteger rowNumberInTable;
@end

View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#import "TableRowAccessibility.h"
#import "JavaAccessibilityAction.h"
#import "JavaAccessibilityUtilities.h"
#import "TableAccessibility.h"
#import "CellAccessibility.h"
#import "ThreadUtilities.h"
#import "JNIUtilities.h"
#import "sun_lwawt_macosx_CAccessibility.h"
static jclass sjc_CAccessibility = NULL;
static jmethodID jm_getChildrenAndRoles = NULL;
#define GET_CHILDRENANDROLES_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles",\
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;", ret);
@implementation TableRowAccessibility
// NSAccessibilityElement protocol methods
- (NSAccessibilityRole)accessibilityRole
{
return NSAccessibilityRowRole;
}
- (NSAccessibilitySubrole)accessibilitySubrole
{
return NSAccessibilityTableRowSubrole;
}
- (NSArray *)accessibilityChildren
{
NSArray *children = [super accessibilityChildren];
if (children == nil) {
JNIEnv *env = [ThreadUtilities getJNIEnv];
CommonComponentAccessibility *parent = [self accessibilityParent];
if (parent->fAccessible == NULL) return nil;
GET_CHILDRENANDROLES_METHOD_RETURN(nil);
jobjectArray jchildrenAndRoles = (jobjectArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getChildrenAndRoles,
parent->fAccessible, parent->fComponent, sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN, NO);
CHECK_EXCEPTION();
if (jchildrenAndRoles == NULL) return nil;
jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
NSMutableArray *childrenCells = [NSMutableArray arrayWithCapacity:arrayLen/2];
NSUInteger childIndex = fIndex * [(TableAccessibility *)parent accessibilityColumnCount];
NSInteger i = childIndex * 2;
NSInteger n = (fIndex + 1) * [(TableAccessibility *)parent accessibilityColumnCount] * 2;
for(i; i < n; 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) {
DECLARE_CLASS_RETURN(sjc_AccessibleRole, "javax/accessibility/AccessibleRole", nil);
DECLARE_FIELD_RETURN(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;", nil);
jobject jkey = (*env)->GetObjectField(env, jchildJavaRole, sjf_key);
CHECK_EXCEPTION();
childJavaRole = JavaStringToNSString(env, jkey);
(*env)->DeleteLocalRef(env, jkey);
}
CellAccessibility *child = [[CellAccessibility alloc] initWithParent:self
withEnv:env
withAccessible:jchild
withIndex:childIndex
withView:self->fView
withJavaRole:childJavaRole];
[childrenCells addObject:[[child retain] autorelease]];
(*env)->DeleteLocalRef(env, jchild);
(*env)->DeleteLocalRef(env, jchildJavaRole);
childIndex++;
}
(*env)->DeleteLocalRef(env, jchildrenAndRoles);
return childrenCells;
} else {
return children;
}
}
- (NSInteger)accessibilityIndex
{
return self->fIndex;
}
- (NSString *)accessibilityLabel
{
NSString *accessibilityName = @"";
NSArray *children = [self accessibilityChildren];
for (id cell in children) {
if ([accessibilityName isEqualToString:@""]) {
accessibilityName = [cell accessibilityLabel];
} else {
accessibilityName = [accessibilityName stringByAppendingFormat:@", %@", [cell accessibilityLabel]];
}
}
return accessibilityName;
}
- (id)accessibilityParent
{
return [super accessibilityParent];
}
- (NSRect)accessibilityFrame
{
int height = [[[self accessibilityChildren] objectAtIndex:0] accessibilityFrame].size.height;
int width = 0;
NSPoint point = [[[self accessibilityChildren] objectAtIndex:0] accessibilityFrame].origin;
for (id cell in [self accessibilityChildren]) {
width += [cell accessibilityFrame].size.width;
}
return NSMakeRect(point.x, point.y, width, height);
}
@end

View File

@@ -183,23 +183,25 @@
* or maybe a way for the app to continue running depending on the exact
* nature of the problem that has been detected and how survivable it is.
*/
#define CHECK_EXCEPTION() \
if ((*env)->ExceptionOccurred(env) != NULL) { \
#define CHECK_EXCEPTION_IN_ENV(env) \
if ((*(env))->ExceptionOccurred(env) != NULL) { \
if ([NSThread isMainThread] == YES) { \
if (getenv("JNU_APPKIT_TRACE")) { \
(*env)->ExceptionDescribe(env); \
(*(env))->ExceptionDescribe(env); \
NSLog(@"%@",[NSThread callStackSymbols]); \
} else { \
(*env)->ExceptionClear(env); \
(*(env))->ExceptionClear(env); \
} \
} \
if (getenv("JNU_NO_COCOA_EXCEPTION") == NULL) { \
[NSException raise:NSGenericException format:@"Java Exception"]; \
} else { \
(*env)->ExceptionClear(env); \
(*(env))->ExceptionClear(env); \
} \
};
#define CHECK_EXCEPTION() CHECK_EXCEPTION_IN_ENV(env)
#define CHECK_EXCEPTION_NULL_RETURN(x, y) \
CHECK_EXCEPTION(); \
if ((x) == NULL) { \

View File

@@ -235,15 +235,38 @@ public abstract class SunToolkit extends Toolkit
private static final ReentrantLock AWT_LOCK = new ReentrantLock();
private static final Condition AWT_LOCK_COND = AWT_LOCK.newCondition();
public interface AwtLockListener {
void afterAwtLocked();
void beforeAwtUnlocked();
}
private static java.util.List<AwtLockListener> awtLockListeners;
public static synchronized void addAwtLockListener(AwtLockListener l) {
if (awtLockListeners == null) {
awtLockListeners = Collections.synchronizedList(new ArrayList<>());
}
awtLockListeners.add(l);
}
public static final void awtLock() {
AWT_LOCK.lock();
if (awtLockListeners != null) {
awtLockListeners.forEach(AwtLockListener::afterAwtLocked);
}
}
public static final boolean awtTryLock() {
return AWT_LOCK.tryLock();
final boolean wasLocked = AWT_LOCK.tryLock();
if (wasLocked && awtLockListeners != null) {
awtLockListeners.forEach(AwtLockListener::afterAwtLocked);
}
return wasLocked;
}
public static final void awtUnlock() {
if (awtLockListeners != null) {
awtLockListeners.forEach(AwtLockListener::beforeAwtUnlocked);
}
AWT_LOCK.unlock();
}

View File

@@ -73,6 +73,12 @@
#include "fontscaler.h"
#define CHECK_EXCEPTION(env, describe) \
if ((*(env))->ExceptionCheck(env)) { \
if (describe) (*(env))->ExceptionDescribe(env);\
else (*(env))->ExceptionClear(env); \
}
#define ftFixed1 (FT_Fixed) (1 << 16)
#define FloatToFTFixed(f) (FT_Fixed)((f) * (float)(ftFixed1))
#define FTFixedToFloat(x) ((x) / (float)(ftFixed1))
@@ -164,6 +170,7 @@ static jclass tkClass;
static jmethodID getScreenResolutionMID;
static jfieldID platNameFID;
static jfieldID familyNameFID;
static jboolean debugFonts; // Stores the value of FontUtilities.debugFonts()
#ifndef DISABLE_FONTCONFIG
typedef FcBool (*FcPatternAddPtrType) (FcPattern *p, const char *object, FcValue value, FcBool append);
@@ -253,6 +260,11 @@ Java_sun_font_FreetypeFontScaler_initIDs(
invalidateScalerMID =
(*env)->GetMethodID(env, FFSClass, "invalidateScaler", "()V");
jboolean ignoreException;
debugFonts = JNU_CallStaticMethodByName(env, &ignoreException,
"sun/font/FontUtilities",
"debugFonts", "()Z").z;
getDefaultToolkitMID =
(*env)->GetStaticMethodID(env, TKClass, "getDefaultToolkit",
"()Ljava/awt/Toolkit;");
@@ -337,6 +349,11 @@ static int getScreenResolution(JNIEnv *env) {
jthrowable exc;
jclass tk = (*env)->CallStaticObjectMethod(
env, tkClass, getDefaultToolkitMID);
exc = (*env)->ExceptionOccurred(env);
if (exc) {
(*env)->ExceptionClear(env);
return DEFAULT_DPI;
}
int dpi = (*env)->CallIntMethod(env, tk, getScreenResolutionMID);
/* Test if there is no exception here (can get java.awt.HeadlessException)
@@ -396,6 +413,9 @@ static void invalidateJavaScaler(JNIEnv *env,
FTScalerInfo* scalerInfo) {
freeNativeResources(env, scalerInfo);
(*env)->CallVoidMethod(env, scaler, invalidateScalerMID);
// NB: Exceptions must not be cleared (and therefore no JNI calls
// performed) after calling this method because it intentionally
// leaves an exception pending.
}
/******************* I/O handlers ***************************/
@@ -446,6 +466,7 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream,
scalerInfo->font2D,
sunFontIDs.ttReadBlockMID,
bBuffer, offset, numBytes);
CHECK_EXCEPTION(env, debugFonts);
if (bread < 0) {
return 0;
} else {
@@ -465,7 +486,8 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream,
(*env)->CallObjectMethod(env, scalerInfo->font2D,
sunFontIDs.ttReadBytesMID,
offset, numBytes);
/* If there's an OutofMemoryError then byteArray will be null */
CHECK_EXCEPTION(env, debugFonts);
/* If there's an OutOfMemoryError then byteArray will be null */
if (byteArray == NULL) {
return 0;
} else {
@@ -498,6 +520,7 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream,
sunFontIDs.ttReadBlockMID,
bBuffer, offset,
scalerInfo->fontDataLength);
CHECK_EXCEPTION(env, debugFonts);
if (bread <= 0) {
return 0;
} else if ((unsigned long)bread < numBytes) {

View File

@@ -110,6 +110,13 @@ class XAtomList {
atoms.remove(atom);
}
/**
* Adds or removes (depending on {@code set} value) atom to the list. Returns {@code true} if the list contents
* has changed after the operation.
*/
public boolean update(XAtom atom, boolean set) {
return set ? atoms.add(atom) : atoms.remove(atom);
}
/**
* Returns size of the list

View File

@@ -32,6 +32,7 @@ import java.awt.event.WindowEvent;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import sun.awt.IconInfo;
import sun.util.logging.PlatformLogger;
@@ -340,7 +341,19 @@ abstract class XDecoratedPeer extends XWindowPeer {
|| ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom())
{
if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) {
getWMSetInsets(XAtom.get(ev.get_atom()));
if (getMWMDecorTitleProperty().isPresent()) {
// Insets might have changed "in-flight" if that property
// is present, so we need to get the actual values of
// insets from the WM and propagate them through all the
// proper channels.
wm_set_insets = null;
Insets in = getWMSetInsets(XAtom.get(ev.get_atom()));
if (in != null && !in.equals(dimensions.getInsets())) {
handleCorrectInsets(in);
}
} else {
getWMSetInsets(XAtom.get(ev.get_atom()));
}
} else {
if (!isReparented()) {
return;
@@ -1319,4 +1332,24 @@ abstract class XDecoratedPeer extends XWindowPeer {
}
super.handleWindowFocusOut(oppositeWindow, serial);
}
public static final String MWM_DECOR_TITLE_PROPERTY_NAME = "xawt.mwm_decor_title";
public final Optional<Boolean> getMWMDecorTitleProperty() {
Optional<Boolean> res = Optional.empty();
if (SunToolkit.isInstanceOf(target, "javax.swing.RootPaneContainer")) {
javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer) target).getRootPane();
Object prop = rootpane.getClientProperty(MWM_DECOR_TITLE_PROPERTY_NAME);
if (prop != null) {
res = Optional.of(Boolean.parseBoolean(prop.toString()));
}
}
return res;
}
public final boolean getWindowTitleVisible() {
return getMWMDecorTitleProperty().orElse(true);
}
}

View File

@@ -63,11 +63,27 @@ class XDialogPeer extends XDecoratedPeer implements DialogPeer {
try {
Dialog target = (Dialog)this.target;
if (vis) {
if (target.getModalityType() != Dialog.ModalityType.MODELESS) {
boolean modal = target.getModalityType() != Dialog.ModalityType.MODELESS;
if (modal) {
if (!isModalBlocked()) {
XBaseWindow.ungrabInput();
}
}
if (XWM.getWMID() == XWM.KDE2_WM) {
// In case of KDE, we inform window manager that our window is a modal dialog
// so that it's minimized along with its parent window.
// This is not needed for other WMs, as it seems only KDE allows minimizing 'transient'
// windows, and setting _NET_WM_STATE_MODAL causes other WMs' undesirable behaviour.
// GNOME (mutter WM), for example, enforces centering of modal dialogs with respect
// to their parent, which breaks SiblingChildOrderTest.
XNETProtocol protocol = XWM.getWM().getNETProtocol();
if (protocol != null && protocol.doModalityProtocol()) {
XAtomList net_wm_state = getNETWMState();
if (net_wm_state.update(protocol.XA_NET_WM_STATE_MODAL, modal)) {
setNETWMState(net_wm_state);
}
}
}
} else {
restoreTransientFor(this);
prevTransientFor = null;

View File

@@ -34,6 +34,7 @@ import java.awt.Insets;
import java.awt.MenuBar;
import java.awt.Rectangle;
import java.awt.peer.FramePeer;
import sun.awt.SunToolkit;
import sun.util.logging.PlatformLogger;
import sun.awt.AWTAccessor;
@@ -66,11 +67,7 @@ class XFramePeer extends XDecoratedPeer implements FramePeer {
state = 0;
undecorated = Boolean.valueOf(target.isUndecorated());
winAttr.nativeDecor = !target.isUndecorated();
if (winAttr.nativeDecor) {
winAttr.decorations = XWindowAttributesData.AWT_DECOR_ALL;
} else {
winAttr.decorations = XWindowAttributesData.AWT_DECOR_NONE;
}
winAttr.decorations = getWindowDecorationBits();
winAttr.functions = MWMConstants.MWM_FUNC_ALL;
winAttr.isResizable = true; // target.isResizable();
winAttr.title = target.getTitle();
@@ -80,6 +77,38 @@ class XFramePeer extends XDecoratedPeer implements FramePeer {
Integer.valueOf(winAttr.decorations), Boolean.valueOf(winAttr.initialResizability),
Boolean.valueOf(!winAttr.nativeDecor), Integer.valueOf(winAttr.initialState));
}
registerWindowDecorationChangeListener();
}
private void registerWindowDecorationChangeListener() {
if (SunToolkit.isInstanceOf(target, "javax.swing.RootPaneContainer")) { // avoid unnecessary class loading
javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer) target).getRootPane();
rootpane.addPropertyChangeListener(MWM_DECOR_TITLE_PROPERTY_NAME, e -> winAttr.decorations = getWindowDecorationBits() );
}
}
private int getWindowDecorationBits() {
int decorations = XWindowAttributesData.AWT_DECOR_NONE;
final Frame target = (Frame)(this.target);
final boolean useNativeDecor = !target.isUndecorated();
if (useNativeDecor) {
decorations = XWindowAttributesData.AWT_DECOR_ALL;
if (!getWindowTitleVisible()) {
// NB: the window must be [re-]mapped to make this change effective. Also, window insets will probably
// change and that'll be caught by one of the subsequent property change events in XDecoratedPeer
// (not necessarily the very next event, though).
decorations = XWindowAttributesData.AWT_DECOR_BORDER;
}
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("Frame''s initial decorations affected by the client property {0}={1}",
MWM_DECOR_TITLE_PROPERTY_NAME, getMWMDecorTitleProperty());
}
}
return decorations;
}
void postInit(XCreateWindowParams params) {

View File

@@ -111,6 +111,9 @@ import java.awt.peer.TextFieldPeer;
import java.awt.peer.TrayIconPeer;
import java.awt.peer.WindowPeer;
import java.beans.PropertyChangeListener;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
@@ -125,6 +128,12 @@ import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import java.util.Deque;
import java.util.ArrayDeque;
import java.util.AbstractMap;
import java.util.StringTokenizer;
import java.util.Optional;
import java.util.Set;
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
@@ -159,6 +168,280 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
private static final PlatformLogger keyEventLog = PlatformLogger.getLogger("sun.awt.X11.kye.XToolkit");
private static final PlatformLogger backingStoreLog = PlatformLogger.getLogger("sun.awt.X11.backingStore.XToolkit");
public static final class Tracer {
private static int flags; // what to trace (see TRACE... below)
private static String fileName; // where to trace to (file or stderr if null)
private static String pattern; // limit tracing to method names containing this pattern (ignore case)
private static PrintStream outStream; // stream to trace to
private static long threshold = 0; // minimum time delta to record the event
private static boolean verbose = false; // verbose tracing
private static final int TRACELOG = 1;
private static final int TRACETIMESTAMP = 1 << 1;
private static final int TRACESTATS = 1 << 2;
private static void showTraceUsage() {
System.err.println("usage: -Dsun.awt.x11.trace=" +
"[log[,timestamp]],[stats],[name:<substr pattern>]," +
"[out:<filename>],[td=<threshold>],[help],[verbose]");
}
static {
final String trace = System.getProperty("sun.awt.x11.trace");
if (trace != null) {
int traceFlags = 0;
final StringTokenizer st = new StringTokenizer(trace, ",");
while (st.hasMoreTokens()) {
final String tok = st.nextToken();
if (tok.equalsIgnoreCase("stats")) {
traceFlags |= TRACESTATS;
} else if (tok.equalsIgnoreCase("log")) {
traceFlags |= TRACELOG;
} else if (tok.equalsIgnoreCase("timestamp")) {
traceFlags |= TRACETIMESTAMP;
} else if (tok.regionMatches(true, 0, "name:", 0, 5)) {
pattern = tok.substring(5).toUpperCase();
} else if (tok.equalsIgnoreCase("verbose")) {
verbose = true;
} else if (tok.regionMatches(true, 0, "out:", 0, 4)) {
fileName = tok.substring(4);
} else if (tok.regionMatches(true, 0, "td=", 0, 3)) {
try {
threshold = Long.max(Long.parseLong(tok.substring(3)), 0);
} catch (NumberFormatException e) {
showTraceUsage();
}
} else {
if (!tok.equalsIgnoreCase("help")) {
System.err.println("unrecognized token: " + tok);
}
showTraceUsage();
}
}
if (verbose) {
System.err.print("XToolkit logging ");
if ((traceFlags & TRACELOG) != 0) {
System.err.println("enabled");
System.err.print("XToolkit timestamps ");
if ((traceFlags & TRACETIMESTAMP) != 0) {
System.err.println("enabled");
} else {
System.err.println("disabled");
}
} else {
System.err.println("[and timestamps] disabled");
}
System.err.print("XToolkit invocation statistics at exit ");
if ((traceFlags & TRACESTATS) != 0) {
System.err.println("enabled");
} else {
System.err.println("disabled");
}
System.err.print("XToolkit trace output to ");
if (fileName == null) {
System.err.println("System.err");
} else {
System.err.println("file '" + fileName + "'");
}
if (pattern != null) {
System.err.println("XToolkit trace limited to " + pattern);
}
}
Tracer.flags = traceFlags;
}
}
public static boolean tracingEnabled() {
return (flags != 0);
}
private static synchronized PrintStream getTraceOutputFile() {
if (outStream == null) {
outStream = System.err;
if (fileName != null) {
try {
outStream = new PrintStream(new FileOutputStream(fileName), true);
} catch (FileNotFoundException e) {
}
}
}
return outStream;
}
private static long lastTimeMs = System.currentTimeMillis();
private static synchronized void outputTraceLine(String prefix, String line) {
final StringBuilder outStr = new StringBuilder(prefix);
outStr.append(' ');
if ((flags & TRACETIMESTAMP) != 0) {
final long curTimeMs = System.currentTimeMillis();
outStr.append(String.format("+ %1$03dms ", curTimeMs - lastTimeMs));
lastTimeMs = curTimeMs;
}
outStr.append(line);
getTraceOutputFile().println(outStr);
}
public static void traceRawLine(String line) {
getTraceOutputFile().println(line);
}
public static void traceLine(String line) {
outputTraceLine("[LOG] ", line);
}
public static void traceError(String msg) {
outputTraceLine("[ERR] ", msg);
}
private static boolean isInterestedInMethod(String mname) {
return (pattern == null || mname.toUpperCase().contains(pattern));
}
private static final class AwtLockerDescriptor {
public long startTimeMs; // when the locking has occurred
public StackWalker.StackFrame frame; // the frame that called awtLock()
public AwtLockerDescriptor(StackWalker.StackFrame frame, long start) {
this.startTimeMs = start;
this.frame = frame;
}
}
private static final Deque<AwtLockerDescriptor> awtLockersStack = new ArrayDeque<>();
private static void pushAwtLockCaller(StackWalker.StackFrame frame, long startTimeMs) {
// accessed under AWT lock so no need for additional synchronization
awtLockersStack.push(new AwtLockerDescriptor(frame, startTimeMs));
}
private static long popAwtLockCaller(StackWalker.StackFrame frame, long finishTimeMs) {
// accessed under AWT lock so no need for additional synchronization
try {
final AwtLockerDescriptor descr = awtLockersStack.pop();
if (descr.frame.getMethodName().compareTo(frame.getMethodName()) != 0) {
// Note: this often happens with XToolkit.waitForEvents()/XToolkit.run().
// traceError("Mismatching awtLock()/awtUnlock(): locked by " + descr.frame + ", unlocked by " + frame);
}
return finishTimeMs - descr.startTimeMs;
} catch(NoSuchElementException e) {
traceError("No matching awtLock() for awtUnlock(): " + frame);
}
return -1;
}
private static class AwtLockTracer implements SunToolkit.AwtLockListener {
private static final Set<String> awtLockerMethods = Set.of("awtLock", "awtUnlock", "awtTryLock");
private static StackWalker.StackFrame getLockCallerFrame() {
Optional<StackWalker.StackFrame> frame = StackWalker.getInstance().walk(
s -> s.dropWhile(stackFrame -> !awtLockerMethods.contains(stackFrame.getMethodName()))
.dropWhile(stackFrame -> awtLockerMethods.contains( stackFrame.getMethodName()))
.findFirst() );
return frame.orElse(null);
}
public void afterAwtLocked() {
final StackWalker.StackFrame awtLockerFrame = getLockCallerFrame();
if (awtLockerFrame != null) {
final String mname = awtLockerFrame.getMethodName();
if (isInterestedInMethod(mname)) {
pushAwtLockCaller(awtLockerFrame, System.currentTimeMillis());
}
}
}
public void beforeAwtUnlocked() {
final StackWalker.StackFrame awtLockerFrame = getLockCallerFrame();
if (awtLockerFrame != null) {
final String mname = awtLockerFrame.getMethodName();
if (isInterestedInMethod(mname)) {
final long timeSpentMs = popAwtLockCaller(awtLockerFrame, System.currentTimeMillis());
if (timeSpentMs >= threshold) {
updateStatistics(awtLockerFrame.toString(), timeSpentMs);
traceLine(String.format("%s held AWT lock for %dms", awtLockerFrame, timeSpentMs));
}
}
}
}
}
private static final class MethodStats implements Comparable<MethodStats> {
public long minTimeMs;
public long maxTimeMs;
public long count;
private long totalTimeMs;
MethodStats() {
this.minTimeMs = Long.MAX_VALUE;
}
public void update(long timeSpentMs) {
count++;
minTimeMs = Math.min(minTimeMs, timeSpentMs);
maxTimeMs = Math.max(maxTimeMs, timeSpentMs);
totalTimeMs += timeSpentMs;
}
public long averageTimeMs() {
return (long)((double)totalTimeMs / count);
}
@Override
public int compareTo(MethodStats other) {
return Long.compare(other.averageTimeMs(), this.averageTimeMs());
}
@Override
public String toString() {
return String.format("%dms (%dx[%d-%d]ms)", averageTimeMs(), count, minTimeMs, maxTimeMs);
}
}
private static HashMap<String, MethodStats> methodTimingTable;
private static synchronized void updateStatistics(String mname, long timeSpentMs) {
if ((flags & TRACESTATS) != 0) {
if (methodTimingTable == null) {
methodTimingTable = new HashMap<>(1024);
TraceReporter.setShutdownHook();
}
final MethodStats descr = methodTimingTable.computeIfAbsent(mname, k -> new MethodStats());
descr.update(timeSpentMs);
}
}
private static class TraceReporter implements Runnable {
public static void setShutdownHook() {
final Tracer.TraceReporter t = new Tracer.TraceReporter();
final Thread thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), t,
"XToolkit TraceReporter", 0, false);
thread.setContextClassLoader(null);
Runtime.getRuntime().addShutdownHook(thread);
}
public void run() {
traceRawLine("");
traceRawLine("AWT Lock usage statistics");
traceRawLine("=========================");
final ArrayList<AbstractMap.SimpleImmutableEntry<String, MethodStats>> l;
synchronized(Tracer.class) { // in order to avoid methodTimingTable modifications during the traversal
l = new ArrayList<>(methodTimingTable.size());
methodTimingTable.forEach((fname, fdescr)
-> l.add(new AbstractMap.SimpleImmutableEntry<>(fname, fdescr)));
}
l.sort(Map.Entry.comparingByValue());
l.forEach(item -> traceRawLine(item.getValue() + " --- " + item.getKey()));
traceRawLine("Legend: <avg time> ( <times called> x [ <fastest time> - <slowest time> ] ms) --- <caller of XToolkit.awtUnlock()>");
}
}
}
//There is 400 ms is set by default on Windows and 500 by default on KDE and GNOME.
//We use the same hardcoded constant.
private static final int AWT_MULTICLICK_DEFAULT_TIME = 500;
@@ -419,6 +702,10 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
PerformanceLogger.setTime("XToolkit construction");
}
if (Tracer.tracingEnabled()) {
addAwtLockListener(new Tracer.AwtLockTracer());
}
if (!GraphicsEnvironment.isHeadless()) {
String mainClassName = null;

View File

@@ -47,6 +47,8 @@
#include "awt_p.h"
#include "awt_GraphicsEnv.h"
#include "keycode_cache.h"
#define XK_KATAKANA
#include <X11/keysym.h> /* standard X keysyms */
#include <X11/DECkeysym.h> /* DEC vendor-specific */
@@ -812,6 +814,7 @@ isXKBenabled(Display *display) {
return awt_UseXKB;
}
#ifndef USE_KEYCODE_CACHE
/*
* Map a keycode to the corresponding keysym.
* This replaces the deprecated X11 function XKeycodeToKeysym
@@ -836,6 +839,7 @@ keycodeToKeysym(Display *display, KeyCode keycode, int index) {
XFree(key_syms);
return ks;
}
#endif // USE_KEYCODE_CACHE
static Boolean
isKPevent(XEvent *event)

View File

@@ -36,6 +36,7 @@
#include "utility/rect.h"
#include "sun_awt_X11_XlibWrapper.h"
#include "keycode_cache.h"
#include <stdlib.h>
#include <string.h>
@@ -56,9 +57,6 @@
extern Bool statusWindowEventHandler(XEvent event);
#endif
// From XWindow.c
extern KeySym keycodeToKeysym(Display *display, KeyCode keycode, int index);
#if defined(DEBUG)
static jmethodID lockIsHeldMID = NULL;
@@ -179,6 +177,11 @@ JNIEXPORT void JNICALL
Java_sun_awt_X11_XlibWrapper_XCloseDisplay(JNIEnv *env, jclass clazz,
jlong display) {
AWT_CHECK_HAVE_LOCK();
#ifdef USE_KEYCODE_CACHE
resetKeyCodeCache();
#endif
XCloseDisplay((Display*) jlong_to_ptr(display));
}
@@ -2023,6 +2026,11 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XlibWrapper_XRefreshKeyboardMapping
(JNIEnv *env, jclass clazz, jlong event_ptr)
{
AWT_CHECK_HAVE_LOCK();
#ifdef USE_KEYCODE_CACHE
resetKeyCodeCache();
#endif
XRefreshKeyboardMapping((XMappingEvent*) jlong_to_ptr(event_ptr));
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2021 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "keycode_cache.h"
#include "awt.h"
#ifdef DEBUG
#include <stdio.h>
#endif
#ifdef USE_KEYCODE_CACHE
/**
* Keeps the KeyCode -> KeySym mapping.
*/
typedef struct {
KeySym* symbols; // array of KeySym indexed by the key code with min_code corresponding to index 0
int syms_per_code; // number of elements in 'symbols' corresponding to one key code
int min_code; // minimum valid key code (typically 8)
int max_code; // maximum valid key code (typically 255)
} KeyCodeCache;
static KeyCodeCache keycode_cache = {0};
#ifdef DEBUG
static void
dump_keycode_cache(const KeyCodeCache* cache) {
fprintf(stderr, "KeyCodeCache dump\n");
if (cache->symbols == NULL) {
fprintf(stderr, "-- empty --\n");
} else {
fprintf(stderr, "syms_per_code=%d, min_code=%d, max_code=%d\n",
cache->syms_per_code, cache->min_code, cache->max_code);
for(int i = cache->min_code; i <= cache->max_code; i++) {
fprintf(stderr, "0x%02x --", i);
for(int j = 0; j < cache->syms_per_code; j++) {
const int sym_index = (i - cache->min_code)*cache->syms_per_code + j;
fprintf(stderr, "%04d - ", cache->symbols[sym_index]);
}
fprintf(stderr, "\n");
}
}
}
#endif // DEBUG
/**
* Clears the cache and frees memory, if allocated.
*
* NB: not thread safe and is supposed to be called only when holding the AWT lock.
*/
extern void
resetKeyCodeCache(void) {
if (keycode_cache.symbols) {
XFree(keycode_cache.symbols);
}
keycode_cache = (KeyCodeCache){0};
}
/**
* Translates the given keycode to the corresponding KeySym at the given index.
* Caches the mapping for all valid key codes by using just one XGetKeyboardMapping() Xlib call,
* which greatly reduces delays when working with a remote X server.
*
* NB: not thread safe and is supposed to be called only when holding the AWT lock.
*/
extern KeySym
keycodeToKeysym(Display* display, KeyCode keycode, int index) {
if (!keycode_cache.symbols) {
XDisplayKeycodes(display, &keycode_cache.min_code, &keycode_cache.max_code);
const int count_all = keycode_cache.max_code - keycode_cache.min_code + 1;
keycode_cache.symbols = XGetKeyboardMapping(display, keycode_cache.min_code, count_all, &keycode_cache.syms_per_code);
// NB: this may not always get free'ed
}
if (keycode_cache.symbols) {
const Boolean code_within_range = (keycode >= keycode_cache.min_code && keycode <= keycode_cache.max_code);
const Boolean index_within_range = (index >= 0 && index < keycode_cache.syms_per_code);
if (code_within_range && index_within_range) {
const int sym_index = (keycode - keycode_cache.min_code)*keycode_cache.syms_per_code + index;
KeySym sym = keycode_cache.symbols[sym_index];
return sym;
}
}
return NoSymbol;
}
#endif /* USE_KEYCODE_CACHE */

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2021 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _KEYCODE_CACHE_H
#define _KEYCODE_CACHE_H
#include <X11/Xlib.h>
#define USE_KEYCODE_CACHE 1
void resetKeyCodeCache(void);
KeySym keycodeToKeysym(Display* display, KeyCode keycode, int index);
#endif /* _KEYCODE_CACHE_H */

View File

@@ -866,7 +866,11 @@ void D3DRQ_FlushBuffer(void *pParam)
if (!JNU_IsNull(env, pFlush->runnable)) {
J2dTraceLn(J2D_TRACE_VERBOSE, " executing runnable");
JNU_CallMethodByName(env, NULL, pFlush->runnable, "run", "()V");
jboolean hasException;
JNU_CallMethodByName(env, &hasException, pFlush->runnable, "run", "()V");
if (hasException) {
J2dTraceLn(J2D_TRACE_ERROR, " exception occurred while executing runnable");
}
}
}

View File

@@ -6706,11 +6706,11 @@ JNIEXPORT void JNICALL
Java_java_awt_Component_initIDs(JNIEnv *env, jclass cls)
{
TRY;
jclass inputEventClazz = env->FindClass("java/awt/event/InputEvent");
CHECK_NULL(inputEventClazz);
jmethodID getButtonDownMasksID = env->GetStaticMethodID(inputEventClazz, "getButtonDownMasks", "()[I");
CHECK_NULL(getButtonDownMasksID);
jintArray obj = (jintArray)env->CallStaticObjectMethod(inputEventClazz, getButtonDownMasksID);
jboolean ignoreException;
jintArray obj = (jintArray)JNU_CallStaticMethodByName(env, &ignoreException,
"java/awt/event/InputEvent",
"getButtonDownMasks", "()[I").l;
CHECK_NULL(obj);
jint * tmp = env->GetIntArrayElements(obj, JNI_FALSE);
CHECK_NULL(tmp);
jsize len = env->GetArrayLength(obj);

View File

@@ -823,6 +823,7 @@ void AwtDesktopProperties::SetStringProperty(LPCTSTR propName, LPTSTR value) {
key, jValue);
GetEnv()->DeleteLocalRef(jValue);
GetEnv()->DeleteLocalRef(key);
(void)safe_ExceptionOccurred(GetEnv());
}
void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) {
@@ -835,6 +836,7 @@ void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) {
AwtDesktopProperties::setIntegerPropertyID,
key, (jint)value);
GetEnv()->DeleteLocalRef(key);
(void)safe_ExceptionOccurred(GetEnv());
}
void AwtDesktopProperties::SetBooleanProperty(LPCTSTR propName, BOOL value) {
@@ -846,6 +848,7 @@ void AwtDesktopProperties::SetBooleanProperty(LPCTSTR propName, BOOL value) {
AwtDesktopProperties::setBooleanPropertyID,
key, value ? JNI_TRUE : JNI_FALSE);
GetEnv()->DeleteLocalRef(key);
(void)safe_ExceptionOccurred(GetEnv());
}
void AwtDesktopProperties::SetColorProperty(LPCTSTR propName, DWORD value) {
@@ -858,6 +861,7 @@ void AwtDesktopProperties::SetColorProperty(LPCTSTR propName, DWORD value) {
key, GetRValue(value), GetGValue(value),
GetBValue(value));
GetEnv()->DeleteLocalRef(key);
(void)safe_ExceptionOccurred(GetEnv());
}
void AwtDesktopProperties::SetFontProperty(HDC dc, int fontID,
@@ -920,6 +924,7 @@ void AwtDesktopProperties::SetFontProperty(HDC dc, int fontID,
key, fontName, style, pointSize);
GetEnv()->DeleteLocalRef(key);
GetEnv()->DeleteLocalRef(fontName);
(void)safe_ExceptionOccurred(GetEnv());
}
}
delete[] face;
@@ -967,6 +972,7 @@ void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & fon
key, fontName, style, pointSize);
GetEnv()->DeleteLocalRef(key);
GetEnv()->DeleteLocalRef(fontName);
(void)safe_ExceptionOccurred(GetEnv());
}
void AwtDesktopProperties::SetSoundProperty(LPCTSTR propName, LPCTSTR winEventName) {
@@ -984,6 +990,7 @@ void AwtDesktopProperties::SetSoundProperty(LPCTSTR propName, LPCTSTR winEventNa
key, event);
GetEnv()->DeleteLocalRef(event);
GetEnv()->DeleteLocalRef(key);
(void)safe_ExceptionOccurred(GetEnv());
}
void AwtDesktopProperties::PlayWindowsSound(LPCTSTR event) {

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary Verifies the -Dsun.awt.x11.trace option
* @requires (os.family == "linux")
* @library /test/lib
* @run main X11Trace
*/
import java.awt.AWTException;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.charset.StandardCharsets;
import java.util.stream.Stream;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
public class X11Trace {
public static void main(String[] args) throws Exception {
if (args.length > 0 && args[0].equals("runtest")) {
runTest();
} else {
OutputAnalyzer oa = ProcessTools.executeTestJvm("-Dsun.awt.x11.trace=log,timestamp,stats,td=0", X11Trace.class.getName(), "runtest");
oa.shouldContain("held AWT lock for").shouldContain("AWT Lock usage statistics").shouldHaveExitValue(0);
oa = ProcessTools.executeTestJvm("-Dsun.awt.x11.trace=log", X11Trace.class.getName(), "runtest");
oa.shouldContain("held AWT lock for").shouldNotContain("AWT Lock usage statistics").shouldHaveExitValue(0);
oa = ProcessTools.executeTestJvm("-Dsun.awt.x11.trace=log,timestamp,stats,td=0,out:mylog", X11Trace.class.getName(), "runtest");
oa.shouldHaveExitValue(0).stderrShouldBeEmpty();
final String logFileContents = Files.readString(Paths.get("mylog"));
OutputAnalyzer logOA = new OutputAnalyzer(logFileContents);
logOA.shouldContain("held AWT lock for").shouldContain("AWT Lock usage statistics");
}
}
public static void delay(int ms) {
try {
Thread.sleep(ms);
} catch(InterruptedException e) {
}
}
public static void runTest() {
runSwing(() -> {
final JFrame frame = new JFrame("test");
frame.setVisible(true);
delay(500);
frame.dispose();
});
}
private static void runSwing(Runnable r) {
try {
SwingUtilities.invokeAndWait(r);
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -52,7 +52,9 @@ public class SiblingChildOrderTest
frame.setVisible(true);
});
Robot robot = new Robot();
for (int i = 0; i < colors.length; i++) {
robot.delay(100);
int finalI = i;
SwingUtilities.invokeLater(() -> {
dlgs[finalI] = new JDialog(frame, "DLG " + finalI, true);
@@ -63,7 +65,6 @@ public class SiblingChildOrderTest
});
}
Robot robot = new Robot();
robot.waitForIdle();
robot.delay(1000);

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.*;
import java.security.PublicKey;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CountDownLatch;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.GridBagLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JButton;
public abstract class AccessibleComponentTest {
protected static volatile boolean testResult = true;
protected static volatile CountDownLatch countDownLatch;
protected static String INSTRUCTIONS;
protected static String exceptionString;
protected JFrame mainFrame;
protected static AccessibleComponentTest a11yTest;
public abstract CountDownLatch createCountDownLatch();
public void createUI(JPanel component, String testName) {
mainFrame = new JFrame(testName);
GridBagLayout layout = new GridBagLayout();
JPanel mainControlPanel = new JPanel(layout);
JPanel resultButtonPanel = new JPanel(layout);
GridBagConstraints gbc = new GridBagConstraints();
JTextArea instructionTextArea = new JTextArea();
instructionTextArea.setText(INSTRUCTIONS);
instructionTextArea.setEditable(false);
instructionTextArea.setBackground(Color.white);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
mainControlPanel.add(instructionTextArea, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
mainControlPanel.add(component);
JButton passButton = new JButton("Pass");
passButton.setActionCommand("Pass");
passButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
mainFrame.dispose();
countDownLatch.countDown();
}
});
JButton failButton = new JButton("Fail");
failButton.setActionCommand("Fail");
failButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
testResult = false;
mainFrame.dispose();
countDownLatch.countDown();
}
});
gbc.gridx = 0;
gbc.gridy = 0;
resultButtonPanel.add(passButton, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
resultButtonPanel.add(failButton, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
mainControlPanel.add(resultButtonPanel, gbc);
mainFrame.add(mainControlPanel);
mainFrame.pack();
mainFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
mainFrame.dispose();
countDownLatch.countDown();
}
});
mainFrame.setVisible(true);
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8264287
* @summary Test implementation of NSAccessibilityComboBox protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJComboboxTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.util.concurrent.CountDownLatch;
public class AccessibleJComboboxTest extends AccessibleComponentTest {
@java.lang.Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
void createCombobox() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JCombobox.\n\n"
+ "Turn screen reader on, and Tab to the combobox.\n\n"
+ "If you can hear combobox selected item tab further and press PASS, otherwise press FAIL.";
JPanel frame = new JPanel();
String[] NAMES = {"One", "Two", "Three", "Four", "Five"};
JComboBox<String> combo = new JComboBox<>(NAMES);
JLabel label = new JLabel("This is combobox:");
label.setLabelFor(combo);
frame.setLayout(new FlowLayout());
frame.add(label);
frame.add(combo);
exceptionString = "AccessibleJCombobox test failed!";
super.createUI(frame, "AccessibleJComboboxTest");
}
public static void main(String[] args) throws Exception {
AccessibleJComboboxTest test = new AccessibleJComboboxTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeLater(test::createCombobox);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
}
}

View File

@@ -0,0 +1,330 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8264292
* @summary Test implementation of NSAccessibilityList protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJListTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JList;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JWindow;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.Rectangle;
import java.awt.Dimension;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccessibleJListTest extends AccessibleComponentTest {
private static final String[] NAMES = {"One", "Two", "Three", "Four", "Five"};
static JWindow window;
public static void main(String[] args) throws Exception {
a11yTest = new AccessibleJListTest();
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createSimpleList);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createSimpleListRenderer);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createSimpleListNamed);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createCombobox);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createPushButton);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
countDownLatch = a11yTest.createCountDownLatch();
SwingUtilities.invokeLater(((AccessibleJListTest) a11yTest)::createPushButtonHeavyWeight);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
}
@java.lang.Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
public void createSimpleList() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList.\n\n"
+ "Turn screen reader on, and Tab to the list.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear menu items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JList<String> list = new JList<>(NAMES);
frame.setLayout(new FlowLayout());
frame.add(list);
exceptionString = "Accessible JList simple list test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createSimpleListRenderer() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList with renderer.\n\n"
+ "Turn screen reader on, and Tab to the list.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear menu items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JList<String> list = new JList<>(NAMES);
list.setCellRenderer(new AccessibleJListTestRenderer());
frame.setLayout(new FlowLayout());
frame.add(list);
exceptionString = "Accessible JList with renderer simple list test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createSimpleListNamed() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of named JList.\n\n"
+ "Turn screen reader on, and Tab to the list.\n"
+ "Press the tab button to move to second list.\n\n"
+ "If you can hear second list name: \"second list\" - tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JList<String> list = new JList<>(NAMES);
JList<String> secondList = new JList<>(NAMES);
secondList.getAccessibleContext().setAccessibleName("Second list");
frame.setLayout(new FlowLayout());
frame.add(list);
frame.add(secondList);
exceptionString = "Accessible JList simple list named test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createCombobox() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList in a combobox.\n\n"
+ "Turn screen reader on, and Tab to the combobox.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear combobox items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JComboBox<String> combo = new JComboBox<>(NAMES);
frame.setLayout(new FlowLayout());
frame.add(combo);
exceptionString = "Accessible JList combobox test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createPushButton() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList in a popup in a simple window.\n\n"
+ "Turn screen reader on, and Tab to the show button and press space.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear popup menu items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JButton button = new JButton("show");
button.setPreferredSize(new Dimension(100, 35));
button.addActionListener(new ActionListener() {
final Runnable dispose = () -> {
window.dispose();
window = null;
button.setText("show");
};
@Override
public void actionPerformed(ActionEvent e) {
if (window == null) {
Rectangle bounds = frame.getBounds();
window = new JWindow(mainFrame);
JList<String> winList = new JList<>(NAMES);
winList.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dispose.run();
}
}
});
window.add(winList);
window.setLocation(bounds.x + bounds.width + 20, bounds.y);
window.pack();
window.setVisible(true);
button.setText("hide (ESC)");
} else {
dispose.run();
}
}
});
frame.setLayout(new FlowLayout());
frame.add(button);
exceptionString = "Accessible JList push button with simple window test failed!";
super.createUI(frame, "Accessible JList test");
}
public void createPushButtonHeavyWeight() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JList in a popup in a heavy weight window.\n\n"
+ "Turn screen reader on, and Tab to the show button and press space.\n"
+ "Press the up and down arrow buttons to move through the list.\n\n"
+ "If you can hear popup menu items tab further and press PASS, otherwise press FAIL.\n";
JPanel frame = new JPanel();
JButton button = new JButton("show");
button.setPreferredSize(new Dimension(100, 35));
button.addActionListener(new ActionListener() {
private Popup popup = null;
final Runnable dispose = () -> {
popup.hide();
popup = null;
button.requestFocus();
button.setText("show");
};
@Override
public void actionPerformed(ActionEvent e) {
if (popup == null) {
Rectangle bounds = frame.getBounds();
PopupFactory factory = PopupFactory.getSharedInstance();
JList<String> winList = new JList<>(NAMES);
winList.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dispose.run();
}
}
});
popup = factory.getPopup(frame, winList, bounds.x + bounds.width + 20, bounds.y);
Window c = SwingUtilities.getWindowAncestor(winList);
if (c != null) {
c.setAutoRequestFocus(true);
c.setFocusableWindowState(true);
}
popup.show();
button.setText("hide (ESC)");
} else {
dispose.run();
}
}
});
frame.setLayout(new FlowLayout());
frame.add(button);
exceptionString = "Accessible JList push button with heavy weight window test failed!";
super.createUI(frame, "Accessible JList test");
}
public static class AccessibleJListTestRenderer extends JPanel implements ListCellRenderer {
private JLabel labelAJT = new JLabel("AJL");
private JLabel itemName = new JLabel();
AccessibleJListTestRenderer() {
super(new FlowLayout());
setFocusable(false);
layoutComponents();
}
private void layoutComponents() {
add(labelAJT);
add(itemName);
}
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
return new Dimension(Math.min(size.width, 245), size.height);
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
itemName.setText(((String) value));
getAccessibleContext().setAccessibleName(labelAJT.getText() + ", " + itemName.getText());
return this;
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8264303
* @summary Test implementation of NSAccessibilityTabPanel protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJTabbedPaneTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JTabbedPane;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.JCheckBox;
import javax.swing.SwingUtilities;
import java.util.concurrent.CountDownLatch;
public class AccessibleJTabbedPaneTest extends AccessibleComponentTest {
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
void createTabPane() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTabbedPane.\n\n"
+ "Turn screen reader on, and tab to the JTabbedPane.\n"
+ "Use page up and page down arrow buttons to move through the tabs.\n\n"
+ "If you can hear selected tab names tab further and press PASS, otherwise press FAIL.\n";
JTabbedPane tabbedPane = new JTabbedPane();
JPanel panel1 = new JPanel();
String[] names = {"One", "Two", "Three", "Four", "Five"};
JList list = new JList(names);
JLabel fieldName = new JLabel("Text field:");
JTextField textField = new JTextField("some text");
fieldName.setLabelFor(textField);
panel1.add(fieldName);
panel1.add(textField);
panel1.add(list);
tabbedPane.addTab("Tab 1", panel1);
JPanel panel2 = new JPanel();
for (int i = 0; i < 5; i++) {
panel2.add(new JCheckBox("CheckBox " + String.valueOf(i + 1)));
}
tabbedPane.addTab("tab 2", panel2);
JPanel panel = new JPanel();
panel.add(tabbedPane);
exceptionString = "AccessibleJTabbedPane test failed!";
createUI(panel, "AccessibleJTabbedPaneTest");
}
public static void main(String[] args) throws Exception {
AccessibleJTabbedPaneTest test = new AccessibleJTabbedPaneTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeLater(test::createTabPane);
countDownLatch.await();
if (!testResult) {
throw new RuntimeException(a11yTest.exceptionString);
}
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8267388
* @summary Test implementation of NSAccessibilityTable protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJTableTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JTable;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccessibleJTableTest extends AccessibleComponentTest {
private static final String[] columnNames = {"One", "Two", "Three"};
private static final String[][] data = {
{"One1", "Two1", "Three1"},
{"One2", "Two2", "Three2"},
{"One3", "Two3", "Three3"},
{"One4", "Two4", "Three4"},
{"One5", "Two5", "Three5"}
};
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
public void createUI() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTable.\n\n"
+ "Turn screen reader on, and Tab to the table.\n"
+ "On Windows press the arrow buttons to move through the table.\n\n"
+ "On MacOS, use the up and down arrow buttons to move through rows, and VoiceOver fast navigation to move through columns.\n\n"
+ "If you can hear table cells ctrl+tab further and press PASS, otherwise press FAIL.\n";
JTable table = new JTable(data, columnNames);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(table);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTable test failed!";
super.createUI(panel, "AccessibleJTableTest");
}
public void createUINamed() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of named JTable.\n\n"
+ "Turn screen reader on, and Tab to the table.\n"
+ "Press the ctrl+tab button to move to second table.\n\n"
+ "If you can hear second table name: \"second table\" - ctrl+tab further and press PASS, otherwise press FAIL.\n";
JTable table = new JTable(data, columnNames);
JTable secondTable = new JTable(data, columnNames);
secondTable.getAccessibleContext().setAccessibleName("Second table");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(table);
JScrollPane secondScrollPane = new JScrollPane(secondTable);
panel.add(scrollPane);
panel.add(secondScrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTable test failed!";
super.createUI(panel, "AccessibleJTableTest");
}
public static void main(String[] args) throws Exception {
AccessibleJTableTest test = new AccessibleJTableTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createUI);
countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createUINamed);
countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
}
}

View File

@@ -0,0 +1,239 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8267387
* @summary Test implementation of NSAccessibilityOutLine protocol peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleJTreeTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JTree;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.SwingUtilities;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.Hashtable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccessibleJTreeTest extends AccessibleComponentTest {
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
public void createSampleTree() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTree.\n\n"
+ "Turn screen reader on, and Tab to the tree.\n"
+ "Press the arrow buttons to move through the tree.\n\n"
+ "If you can hear tree components tab further and press PASS, otherwise press FAIL.\n";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
tree.setRootVisible(true);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTree sample item test failed!";
super.createUI(panel, "AccessibleJTreeTest");
}
public void createSampleTreeUnvisableRoot() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTree with invisible root.\n\n"
+ "Turn screen reader on, and Tab to the tree.\n"
+ "Press the arrow buttons to move through the tree.\n\n"
+ "If you can hear tree components tab further and press PASS, otherwise press FAIL.\n";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTree sample item invisible root test failed!";
super.createUI(panel, "AccessibleJTreeTest");
}
public void createSampleTreeNamed() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of named JTree.\n\n"
+ "Turn screen reader on, and Tab to the tree.\n"
+ "Press the tab button to move to second tree.\\n\n"
+ "If you can hear second tree name: \"second tree\" - tab further and press PASS, otherwise press FAIL.\n";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
JTree secondTree = new JTree(data);
secondTree.getAccessibleContext().setAccessibleName("Second tree");
tree.setRootVisible(true);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
JScrollPane secondScrollPane = new JScrollPane(secondTree);
panel.add(scrollPane);
panel.add(secondScrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTree named test failed!";
super.createUI(panel, "AccessibleJTreeTest");
}
public void createRendererTree() {
INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTree using renderer.\n\n"
+ "Turn screen reader on, and Tab to the tree.\n"
+ "Press the arrow buttons to move through the tree.\n\n"
+ "If you can hear tree components tab further and press PASS, otherwise press FAIL.\n";
String root = "Root";
String[] nodes = new String[] {"One node", "Two node"};
String[][] leafs = new String[][]{{"leaf 1.1", "leaf 1.2", "leaf 1.3", "leaf 1.4"},
{"leaf 2.1", "leaf 2.2", "leaf 2.3", "leaf 2.4"}};
Hashtable<String, String[]> data = new Hashtable<String, String[]>();
for (int i = 0; i < nodes.length; i++) {
data.put(nodes[i], leafs[i]);
}
JTree tree = new JTree(data);
tree.setRootVisible(true);
tree.setCellRenderer(new AccessibleJTreeTestRenderer());
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JScrollPane scrollPane = new JScrollPane(tree);
panel.add(scrollPane);
panel.setFocusable(false);
exceptionString = "AccessibleJTree renderer item test failed!";
super.createUI(panel, "AccessibleJTreeTest");
}
public static void main(String[] args) throws Exception {
AccessibleJTreeTest test = new AccessibleJTreeTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createSampleTree);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createSampleTreeNamed);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createSampleTreeUnvisableRoot);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createRendererTree);
countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(AccessibleComponentTest.exceptionString);
}
}
public static class AccessibleJTreeTestRenderer extends JPanel implements TreeCellRenderer {
private JLabel labelAJT = new JLabel("AJT");
private JLabel itemName = new JLabel();
AccessibleJTreeTestRenderer() {
super(new FlowLayout());
setFocusable(false);
layoutComponents();
}
private void layoutComponents() {
add(labelAJT);
add(itemName);
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
itemName.setText((String) (((DefaultMutableTreeNode) value).getUserObject()));
getAccessibleContext().setAccessibleName(labelAJT.getText() + ", " + itemName.getText());
return this;
}
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
return new Dimension(Math.min(size.width, 245), size.height);
}
}
}

View File

@@ -0,0 +1,293 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8262031
* @summary Test implementation of NSAccessibilityNavigableStaticTest and NSAccessibilityStaticText protocols peer
* @author Artem.Semenov@jetbrains.com
* @run main/manual AccessibleTextTest
* @requires (os.family == "windows" | os.family == "mac")
*/
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AccessibleTextTest extends AccessibleComponentTest {
@Override
public CountDownLatch createCountDownLatch() {
return new CountDownLatch(1);
}
private void createSimpleLabel() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JLabel.\n\n"
+ "Turn screen reader on.\n"
+ "On MacOS, use the VO navigation keys to read the label text;\n"
+ "ON Windows with JAWS, use window virtualization (insert+alt+w and arrows) to read the label text;\n"
+ "ON Windows with NVDA, use the browse cursor (insert+num4 or insert+num6) to read the label text;\n\n"
+ "If you can hear text from label tab further and press PASS, otherwise press FAIL.";
JLabel label = new JLabel("this is a label");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(label);
exceptionString = "Simple label test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createOneLineTexField() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTextField.\n\n"
+ "Turn screen reader on and press Tab to move to the text field and type some characters.\n\n"
+ "If you can hear input results according to your screen reader settings, tab further and press PASS, otherwise press FAIL.";
JTextField textField = new JTextField("some text to edit");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textField);
exceptionString = "Simple text field test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createPassField() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JPasswordField.\n\n"
+ "Turn screen reader on and press Tab to move to the password field and type some characters.\n\n"
+ "If you can hear sounds specific to your screen reader when interacting with password fields, tab further and press PASS, otherwise press FAIL.";
JPasswordField passwordField = new JPasswordField("12345678");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(passwordField);
exceptionString = "Simple passfield field test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createNamedTextField() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of named JTextField.\n\n"
+ "Turn screen reader on and press Tab to move to the text field.\n\n"
+ "If you can hear in addition to the fact that this text field is also the names of these fields, tab further and press PASS, otherwise press FAIL.";
JTextField textField = new JTextField("some text 1");
textField.getAccessibleContext().setAccessibleName("This is the first text field:");
JLabel label = new JLabel("This is the second text field:");
JTextField secondTextField = new JTextField("some text 2");
label.setLabelFor(secondTextField);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textField);
panel.add(label);
panel.add(secondTextField);
exceptionString = "Named text field test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createTextArea() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of JTextArea.\n\n"
+ "Turn screen reader on and press the arrow keys.\n\n"
+ "If you can hear this instructions, tab further and press PASS, otherwise press FAIL.";
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
exceptionString = "Simple text area test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createEditableTextArea() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of editable JTextArea.\n\n"
+ "Turn screen reader on and press Tab to move to the text area and type some characters.\n\n"
+ "If you can hear input results according to your screen reader settings, tab further and press PASS, otherwise press FAIL.";
JTextArea textArea = new JTextArea("some text to edit");
JLabel label = new JLabel(textArea.getText().length() + " chars");
label.setLabelFor(textArea);
textArea.setEditable(true);
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
label.setText(String.valueOf(textArea.getText().length()) + " chars");
}
});
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textArea);
panel.add(label);
exceptionString = "Editable text area test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createTextPane() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of text in JTextPane.\n\n"
+ "Turn screen reader on and press Tab to move to the text pane and press the arrow keys.\n\n"
+ "If you can hear text, tab further and press PASS, otherwise press FAIL.";
String str = "Line 1\nLine 2\nLine 3";
JTextPane textPane = new JTextPane();
textPane.setEditable(false);
textPane.setText(str);
JTextArea textArea = new JTextArea();
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textPane);
exceptionString = "Simple text pane test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createHTMLTextPane() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of html text in JTextPane.\n\n"
+ "Turn screen reader on and press Tab to move to the text pane and press the arrow keys.\n\n"
+ "If you can hear text, tab further and press PASS, otherwise press FAIL.";
String str = "<html><h1>Header</h1><ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul></html>";
JTextPane textPane = new JTextPane();
textPane.setEditable(false);
textPane.setContentType("text/html");
textPane.setText(str);
JTextArea textArea = new JTextArea();
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textPane);
exceptionString = "HTML text pane test failed!";
super.createUI(panel, "AccessibleTextTest");
}
private void createEditableTextPane() {
AccessibleComponentTest.INSTRUCTIONS = "INSTRUCTIONS:\n"
+ "Check a11y of editable JTextPane.\n\n"
+ "Turn screen reader on and press Tab to move to the text pane and type some characters.\n\n"
+ "If you can hear input results according to your screen reader settings, tab further and press PASS, otherwise press FAIL.";
JTextPane textPane = new JTextPane();
textPane.setText("some text to edit");
JLabel label = new JLabel(textPane.getText().length() + " chars");
label.setLabelFor(textPane);
textPane.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
label.setText(String.valueOf(textPane.getText().length()) + " chars");
}
});
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(textPane);
panel.add(label);
exceptionString = "Editable text pane test failed!";
super.createUI(panel, "AccessibleTextTest");
}
public static void main(String[] args) throws Exception {
AccessibleTextTest test = new AccessibleTextTest();
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createSimpleLabel);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createOneLineTexField);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createPassField);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createNamedTextField);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createTextArea);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createEditableTextArea);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createTextPane);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createHTMLTextPane);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
countDownLatch = test.createCountDownLatch();
SwingUtilities.invokeAndWait(test::createEditableTextPane);
AccessibleComponentTest.countDownLatch.await(15, TimeUnit.MINUTES);
if (!testResult) {
throw new RuntimeException(exceptionString);
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8269223
* @summary Verifies that -Xcheck:jni issues no warnings from freetypeScaler.c
* @library /test/lib
* @run main FreeTypeScalerJNICheck
*/
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GraphicsEnvironment;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
public class FreeTypeScalerJNICheck {
public static void main(String[] args) throws Exception {
if (args.length > 0 && args[0].equals("runtest")) {
runTest();
} else {
ProcessBuilder pb = ProcessTools.createTestJvm("-Xcheck:jni", FreeTypeScalerJNICheck.class.getName(), "runtest");
OutputAnalyzer oa = ProcessTools.executeProcess(pb);
oa.shouldContain("Done").shouldNotContain("WARNING").shouldHaveExitValue(0);
}
}
public static void runTest() {
String families[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
for (String ff : families)
{
Font font = new Font(ff, Font.PLAIN, 12);
Rectangle2D bounds = font.getStringBounds("test", g2d.getFontRenderContext());
g2d.setFont(font);
FontMetrics metrics = g2d.getFontMetrics(font);
System.out.println(bounds.getHeight() + metrics.getHeight()); // use bounds and metrics
}
System.out.println("Done");
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary Verifies that the launcher doesn't unnecessarily set LD_LIBRARY_PATH on
* non-musl-based systems.
* @requires (os.family == "linux")
* @library /test/lib
* @run main MuslCheck
*/
import java.util.Map;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
public class MuslCheck extends TestHelper {
public static void main(String[] args) throws Exception {
final Map<String, String> envMap = Map.of("_JAVA_LAUNCHER_DEBUG", "true");
TestResult tr = doExec(envMap, javaCmd, "-help");
if (!tr.contains("mustsetenv:")) {
throw new RuntimeException("Test error: the necessary tracing is missing in the output");
}
if (!tr.contains("micro seconds to check for the musl compatibility layer for glibc")) {
throw new RuntimeException("The check for libgcompat seems to be missing");
}
if (tr.contains("mustsetenv: TRUE")) {
throw new RuntimeException("launcher is not supposed to set LD_LIBRARY_PATH");
}
}
}