Compare commits

..

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

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

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

(AKA JBR-3416 Introduce new client property for Linux: xawt.mwm_decor_title)
2021-08-30 06:50:11 -07:00
Dmitry Batrak
28e26bc344 JBR-3706 Toggling full screen mode for two frames doesn't work on macOS if invoked without delay
(cherry picked from commit 28cfc4815f)
2021-08-26 16:10:48 +03:00
Dmitry Batrak
1333261006 JBR-3695 JNF removal issue
(cherry picked from commit 83556f56e7)
2021-08-20 10:46:41 +03:00
Vitaly Provodin
519d67cd4c exclude FullScreenInsets test on macosx-aarch64 due to 8266245
exclude bug6596966 test on windows-all due to 8197552
2021-08-18 10:47:41 +07:00
Vladimir Kempik
096484d199 exclude FullScreenInsets test on macosx-aarch64 due to 8266245 2021-08-18 08:40:33 +07:00
117 changed files with 6518 additions and 562 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -166,7 +166,7 @@ AWT_NS_WINDOW_IMPLEMENTATION
// send up to the GestureHandler to recursively dispatch on the AWT event thread
DECLARE_CLASS(jc_GestureHandler, "com/apple/eawt/event/GestureHandler");
DECLARE_METHOD(sjm_handleGestureFromNative, jc_GestureHandler,
DECLARE_STATIC_METHOD(sjm_handleGestureFromNative, jc_GestureHandler,
"handleGestureFromNative", "(Ljava/awt/Window;IDDDD)V");
(*env)->CallStaticVoidMethod(env, jc_GestureHandler, sjm_handleGestureFromNative,
awtWindow, type, (jdouble)loc.x, (jdouble)loc.y, (jdouble)a, (jdouble)b);
@@ -635,6 +635,7 @@ AWT_ASSERT_APPKIT_THREAD;
DECLARE_CLASS(jc_CCursorManager, "sun/lwawt/macosx/CCursorManager");
DECLARE_STATIC_METHOD(sjm_resetCurrentCursor, jc_CCursorManager, "resetCurrentCursor", "()V");
(*env)->CallStaticVoidMethod(env, jc_CCursorManager, sjm_resetCurrentCursor);
CHECK_EXCEPTION();
}
- (BOOL) canBecomeMainWindow {
@@ -1718,6 +1719,7 @@ JNI_COCOA_EXIT(env);
}
// undocumented approach which avoids focus stealing
// and can be used full screen switch is in progress for another window
void enableFullScreenSpecial(NSWindow *nsWindow) {
NSKeyedArchiver *coder = [[NSKeyedArchiver alloc] init];
[nsWindow encodeRestorableStateWithCoder:coder];
@@ -1744,12 +1746,17 @@ JNI_COCOA_ENTER(env);
if (![nsWindow respondsToSelector:toggleFullScreenSelector]) return;
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
if ((nsWindow.styleMask & NSWindowStyleMaskFullScreen) != NSWindowStyleMaskFullScreen && !NSApp.active) {
static BOOL inProgress = NO;
if ((nsWindow.styleMask & NSWindowStyleMaskFullScreen) != NSWindowStyleMaskFullScreen &&
(inProgress || !NSApp.active)) {
enableFullScreenSpecial(nsWindow);
if ((nsWindow.styleMask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) return; // success
// otherwise fall back to standard approach
}
BOOL savedValue = inProgress;
inProgress = YES;
[nsWindow performSelector:toggleFullScreenSelector withObject:nil];
inProgress = savedValue;
}];
JNI_COCOA_EXIT(env);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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

View File

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

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

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