Compare commits

..

20 Commits

Author SHA1 Message Date
Roger Riggs
f51e55a20f 8269850: Most JDK releases report macOS version 12 as 10.16 instead of 12.0
Reviewed-by: naoto, clanger
(cherry picked from commit 3b1b8fc646)
(AKA JBR-3804 Cherry-pick 8269850 from OpenJDK11)
2021-09-24 09:09:10 +03:00
Dmitry Batrak
e68d154a63 JBR-3799 Broken input of supplementary plane Unicode characters on macOS
apply upstream fix (JDK-8272602)

(cherry picked from commit 7d915be754)
2021-09-22 15:20:21 +03:00
Dmitry
b526f948ff JBR-3793 Accept unrecognized options and make them available in Java
This patch:

- Change default behavior to ignore unrecognized options (+IgnoreUnrecognizedVMOptions)

- Store all ignored values to: "java.vm.unrecognized.options" as "+BogusOption01 +BogusOption02" (space separated), see testcase

- Explicitly set -IgnoreUnrecognizedVMOptions for couple of tests, that rely on default behavior
2021-09-21 18:47:56 +03:00
Dmitry Batrak
fdbb6f02b8 improve the stability of TypeaheadRequestFocusTest
it failed sometimes under MATE desktop environment on Linux

(cherry picked from commit 37901295e1)
2021-09-21 13:04:10 +03:00
Ivan Migalev
6743f36c32 JBR-3785: don't touch the active keyboard layout on input method activation / deactivation.
origin PR: github.com/JetBrains/JetBrainsRuntime/pull/78.

(cherry picked from commit 2f772fd1a2)
2021-09-21 09:45:55 +01:00
Vitaly Provodin
f706b93717 exclude tests failing due to JDK-8253184 2021-09-21 12:04:20 +07:00
Dmitry Batrak
6f046e9f68 make NestedDialogHideTest more reliable
currently, if fails on KDE, if multiple workspaces are configured, because mouse cursor happens to be located over 'pin' button in window title bar,
and that hover causes a tooltip to be shown, which blocks mouse clicks

(cherry picked from commit ad1595b5c2)
2021-09-20 18:21:26 +03:00
Dmitry Batrak
bac641fe77 JBR-3786 javax/swing/plaf/aqua/CustomComboBoxFocusTest.java fails on MacOS by timeout
(cherry picked from commit f5c5388fb5)
2021-09-20 17:27:07 +03:00
Dmitry Batrak
8dfcb3fd5a JBR-3779 Unexpected Alt+Tab behaviour for Java frames on Cinnamon DE
(cherry picked from commit 0bf13985d5)
2021-09-20 12:27:42 +03:00
Maxim Kartashev
ef651ca1bb JBR-3688 PyCharm incredibly slow with fakexrandr
Cache screen bounds and insets and (conservatively) reset those caches
upon any possibility of a change.
This feature can be disabled with -Dx11.cache.screen.insets=false and
-Dx11.cache.screen.bounds=false.

Based on commit accef6f21e.
2021-09-20 10:55:38 +03:00
Maxim Kartashev
3092ca0461 JBR-3772 java/beans/PropertyEditor/TestFontClass.java: access denied ("java.util.PropertyPermission" "sun.awt.x11.trace" "read")
Instead of using System.getProperty() directly, wrap the call into
GetPropertyAction and use AccessController to execute it.
2021-09-16 09:19:54 +03:00
Dmitry Batrak
3caa06a639 JBR-3726 Modal windows 'disappear' on minimize in KDE
revert changes not needed anymore

(cherry picked from commit f0ed32fca4)
2021-09-14 18:41:53 +03:00
Dmitry Batrak
6c50ed6690 JBR-3726 Modal windows 'disappear' on minimize in KDE
re-implement the fix without using _NET_WM_STATE_MODAL - it causes other issues

(cherry picked from commit 5c4fd9ceaf)
2021-09-14 18:41:45 +03:00
Nikita Gubarkov
805a5b4f75 Add ExtendedGlyphCache and remove SampleJBRApi from JBR API 2021-09-13 16:47:25 +03:00
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
105 changed files with 5798 additions and 557 deletions

View File

@@ -117,6 +117,8 @@ bool Arguments::_has_jimage = false;
char* Arguments::_ext_dirs = NULL;
GrowableArray<const char *> *Arguments::_unrecognized_vm_options = NULL;
bool PathString::set_value(const char *value) {
if (_value != NULL) {
FreeHeap(_value);
@@ -132,7 +134,7 @@ bool PathString::set_value(const char *value) {
return true;
}
void PathString::append_value(const char *value) {
void PathString::append_value(const char *value, const char *separator) {
char *sp;
size_t len = 0;
if (value != NULL) {
@@ -145,7 +147,7 @@ void PathString::append_value(const char *value) {
if (sp != NULL) {
if (_value != NULL) {
strcpy(sp, _value);
strcat(sp, os::path_separator());
strcat(sp, separator);
strcat(sp, value);
FreeHeap(_value);
} else {
@@ -1217,8 +1219,10 @@ bool Arguments::process_argument(const char* arg,
}
} else {
if (ignore_unrecognized) {
store_unrecognized_vm_option(arg);
return true;
}
jio_fprintf(defaultStream::error_stream(),
"Unrecognized VM option '%s'\n", argname);
JVMFlag* fuzzy_matched = JVMFlag::fuzzy_match((const char*)argname, arg_len, true);
@@ -1229,7 +1233,7 @@ bool Arguments::process_argument(const char* arg,
fuzzy_matched->name(),
(fuzzy_matched->is_bool()) ? "" : "=<value>");
}
}
}
// allow for commandline "commenting out" options like -XX:#+Verbose
return arg[0] == '#';
@@ -2017,9 +2021,38 @@ bool Arguments::check_vm_args_consistency() {
return status;
}
void Arguments::set_unrecognized_vm_options_property() {
if (_unrecognized_vm_options != NULL) {
int num_of_entries = _unrecognized_vm_options->length();
const char* option_string = _unrecognized_vm_options->at(0);
SystemProperty* prop = new SystemProperty("java.vm.unrecognized.options", "", true, false);
prop->set_value(option_string);
for (int i = 1; i < num_of_entries; i++) {
option_string = _unrecognized_vm_options->at(i);
prop->append_value(option_string, "\n");
}
PropertyList_add(&_system_properties, prop);
}
}
void Arguments::store_unrecognized_vm_option(const char* option) {
if (_unrecognized_vm_options == NULL) {
// Create GrowableArray lazily, only if unrecognized vm options found
_unrecognized_vm_options = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<const char *>(10, mtArguments);
}
_unrecognized_vm_options->push(option);
}
bool Arguments::is_bad_option(const JavaVMOption* option, jboolean ignore,
const char* option_type) {
if (ignore) return false;
if (ignore) {
store_unrecognized_vm_option(option->optionString);
return false;
}
const char* spacer = " ";
if (option_type == NULL) {

View File

@@ -62,7 +62,8 @@ class PathString : public CHeapObj<mtArguments> {
char* value() const { return _value; }
bool set_value(const char *value);
void append_value(const char *value);
void append_value(const char *value, const char *delemiter);
void append_value(const char *value) { append_value(value, os::path_separator()); }
PathString(const char* value);
~PathString();
@@ -346,6 +347,10 @@ class Arguments : AllStatic {
static void set_xdebug_mode(bool arg) { _xdebug_mode = arg; }
static bool xdebug_mode() { return _xdebug_mode; }
// List of unrecognized VM options
static GrowableArray<const char *> *_unrecognized_vm_options;
static void store_unrecognized_vm_option(const char* option);
// preview features
static bool _enable_preview;
@@ -559,6 +564,9 @@ class Arguments : AllStatic {
// Update/Initialize System properties after JDK version number is known
static void init_version_specific_system_properties();
// Store unrecognized vm options to system property
static void set_unrecognized_vm_options_property();
// Update VM info property - called after argument parsing
static void update_vm_info_property(const char* vm_info) {
_vm_info->set_value(vm_info);

View File

@@ -1051,7 +1051,7 @@ const intx ObjectAlignmentInBytes = 8;
product(bool, PrintVMOptions, false, \
"Print flags that appeared on the command line") \
\
product(bool, IgnoreUnrecognizedVMOptions, false, \
product(bool, IgnoreUnrecognizedVMOptions, true, \
"Ignore unrecognized VM options") \
\
product(bool, PrintCommandLineFlags, false, \

View File

@@ -2748,6 +2748,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
jint parse_result = Arguments::parse(args);
if (parse_result != JNI_OK) return parse_result;
// Store all unrecognized vm options to system property
// to make it accessible from Java
Arguments::set_unrecognized_vm_options_property();
os::init_before_ergo();
jint ergo_result = Arguments::apply_ergo();

View File

@@ -234,6 +234,7 @@ void setOSNameAndVersion(java_props_t *sprops) {
// Hardcode os_name, and fill in os_version
sprops->os_name = strdup("Mac OS X");
NSString *nsVerStr = NULL;
char* osVersionCStr = NULL;
// Mac OS 10.9 includes the [NSProcessInfo operatingSystemVersion] function,
// but it's not in the 10.9 SDK. So, call it via NSInvocation.
@@ -246,7 +247,6 @@ void setOSNameAndVersion(java_props_t *sprops) {
[invoke invokeWithTarget:[NSProcessInfo processInfo]];
[invoke getReturnValue:&osVer];
NSString *nsVerStr;
// Copy out the char* if running on version other than 10.16 Mac OS (10.16 == 11.x)
// or explicitly requesting version compatibility
if (!((long)osVer.majorVersion == 10 && (long)osVer.minorVersion >= 16) ||
@@ -258,36 +258,30 @@ void setOSNameAndVersion(java_props_t *sprops) {
nsVerStr = [NSString stringWithFormat:@"%ld.%ld.%ld",
(long)osVer.majorVersion, (long)osVer.minorVersion, (long)osVer.patchVersion];
}
// Copy out the char*
osVersionCStr = strdup([nsVerStr UTF8String]);
} else {
// Version 10.16, without explicit env setting of SYSTEM_VERSION_COMPAT
// AKA 11.x; compute the version number from the letter in the ProductBuildVersion
// AKA 11+ Read the *real* ProductVersion from the hidden link to avoid SYSTEM_VERSION_COMPAT
// If not found, fallback below to the SystemVersion.plist
NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile :
@"/System/Library/CoreServices/SystemVersion.plist"];
@"/System/Library/CoreServices/.SystemVersionPlatform.plist"];
if (version != NULL) {
NSString *nsBuildVerStr = [version objectForKey : @"ProductBuildVersion"];
if (nsBuildVerStr != NULL && nsBuildVerStr.length >= 3) {
int letter = [nsBuildVerStr characterAtIndex:2];
if (letter >= 'B' && letter <= 'Z') {
int vers = letter - 'A' - 1;
asprintf(&osVersionCStr, "11.%d", vers);
}
}
nsVerStr = [version objectForKey : @"ProductVersion"];
}
}
}
// Fallback if running on pre-10.9 Mac OS
if (osVersionCStr == NULL) {
if (nsVerStr == NULL) {
NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile :
@"/System/Library/CoreServices/SystemVersion.plist"];
if (version != NULL) {
NSString *nsVerStr = [version objectForKey : @"ProductVersion"];
if (nsVerStr != NULL) {
osVersionCStr = strdup([nsVerStr UTF8String]);
}
nsVerStr = [version objectForKey : @"ProductVersion"];
}
}
if (nsVerStr != NULL) {
// Copy out the char*
osVersionCStr = strdup([nsVerStr UTF8String]);
}
if (osVersionCStr == NULL) {
osVersionCStr = strdup("Unknown");
}

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

@@ -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

@@ -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

@@ -40,11 +40,18 @@ NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {
}
jstring NSStringToJavaString(JNIEnv* env, NSString *str) {
if (str == NULL) {
return NULL;
}
jstring jStr = (*env)->NewStringUTF(env, [str UTF8String]);
jsize len = [str length];
unichar *buffer = (unichar*)calloc(len, sizeof(unichar));
if (buffer == NULL) {
return NULL;
}
NSRange crange = NSMakeRange(0, len);
[str getCharacters:buffer range:crange];
jstring jStr = (*env)->NewString(env, buffer, len);
free(buffer);
CHECK_EXCEPTION();
return jStr;
}

View File

@@ -122,6 +122,8 @@ module java.desktop {
exports sun.awt.dnd to jdk.unsupported.desktop;
exports sun.swing to jdk.unsupported.desktop;
exports sun.font to jetbrains.api.impl;
opens javax.swing.plaf.basic to
jdk.jconsole;

View File

@@ -110,13 +110,6 @@ 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

@@ -168,8 +168,6 @@ public class XBaseWindow {
// Set WM_CLIENT_LEADER property
initClientLeader();
initUserTimeWindow();
}
/**
@@ -441,13 +439,6 @@ public class XBaseWindow {
}
}
private void initUserTimeWindow() {
XNETProtocol netProtocol = XWM.getWM().getNETProtocol();
if (netProtocol != null ) {
netProtocol.setupUserTimeWindow(this);
}
}
static XRootWindow getXAWTRootWindow() {
return XRootWindow.getInstance();
}
@@ -1314,12 +1305,18 @@ public class XBaseWindow {
}
protected void setUserTime(long time, boolean updateGlobalTime) {
setUserTime(time, updateGlobalTime, true);
}
protected void setUserTime(long time, boolean updateGlobalTime, boolean updateWindowProperty) {
if (updateGlobalTime && (int)time - (int)globalUserTime > 0 /* accounting for wrap-around */) {
globalUserTime = time;
}
XNETProtocol netProtocol = XWM.getWM().getNETProtocol();
if (netProtocol != null) {
netProtocol.setUserTime(this, time);
if (updateWindowProperty) {
XNETProtocol netProtocol = XWM.getWM().getNETProtocol();
if (netProtocol != null) {
netProtocol.setUserTime(this, time);
}
}
}

View File

@@ -1072,10 +1072,13 @@ abstract class XDecoratedPeer extends XWindowPeer {
XClientMessageEvent cl = xev.get_xclient();
if ((wm_protocols != null) && (cl.get_message_type() == wm_protocols.getAtom())) {
long timestamp = getTimeStampFromClientMessage(cl);
// we should treat WM_TAKE_FOCUS and WM_DELETE_WINDOW messages as user interaction, as they can originate
// We should treat WM_TAKE_FOCUS and WM_DELETE_WINDOW messages as user interaction, as they can originate
// e.g. from user clicking on window title bar and window close button correspondingly
// (there will be no ButtonPress/ButtonRelease events in those cases)
setUserTime(timestamp, true);
// (there will be no ButtonPress/ButtonRelease events in those cases).
// The received timestamp will be used to set _NET_WM_USER_TIME on newly opened windows to ensure their
// correct focusing/positioning, but we don't set it on current window to avoid race conditions (when e.g.
// WM_TAKE_FOCUS arrives around the time of new window opening).
setUserTime(timestamp, true, false);
if (cl.get_data(0) == wm_delete_window.getAtom()) {
handleQuit();

View File

@@ -63,19 +63,11 @@ class XDialogPeer extends XDecoratedPeer implements DialogPeer {
try {
Dialog target = (Dialog)this.target;
if (vis) {
boolean modal = target.getModalityType() != Dialog.ModalityType.MODELESS;
if (modal) {
if (target.getModalityType() != Dialog.ModalityType.MODELESS) {
if (!isModalBlocked()) {
XBaseWindow.ungrabInput();
}
}
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;
@@ -163,4 +155,25 @@ class XDialogPeer extends XDecoratedPeer implements DialogPeer {
}
return super.isFocusedWindowModalBlocker();
}
@Override
public void handleUnmapNotifyEvent(XEvent xev) {
super.handleUnmapNotifyEvent(xev);
if (visible && ((Dialog)target).isModal() && XWM.getWMID() == XWM.KDE2_WM) {
// the case of modal dialog window being minimized (iconified) on KDE
// (other WMs don't seem to allow minimizing)
Vector<XWindowPeer> windowPeers = collectJavaToplevels();
for (XWindowPeer peer : windowPeers) {
if (peer.modalBlocker == target) {
XToolkit.awtLock();
try {
XlibWrapper.XIconifyWindow(XToolkit.getDisplay(), peer.getWindow(), peer.getScreenNumber());
}
finally {
XToolkit.awtUnlock();
}
}
}
}
}
}

View File

@@ -293,7 +293,6 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt
XAtom XA_NET_WM_WINDOW_OPACITY = XAtom.get("_NET_WM_WINDOW_OPACITY");
XAtom XA_NET_WM_USER_TIME = XAtom.get("_NET_WM_USER_TIME");
XAtom XA_NET_WM_USER_TIME_WINDOW = XAtom.get("_NET_WM_USER_TIME_WINDOW");
/* For _NET_WM_STATE ClientMessage requests */
static final int _NET_WM_STATE_REMOVE =0; /* remove/unset property */
@@ -466,20 +465,9 @@ final class XNETProtocol extends XProtocol implements XStateProtocol, XLayerProt
return (state != null && state.size() != 0 && state.contains(XA_NET_WM_STATE_HIDDEN));
}
private boolean isUserTimeWindowSupported() {
return checkProtocol(XA_NET_SUPPORTED, XA_NET_WM_USER_TIME_WINDOW);
}
void setupUserTimeWindow(XBaseWindow window) {
if (active() && isUserTimeWindowSupported()) {
XA_NET_WM_USER_TIME_WINDOW.setWindowProperty(window, XRootWindow.getInstance());
}
}
void setUserTime(XBaseWindow window, long time) {
if (active()) {
XBaseWindow target = isUserTimeWindowSupported() ? XRootWindow.getInstance() : window;
XA_NET_WM_USER_TIME.setCard32Property(target, time);
XA_NET_WM_USER_TIME.setCard32Property(window, time);
}
}
}

View File

@@ -119,6 +119,7 @@ import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
@@ -187,7 +188,9 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
}
static {
final String trace = System.getProperty("sun.awt.x11.trace");
final GetPropertyAction gpa = new GetPropertyAction("sun.awt.x11.trace");
@SuppressWarnings("removal")
final String trace = AccessController.doPrivileged(gpa);
if (trace != null) {
int traceFlags = 0;
final StringTokenizer st = new StringTokenizer(trace, ",");
@@ -644,9 +647,15 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
try {
((X11GraphicsEnvironment)GraphicsEnvironment.
getLocalGraphicsEnvironment()).rebuildDevices();
if (useCachedInsets) resetScreenInsetsCache();
} finally {
awtLock();
}
} else if (useCachedInsets) {
final XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA");
final boolean rootWindowWorkareaResized = (ev.get_type() == XConstants.PropertyNotify
&& ev.get_xproperty().get_atom() == XA_NET_WORKAREA.getAtom());
if (rootWindowWorkareaResized) resetScreenInsetsCache();
}
}
});
@@ -1153,8 +1162,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
* When two screens overlap and the first contains a dock(*****), then
* _NET_WORKAREA may start at point x1,y1 and end at point x2,y2.
*/
@Override
public Insets getScreenInsets(final GraphicsConfiguration gc) {
private Insets getScreenInsetsImpl(final GraphicsConfiguration gc) {
GraphicsDevice gd = gc.getDevice();
XNETProtocol np = XWM.getWM().getNETProtocol();
if (np == null || !(gd instanceof X11GraphicsDevice) || !np.active()) {
@@ -1182,6 +1190,20 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
}
}
private final Hashtable<GraphicsConfiguration, Insets> cachedInsets = new Hashtable<>();
private void resetScreenInsetsCache() {
cachedInsets.clear();
}
@Override
public Insets getScreenInsets(final GraphicsConfiguration gc) {
if (useCachedInsets) {
return cachedInsets.computeIfAbsent(gc, this::getScreenInsetsImpl);
} else {
return getScreenInsetsImpl(gc);
}
}
/*
* The current implementation of disabling background erasing for
* canvases is that we don't set any native background color
@@ -2906,4 +2928,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
public static boolean getSunAwtDisableGrab() {
return AccessController.doPrivileged(new GetBooleanAction("sun.awt.disablegrab"));
}
@SuppressWarnings("removal")
private static final boolean useCachedInsets = Boolean.parseBoolean(AccessController.doPrivileged(
new GetPropertyAction("x11.cache.screen.insets", "true")));
}

View File

@@ -38,6 +38,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
import sun.security.action.GetPropertyAction;
import sun.awt.util.ThreadGroupUtils;
import sun.java2d.SunGraphicsEnvironment;
@@ -136,7 +137,7 @@ public final class X11GraphicsDevice extends GraphicsDevice
return Region.clipRound(x / (double)getScaleFactor());
}
public Rectangle getBounds() {
private Rectangle getBoundsImpl() {
Rectangle rect = pGetBounds(getScreen());
if (getScaleFactor() != 1) {
rect.x = scaleDown(rect.x);
@@ -147,6 +148,28 @@ public final class X11GraphicsDevice extends GraphicsDevice
return rect;
}
private Rectangle boundsCached;
private synchronized Rectangle getBoundsCached() {
if (boundsCached == null) {
boundsCached = getBoundsImpl();
}
return boundsCached;
}
public synchronized void resetBoundsCache() {
boundsCached = null;
}
public Rectangle getBounds() {
if (X11GraphicsEnvironment.useBoundsCache()) {
return getBoundsCached();
}
else {
return getBoundsImpl();
}
}
/**
* Returns the identification string associated with this graphics
* device.
@@ -633,5 +656,6 @@ public final class X11GraphicsDevice extends GraphicsDevice
public void invalidate(X11GraphicsDevice device) {
screen = device.screen;
if (X11GraphicsEnvironment.useBoundsCache()) resetBoundsCache();
}
}

View File

@@ -38,6 +38,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.security.AccessController;
import sun.security.action.GetPropertyAction;
import sun.awt.X11.XToolkit;
import sun.java2d.SunGraphicsEnvironment;
@@ -254,6 +256,12 @@ public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
it.remove();
}
}
if (useBoundsCache()) {
for (final X11GraphicsDevice gd : devices.values()) {
gd.resetBoundsCache();
}
}
}
@Override
@@ -378,4 +386,12 @@ public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
@Override
public void paletteChanged() {
}
@SuppressWarnings("removal")
private static final boolean cacheScreenBoundsValue = Boolean.parseBoolean(AccessController.doPrivileged(
new GetPropertyAction("x11.cache.screen.bounds", "true")));
public static boolean useBoundsCache() {
return cacheScreenBoundsValue;
}
}

View File

@@ -1335,9 +1335,12 @@ static int getRemoteX11WorkaroundProperty() {
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jstring name = (*env)->NewStringUTF(env, WORKAROUND_PROPERTY_NAME);
CHECK_NULL_RETURN(name, ret);
jstring jPropValue = JNU_CallStaticMethodByName(env, NULL, "java/lang/System", "getProperty",
"(Ljava/lang/String;)Ljava/lang/String;", name).l;
if (jPropValue != NULL) {
jobject jPropGetAction = JNU_NewObjectByName(env, "sun/security/action/GetPropertyAction", "(Ljava/lang/String;)V", name);
CHECK_NULL_RETURN(name, ret);
jboolean ignoreExc;
jstring jPropValue = JNU_CallStaticMethodByName(env, &ignoreExc, "java/security/AccessController", "doPrivileged",
"(Ljava/security/PrivilegedAction;)Ljava/lang/Object;", jPropGetAction).l;
if (jPropValue != NULL && JNU_IsInstanceOfByName(env, jPropValue, "java/lang/String")) {
const char * utf8string = (*env)->GetStringUTFChars(env, jPropValue, NULL);
if (utf8string != NULL) {
if (strcmp(utf8string, "true") == 0) {
@@ -1348,7 +1351,6 @@ static int getRemoteX11WorkaroundProperty() {
}
(*env)->ReleaseStringUTFChars(env, jPropValue, utf8string);
}
(*env)->DeleteLocalRef(env, name);
return ret;
}

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

@@ -168,10 +168,6 @@ final class WInputMethod extends InputMethodAdapter
@Override
public boolean setLocale(Locale lang) {
return setLocale(lang, false);
}
private boolean setLocale(Locale lang, boolean onActivate) {
Locale[] available = WInputMethodDescriptor.getAvailableLocalesInternal();
for (int i = 0; i < available.length; i++) {
Locale locale = available[i];
@@ -180,7 +176,7 @@ final class WInputMethod extends InputMethodAdapter
locale.equals(Locale.JAPAN) && lang.equals(Locale.JAPANESE) ||
locale.equals(Locale.KOREA) && lang.equals(Locale.KOREAN)) {
if (isActive) {
setNativeLocale(locale.toLanguageTag(), onActivate);
setNativeLocale(locale.toLanguageTag());
}
currentLocale = locale;
return true;
@@ -319,9 +315,6 @@ final class WInputMethod extends InputMethodAdapter
isLastFocussedActiveClient = isAc;
}
isActive = true;
if (currentLocale != null) {
setLocale(currentLocale, true);
}
// Compare IM's composition string with Java's composition string
if (hasCompositionString && !isCompositionStringAvailable(context)) {
@@ -348,10 +341,6 @@ final class WInputMethod extends InputMethodAdapter
@Override
public void deactivate(boolean isTemporary)
{
// Sync currentLocale with the Windows keyboard layout which might be changed
// by hot key
getLocale();
// Delay calling disableNativeIME until activate is called and the newly
// focussed component has a different peer as the last focussed component.
if (awtFocussedComponentPeer != null) {
@@ -667,7 +656,7 @@ final class WInputMethod extends InputMethodAdapter
private native void setStatusWindowVisible(WComponentPeer peer, boolean visible);
private native String getNativeIMMDescription();
static native Locale getNativeLocale();
static native boolean setNativeLocale(String localeName, boolean onActivate);
static native boolean setNativeLocale(String localeName);
private native void openCandidateWindow(WComponentPeer peer, int x, int y);
private native boolean isCompositionStringAvailable(int context);
}

View File

@@ -87,15 +87,6 @@ static DCList passiveDCList;
extern void CheckFontSmoothingSettings(HWND);
extern "C" {
// Remember the input language has changed by some user's action
// (Alt+Shift or through the language icon on the Taskbar) to control the
// race condition between the toolkit thread and the AWT event thread.
// This flag remains TRUE until the next WInputMethod.getNativeLocale() is
// issued.
BOOL g_bUserHasChangedInputLang = FALSE;
}
BOOL AwtComponent::sm_suppressFocusAndActivation = FALSE;
BOOL AwtComponent::sm_restoreFocusAndActivation = FALSE;
HWND AwtComponent::sm_focusOwner = NULL;
@@ -1847,9 +1838,6 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
::ToAsciiEx(VK_SPACE, ::MapVirtualKey(VK_SPACE, 0),
keyboardState, &ignored, 0, GetKeyboardLayout());
// Set this flag to block ActivateKeyboardLayout from
// WInputMethod.activate()
g_bUserHasChangedInputLang = TRUE;
CallProxyDefWindowProc(message, wParam, lParam, retValue, mr);
break;
}
@@ -1858,7 +1846,6 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
"new = 0x%08X",
GetHWnd(), GetClassName(), (UINT)lParam);
mr = WmInputLangChange(static_cast<UINT>(wParam), reinterpret_cast<HKL>(lParam));
g_bUserHasChangedInputLang = TRUE;
CallProxyDefWindowProc(message, wParam, lParam, retValue, mr);
// should return non-zero if we process this message
retValue = 1;

View File

@@ -44,8 +44,6 @@ extern "C" {
jobject CreateLocaleObject(JNIEnv *env, const char * name);
HKL getDefaultKeyboardLayout();
extern BOOL g_bUserHasChangedInputLang;
/*
* Class: sun_awt_windows_WInputMethod
* Method: createNativeContext
@@ -292,10 +290,6 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_WInputMethod_getNativeLocale
const char * javaLocaleName = getJavaIDFromLangID(AwtComponent::GetInputLanguage());
if (javaLocaleName != NULL) {
// Now WInputMethod.currentLocale and AwtComponent::m_idLang are get sync'ed,
// so we can reset this flag.
g_bUserHasChangedInputLang = FALSE;
jobject ret = CreateLocaleObject(env, javaLocaleName);
free((void *)javaLocaleName);
return ret;
@@ -309,10 +303,10 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_WInputMethod_getNativeLocale
/*
* Class: sun_awt_windows_WInputMethod
* Method: setNativeLocale
* Signature: (Ljava/lang/String;Z)Z
* Signature: (Ljava/lang/String;)Z
*/
JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WInputMethod_setNativeLocale
(JNIEnv *env, jclass cls, jstring localeString, jboolean onActivate)
(JNIEnv *env, jclass cls, jstring localeString)
{
TRY;
@@ -353,7 +347,7 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WInputMethod_setNativeLocale
if (supported != NULL) {
if (strcmp(supported, requested) == 0) {
// use special message to call ActivateKeyboardLayout() in main thread.
if (AwtToolkit::GetInstance().SendMessage(WM_AWT_ACTIVATEKEYBOARDLAYOUT, (WPARAM)onActivate, (LPARAM)hKLList[i])) {
if (AwtToolkit::GetInstance().SendMessage(WM_AWT_ACTIVATEKEYBOARDLAYOUT, 0, (LPARAM)hKLList[i])) {
//also need to change the same keyboard layout for the Java AWT-EventQueue thread
AwtToolkit::activateKeyboardLayout(hKLList[i]);
retValue = JNI_TRUE;

View File

@@ -71,7 +71,6 @@ extern void initScreens(JNIEnv *env);
extern "C" void awt_dnd_initialize();
extern "C" void awt_dnd_uninitialize();
extern "C" void awt_clipboard_uninitialize(JNIEnv *env);
extern "C" BOOL g_bUserHasChangedInputLang;
extern CriticalSection windowMoveLock;
extern BOOL windowMoveLockHeld;
@@ -1218,14 +1217,6 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message,
return cmode;
}
case WM_AWT_ACTIVATEKEYBOARDLAYOUT: {
if (wParam && g_bUserHasChangedInputLang) {
// Input language has been changed since the last WInputMethod.getNativeLocale()
// call. So let's honor the user's selection.
// Note: we need to check this flag inside the toolkit thread to synchronize access
// to the flag.
return FALSE;
}
if (lParam == (LPARAM)::GetKeyboardLayout(0)) {
// already active
return FALSE;

View File

@@ -0,0 +1,38 @@
/*
* 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.
*
* 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.
*/
package com.jetbrains.impl;
import com.jetbrains.ExtendedGlyphCache;
import java.awt.*;
import sun.font.FontUtilities;
public class ExtendedGlyphCacheImpl implements ExtendedGlyphCache.V1 {
@Override
public Dimension getSubpixelResolution() {
return FontUtilities.subpixelResolution;
}
}

View File

@@ -1,18 +0,0 @@
package com.jetbrains.impl;
import com.jetbrains.SampleJBRApi;
// Here we just implement latest API version
public class SampleJBRApiImpl implements SampleJBRApi.V2 {
@Override
public void someMethod1(SomeDataClass arg) {
}
@Override
public SomeDataClass someMethod2() {
return new SomeDataClass();
}
}

View File

@@ -15,7 +15,7 @@
*/
import com.jetbrains.JBRService;
import com.jetbrains.impl.SampleJBRApiImpl;
import com.jetbrains.impl.*;
module jetbrains.api.impl {
@@ -23,6 +23,6 @@ module jetbrains.api.impl {
// We probably don't want to add `provides with` for each version of API, so we just provide `JBRService`
// implementation, `JBRService#load` will take care of the rest
provides JBRService with SampleJBRApiImpl;
provides JBRService with ExtendedGlyphCacheImpl;
}

View File

@@ -0,0 +1,38 @@
/*
* 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.
*
* 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.
*/
package com.jetbrains;
import java.awt.*;
public interface ExtendedGlyphCache extends JBRService {
interface V1 extends ExtendedGlyphCache {
Dimension getSubpixelResolution();
}
}

View File

@@ -1,27 +0,0 @@
package com.jetbrains;
// SampleJBRApi is a base of our feature API, it's just a marker interface extending JBRService
public interface SampleJBRApi extends JBRService {
// And actual API goes from V1
interface V1 extends SampleJBRApi {
void someMethod1(SomeDataClass arg);
class SomeDataClass {
public SomeDataClass() {}
}
}
// When we need to add something to our API, we create interface for a new version, extending previous one
interface V2 extends V1 {
SomeDataClass someMethod2();
}
}

View File

@@ -18,6 +18,8 @@ import com.jetbrains.JBRService;
module jetbrains.api {
requires transitive java.desktop;
exports com.jetbrains;
uses JBRService;

View File

@@ -42,6 +42,7 @@ public class TestUnrecognizedVMOptionsHandling {
public static void main(String args[]) throws Exception {
// The first two JAVA processes are expected to fail, but with a correct VM option suggestion
ProcessBuilder pb = GCArguments.createJavaProcessBuilder(
"-XX:-IgnoreUnrecognizedVMOptions",
"-XX:+UseDynamicNumberOfGcThreads",
"-version"
);
@@ -52,6 +53,7 @@ public class TestUnrecognizedVMOptionsHandling {
}
pb = GCArguments.createJavaProcessBuilder(
"-XX:-IgnoreUnrecognizedVMOptions",
"-XX:MaxiumHeapSize=500m",
"-version"
);
@@ -63,6 +65,7 @@ public class TestUnrecognizedVMOptionsHandling {
// The last JAVA process should run successfully for the purpose of sanity check
pb = GCArguments.createJavaProcessBuilder(
"-XX:-IgnoreUnrecognizedVMOptions",
"-XX:+UseDynamicNumberOfGCThreads",
"-version"
);

View File

@@ -36,7 +36,7 @@ public class TestUnrecognizedVmOption {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-showversion", "-XX:" + OPTION);
"-showversion", "-XX:-IgnoreUnrecognizedVMOptions", "-XX:" + OPTION);
new OutputAnalyzer(pb.start())
.shouldNotHaveExitValue(0)
.shouldContain("Unrecognized VM option")

View File

@@ -46,7 +46,7 @@ public class ConfigFileWarning {
pw.println("aaa");
pw.close();
pb = ProcessTools.createJavaProcessBuilder("-XX:Flags=hs_flags.txt","-version");
pb = ProcessTools.createJavaProcessBuilder("-XX:Flags=hs_flags.txt","-XX:-IgnoreUnrecognizedVMOptions","-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("Unrecognized VM option 'aaa'");
output.shouldHaveExitValue(1);

View File

@@ -42,7 +42,7 @@ public class TestLongUnrecognizedVMOption {
public static void main(String[] args) throws Exception {
OutputAnalyzer output;
output = new OutputAnalyzer(ProcessTools.createJavaProcessBuilder("-XX:" + VERY_LONG_OPTION, "-version").start());
output = new OutputAnalyzer(ProcessTools.createJavaProcessBuilder("-XX:" + VERY_LONG_OPTION,"-XX:-IgnoreUnrecognizedVMOptions","-version").start());
output.shouldHaveExitValue(1);
output.shouldContain(String.format("Unrecognized VM option '%s'", VERY_LONG_OPTION));
}

View File

@@ -57,7 +57,7 @@ public class TestNullTerminatedFlags {
for (String option : options) {
String testOption = option + "junk";
ProcessBuilder pb =
ProcessTools.createJavaProcessBuilder(testOption, "-version");
ProcessTools.createJavaProcessBuilder(testOption, "-XX:-IgnoreUnrecognizedVMOptions", "-version");
new OutputAnalyzer(pb.start())
.shouldContain("Unrecognized option: " + testOption)
.shouldHaveExitValue(1);

View File

@@ -44,7 +44,7 @@ public class UnrecognizedVMOption {
};
for (String option : badOptions) {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-XX:" + option, "-version");
"-XX:" + option, "-XX:-IgnoreUnrecognizedVMOptions", "-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("Unrecognized VM option '" + option + "'");

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. 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 8006298 8204055
* @summary Using an unrecognized VM option should print the name of the option
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xverify:BadV -XX-BadSyn -Bad -XX:+BadXX01 -XX:+BadXX02 -XX:+Bad:SC UnrecognizedVMOptionsProperty
*/
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
public class UnrecognizedVMOptionsProperty {
public static void main(String[] args) throws Exception {
String badOptions = System.getProperty("java.vm.unrecognized.options");
System.out.println("Found unrecognized VM options " + badOptions);
if (! badOptions.equals("-Xverify:BadV\n-XX-BadSyn\n-Bad\n+BadXX01\n+BadXX02\n+Bad:SC")) {
throw new RuntimeException("Invalid value of 'java.vm.unrecognized.options' property '" + badOptions + "'");
}
}
}

View File

@@ -37,7 +37,7 @@ import jdk.test.lib.Platform;
public class VMOptionWarning {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-version");
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-XX:-IgnoreUnrecognizedVMOptions", "-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("Error: VM option 'AlwaysSafeConstructors' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.");
@@ -46,15 +46,15 @@ public class VMOptionWarning {
return;
}
pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintInlining", "-version");
pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintInlining", "-XX:-IgnoreUnrecognizedVMOptions", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.");
pb = ProcessTools.createJavaProcessBuilder("-XX:+VerifyStack", "-version");
pb = ProcessTools.createJavaProcessBuilder("-XX:+VerifyStack", "-XX:-IgnoreUnrecognizedVMOptions", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM.");
pb = ProcessTools.createJavaProcessBuilder("-XX:+CheckCompressedOops", "-version");
pb = ProcessTools.createJavaProcessBuilder("-XX:+CheckCompressedOops", "-XX:-IgnoreUnrecognizedVMOptions", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("Error: VM option 'CheckCompressedOops' is notproduct and is available only in debug version of VM.");
}

View File

@@ -242,6 +242,7 @@ public class TestVMOptionsFile {
private static ProcessBuilder createProcessBuilder() throws Exception {
ProcessBuilder pb;
List<String> runJava = new ArrayList<>();
runJava.add("-XX:-IgnoreUnrecognizedVMOptions");
runJava.addAll(VMParams);
runJava.add(PrintPropertyAndOptions.class.getName());

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,100 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. 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
@key headful
@bug 8272602
@summary Ctrl+Space should generate a KeyTyped event on macOS
@run main CtrlSpace
*/
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class CtrlSpace extends Frame implements KeyListener {
static volatile boolean testPassed = false;
static volatile Robot robot;
public static void main(String[] args) throws Exception {
robot = new Robot();
robot.setAutoWaitForIdle(true);
robot.setAutoDelay(100);
Frame frame = createAndShowGUI(robot);
test(robot);
robot.waitForIdle();
Thread.sleep(2000);
frame.setVisible(false);
frame.dispose();
if (!testPassed) {
throw new RuntimeException("No KeyTyped event");
}
}
static Frame createAndShowGUI(Robot robot) {
CtrlSpace win = new CtrlSpace();
win.setSize(300, 300);
Panel panel = new Panel(new BorderLayout());
TextField textField = new TextField("abcdefghijk");
textField.addKeyListener(win);
panel.add(textField, BorderLayout.CENTER);
win.add(panel);
win.setVisible(true);
robot.waitForIdle();
textField.requestFocusInWindow();
robot.waitForIdle();
return win;
}
public static void test(Robot robot) {
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_SPACE);
robot.keyRelease(KeyEvent.VK_SPACE);
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.delay(200);
}
public void keyPressed(KeyEvent evt) {
System.out.println("Pressed " + evt);
}
public void keyReleased(KeyEvent evt) {
System.out.println("Released " + evt);
}
public void keyTyped(KeyEvent evt) {
System.out.println("Typed " + evt);
testPassed = true;
}
}

View File

@@ -245,20 +245,23 @@ public class CustomComboBoxFocusTest {
System.out.println("Request focus on " + target);
final Component c = target.getEditor().getEditorComponent();
c.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
SwingUtilities.invokeLater(focusHandler);
}
if (c.isFocusOwner()) {
SwingUtilities.invokeLater(focusHandler);
} else {
c.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
SwingUtilities.invokeLater(focusHandler);
}
@Override
public void focusLost(FocusEvent e) {
@Override
public void focusLost(FocusEvent e) {
}
});
c.requestFocus();
}
});
c.requestFocus();
}
}
public Step nextStep() {

View File

@@ -56,21 +56,21 @@ public class JBRServiceTest {
* it in 'instanceof' statement will cause loading this interface, which may in turn cause NoClassDefFoundError.
*/
public static void main(String[] args) {
// Declaring variables is safe
SampleJBRApi.V1 service;
// We pass lambda instead of plain class. This allows JBRService#load to deal with NoClassDefFoundErrors
service = JBRService.load(() -> SampleJBRApi.V1.class);
// Null-checking variables is safe too
Objects.requireNonNull(service);
// When we ensured that SampleJBRApi.V1 is available, we can use anything that's inside
service.someMethod1(null);
// We can also create SampleJBRApi.V1.SomeDataClass instances, as we know they're supported with V1
service.someMethod1(new SampleJBRApi.V1.SomeDataClass());
// But don't try doing 'service instanceof SampleJBRApi.V2' as it may cause NoClassDefFoundErrors!
SampleJBRApi.V2 service2 = Objects.requireNonNull(JBRService.load(() -> SampleJBRApi.V2.class));
// Versioned service interfaces are inherited, so V2 gives you access to both V2 and V1 API
service2.someMethod1(service2.someMethod2());
// // Declaring variables is safe
// SampleJBRApi.V1 service;
// // We pass lambda instead of plain class. This allows JBRService#load to deal with NoClassDefFoundErrors
// service = JBRService.load(() -> SampleJBRApi.V1.class);
// // Null-checking variables is safe too
// Objects.requireNonNull(service);
// // When we ensured that SampleJBRApi.V1 is available, we can use anything that's inside
// service.someMethod1(null);
// // We can also create SampleJBRApi.V1.SomeDataClass instances, as we know they're supported with V1
// service.someMethod1(new SampleJBRApi.V1.SomeDataClass());
//
// // But don't try doing 'service instanceof SampleJBRApi.V2' as it may cause NoClassDefFoundErrors!
// SampleJBRApi.V2 service2 = Objects.requireNonNull(JBRService.load(() -> SampleJBRApi.V2.class));
// // Versioned service interfaces are inherited, so V2 gives you access to both V2 and V1 API
// service2.someMethod1(service2.someMethod2());
}

View File

@@ -45,6 +45,7 @@ public class TypeaheadRequestFocusTest {
initFinished.get(10, TimeUnit.SECONDS);
clickOn(frameField);
SwingUtilities.invokeAndWait(TypeaheadRequestFocusTest::showPopup);
robot.delay(1000);
pressAndRelease(KeyEvent.VK_ENTER);
pressAndRelease(KeyEvent.VK_A);
typedInPopup.get(10, TimeUnit.SECONDS);

View File

@@ -0,0 +1,133 @@
/*
* 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.
*
* 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 javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* @test
* @summary Regression test for JBR-3726 Modal windows 'disappear' on minimize in KDE
* @key headful
* @requires os.family == "linux"
* @modules java.desktop/java.awt:open
* java.desktop/sun.awt
* java.desktop/sun.awt.X11:open
*/
public class ModalDialogMinimizeOnKDE {
private static final CompletableFuture<Boolean> dialogShown = new CompletableFuture<>();
private static JFrame frame;
private static JDialog dialog;
public static void main(String[] args) throws Exception {
if (!isKDE()) {
System.out.println("This test is only valid for KDE");
return;
}
Robot robot = new Robot();
try {
SwingUtilities.invokeLater(ModalDialogMinimizeOnKDE::initUI);
dialogShown.get(5, TimeUnit.SECONDS);
robot.delay(1000);
minimize(dialog);
robot.delay(1000);
if (frame.getState() != Frame.ICONIFIED) {
throw new RuntimeException("Parent frame isn't minimized");
}
} finally {
SwingUtilities.invokeAndWait(ModalDialogMinimizeOnKDE::disposeUI);
}
}
private static void initUI() {
frame = new JFrame("ModalDialogMinimizeOnKDE");
frame.setSize(300, 200);
frame.setVisible(true);
dialog = new JDialog(frame, true);
dialog.setSize(200, 100);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
dialogShown.complete(true);
}
});
dialog.setVisible(true);
}
private static void disposeUI() {
if (frame != null) frame.dispose();
}
private static boolean isKDE() throws Exception {
Class<?> xwmCls = Class.forName("sun.awt.X11.XWM");
Field kdeField = xwmCls.getDeclaredField("KDE2_WM");
kdeField.setAccessible(true);
Method wmidMethod = xwmCls.getDeclaredMethod("getWMID");
wmidMethod.setAccessible(true);
return kdeField.get(null).equals(wmidMethod.invoke(null));
}
// We need to simulate user minimizing the dialog using button in title bar.
// As we don't know the location of the button (and it can depend on KDE version),
// we'll just use Xlib to minimize the window.
private static void minimize(JDialog dialog) throws Exception {
Class<?> toolkitCls = Class.forName("sun.awt.SunToolkit");
Method lockMethod = toolkitCls.getDeclaredMethod("awtLock");
Method unlockMethod = toolkitCls.getDeclaredMethod("awtUnlock");
Class<?> xToolkitClass = Class.forName("sun.awt.X11.XToolkit");
Method displayMethod = xToolkitClass.getDeclaredMethod("getDisplay");
Class<?> wrapperClass = Class.forName("sun.awt.X11.XlibWrapper");
Method iconifyMethod = wrapperClass.getDeclaredMethod("XIconifyWindow",
long.class, long.class, long.class);
iconifyMethod.setAccessible(true);
Class<?> windowClass = Class.forName("sun.awt.X11.XBaseWindow");
Method windowMethod = windowClass.getDeclaredMethod("getWindow");
Method screenMethod = windowClass.getDeclaredMethod("getScreenNumber");
screenMethod.setAccessible(true);
Field peerField = Component.class.getDeclaredField("peer");
peerField.setAccessible(true);
Object peer = peerField.get(dialog);
lockMethod.invoke(null);
try {
iconifyMethod.invoke(null,
displayMethod.invoke(null),
windowMethod.invoke(peer),
screenMethod.invoke(peer));
} finally {
unlockMethod.invoke(null);
}
}
}

View File

@@ -61,13 +61,11 @@ public class NestedDialogHideTest {
button3 = new JButton("Hide");
button3.addActionListener(eee -> d.setVisible(false));
d2.add(button3);
d2.pack();
d2.setLocation(240, 240);
d2.setBounds(240, 240, 200, 200);
d2.setVisible(true);
});
d.add(button2);
d.pack();
d.setLocation(220, 220);
d.setBounds(220, 220, 200, 200);
d.setVisible(true);
d.addComponentListener(new ComponentAdapter() {
@Override
@@ -77,8 +75,7 @@ public class NestedDialogHideTest {
});
});
frame.add(button1);
frame.pack();
frame.setLocation(200, 200);
frame.setBounds(200, 200, 200, 200);
frame.setVisible(true);
}

Some files were not shown because too many files have changed in this diff Show More