mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-26 19:29:42 +01:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46702cad3c | ||
|
|
ac8ffa0ba7 | ||
|
|
fae062d45f | ||
|
|
0e87047b7e | ||
|
|
0106ef8fef | ||
|
|
a69031c54b | ||
|
|
8b96b1e115 | ||
|
|
48186ebbfb | ||
|
|
6877bb6cd1 | ||
|
|
aab6c2301d | ||
|
|
8b63dd1c22 | ||
|
|
9baaee86b0 | ||
|
|
9e0ff20be5 | ||
|
|
f51e55a20f | ||
|
|
e68d154a63 | ||
|
|
b526f948ff | ||
|
|
fdbb6f02b8 | ||
|
|
6743f36c32 | ||
|
|
f706b93717 | ||
|
|
6f046e9f68 | ||
|
|
bac641fe77 | ||
|
|
8dfcb3fd5a | ||
|
|
ef651ca1bb | ||
|
|
3092ca0461 | ||
|
|
3caa06a639 | ||
|
|
6c50ed6690 | ||
|
|
805a5b4f75 | ||
|
|
efabfd0370 | ||
|
|
f757a39090 | ||
|
|
1039653b97 | ||
|
|
65fa801231 | ||
|
|
3d9ae4dbe8 | ||
|
|
ef8e01b0d4 | ||
|
|
eaa9c1618e | ||
|
|
ee3c7edd84 | ||
|
|
8a19c38728 | ||
|
|
4fcd80acf0 | ||
|
|
6f5dd836de | ||
|
|
2ff21b425e | ||
|
|
28e26bc344 | ||
|
|
1333261006 | ||
|
|
519d67cd4c | ||
|
|
096484d199 |
34
README.md
34
README.md
@@ -5,6 +5,14 @@
|
||||
JetBrains Runtime is a fork of [OpenJDK](https://github.com/openjdk/jdk) available for Windows, Mac OS X, and Linux.
|
||||
It includes a number enhancements in font rendering, HiDPI support, ligatures, performance improvements, and bugfixes.
|
||||
|
||||
## Releases
|
||||
Download the latest releases of JetBrains Runtime to use with JetBrains IDEs. The full list
|
||||
can be found on the [releases page](https://github.com/JetBrains/JetBrainsRuntime/releases).
|
||||
|
||||
| IDE Version | Latest JBR | Date Released |
|
||||
| --- | --- | --- |
|
||||
| 2021.3 | [17-b106.1](https://github.com/JetBrains/JetBrainsRuntime/releases/tag/jbr17b106.1) | 28-Sep-2021 |
|
||||
|
||||
## Contents
|
||||
- [Welcome to JetBrains Runtime](#jetbrains-runtime)
|
||||
- [Products Built on JetBrains Runtime](#products-built-on-jetbrains-runtime)
|
||||
@@ -16,6 +24,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 +139,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/).
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
# How to call this script:
|
||||
# eval $(jb/project/tools/mkjbrapi.sh)
|
||||
|
||||
# It is used to build jetbrains.api module
|
||||
# After properly calling this script, you can use following variables:
|
||||
# JBR_API_JAR - absolute path to resulting JAR
|
||||
# JBR_API_SOURCES_JAR - absolute path to JAR with sources
|
||||
# JBR_API_VERSION - JBR API version in form <major>.<minor>
|
||||
# JBR_API_VERSION_MAJOR, JBR_API_VERSION_MINOR - JBR API version components
|
||||
# JBR_BUILD_DIR - absolute path to JBR build directory
|
||||
# JBR_BOOT_JDK - absolute path to used boot JDK
|
||||
|
||||
ROOT=$(pwd)
|
||||
|
||||
sh configure --with-debug-level=release --disable-warnings-as-errors 1>&2 || exit $?
|
||||
|
||||
# Get boot JDK & build directory using make script
|
||||
make -f $ROOT/make/JBRApi.gmk -I $ROOT jbr-api MAKEOVERRIDES= CONF=release OUT="$ROOT/build/jbr-api.cfg" 1>&2 || exit $?
|
||||
source "$ROOT/build/jbr-api.cfg" || exit $?
|
||||
|
||||
# Build module
|
||||
make jetbrains.api 1>&2 || exit $?
|
||||
|
||||
# Get JBR API version from compiled class
|
||||
JSHELL_COMMAND='
|
||||
System.out.println("\nVERSION_MAJOR=" + com.jetbrains.JBRApi.getMajorVersion());
|
||||
System.out.println("\nVERSION_MINOR=" + com.jetbrains.JBRApi.getMinorVersion());
|
||||
/exit'
|
||||
VERSION_VARIABLES=$("$BOOT_JDK/bin/jshell" -s --module-path "$BUILD_DIR/jdk/modules/jetbrains.api" \
|
||||
--add-modules jetbrains.api <<< "$JSHELL_COMMAND" | grep "^VERSION\|^|") || exit $?
|
||||
eval "$VERSION_VARIABLES" || exit $?
|
||||
|
||||
# Create JAR
|
||||
(
|
||||
cd "$BUILD_DIR/jdk/modules/jetbrains.api"
|
||||
"$BOOT_JDK/bin/jar" -cf "$BUILD_DIR/jbr-api.jar" * 1>&2
|
||||
) || exit $?
|
||||
|
||||
# Create source JAR
|
||||
(
|
||||
cd "src/jetbrains.api/share/classes"
|
||||
"$BOOT_JDK/bin/jar" -cf "$BUILD_DIR/jbr-api-sources.jar" * 1>&2
|
||||
) || exit $?
|
||||
|
||||
# Print output values
|
||||
echo "JBR_API_JAR=$BUILD_DIR/jbr-api.jar"
|
||||
echo "JBR_API_SOURCES_JAR=$BUILD_DIR/jbr-api-sources.jar"
|
||||
echo "JBR_API_VERSION=$VERSION_MAJOR.$VERSION_MINOR"
|
||||
echo "JBR_API_VERSION_MAJOR=$VERSION_MAJOR"
|
||||
echo "JBR_API_VERSION_MINOR=$VERSION_MINOR"
|
||||
echo "JBR_BUILD_DIR=$BUILD_DIR"
|
||||
echo "JBR_BOOT_JDK=$BOOT_JDK"
|
||||
|
||||
echo "Success!" 1>&2
|
||||
@@ -1,11 +1,11 @@
|
||||
diff --git modules.list modules.list
|
||||
index dcf610a6a56..f8797505c23 100644
|
||||
index 054f21d1ee0..d9a121f0273 100644
|
||||
--- modules.list
|
||||
+++ modules.list
|
||||
@@ -51,4 +51,7 @@ jdk.zipfs,
|
||||
@@ -49,4 +49,7 @@ jdk.unsupported,
|
||||
jdk.xml.dom,
|
||||
jdk.zipfs,
|
||||
jdk.hotspot.agent,
|
||||
jetbrains.api,
|
||||
jetbrains.api.impl,
|
||||
-jdk.jcmd
|
||||
+jdk.jcmd,
|
||||
+jcef,
|
||||
|
||||
@@ -42,7 +42,6 @@ function pack_jbr {
|
||||
JBRSDK_BUNDLE=jbrsdk
|
||||
RELEASE_NAME=windows-x86_64-server-release
|
||||
IMAGES_DIR=build/$RELEASE_NAME/images
|
||||
JBSDK=$JBRSDK_BASE_NAME-windows-x64-b$build_number
|
||||
BASE_DIR=.
|
||||
|
||||
if [ "$bundle_type" == "jcef" ] || [ "$bundle_type" == "dcevm" ] || [ "$bundle_type" == "fd" ]; then
|
||||
@@ -53,7 +52,7 @@ pack_jbr jbr${jbr_name_postfix} jbr
|
||||
pack_jbr jbrsdk${jbr_name_postfix} jbrsdk
|
||||
|
||||
if [ -z "$bundle_type" ]; then
|
||||
JBRSDK_TEST=$JBRSDK_BASE_NAME-windows-test-x64-b$build_number
|
||||
JBRSDK_TEST=$JBRSDK_BUNDLE-$JBSDK_VERSION-windows-test-x64-b$build_number
|
||||
echo Creating $JBRSDK_TEST.tar.gz ...
|
||||
/usr/bin/tar -czf $JBRSDK_TEST.tar.gz -C $IMAGES_DIR --exclude='test/jdk/demos' test || do_exit $?
|
||||
fi
|
||||
@@ -1,20 +0,0 @@
|
||||
include Makefile
|
||||
include make/MainSupport.gmk
|
||||
|
||||
.PHONY: jbr-api
|
||||
|
||||
ifeq ($(SPEC),)
|
||||
ifneq ($(words $(SPECS)),1)
|
||||
@echo "Error: Multiple build specification files found. Please select one explicitly."
|
||||
@exit 2
|
||||
endif
|
||||
jbr-api:
|
||||
@cd $(topdir)
|
||||
@$(MAKE) $(MFLAGS) $(MAKE_LOG_FLAGS) -r -R -j 1 -f $(topdir)/make/JBRApi.gmk SPEC=$(SPECS) HAS_SPEC=true ACTUAL_TOPDIR=$(topdir) MODULES="$(MODULES)" jbr-api
|
||||
else #with SPEC
|
||||
|
||||
jbr-api:
|
||||
$(ECHO) "BUILD_DIR=$(OUTPUTDIR)" > $(OUT)
|
||||
$(ECHO) "BOOT_JDK=\"$(BOOT_JDK)\"" >> $(OUT)
|
||||
|
||||
endif
|
||||
@@ -55,8 +55,6 @@ BOOT_MODULES= \
|
||||
jdk.sctp \
|
||||
jdk.unsupported \
|
||||
jdk.naming.rmi \
|
||||
jetbrains.api \
|
||||
jetbrains.api.impl \
|
||||
#
|
||||
|
||||
# Modules that directly or indirectly requiring upgradeable modules
|
||||
|
||||
@@ -49,6 +49,4 @@ jdk.unsupported,
|
||||
jdk.xml.dom,
|
||||
jdk.zipfs,
|
||||
jdk.hotspot.agent,
|
||||
jetbrains.api,
|
||||
jetbrains.api.impl,
|
||||
jdk.jcmd
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, \
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
package java.nio.file;
|
||||
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.BasicWithKeyFileAttributeView;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
@@ -217,7 +219,11 @@ class FileTreeWalker implements Closeable {
|
||||
// links then a link target might not exist so get attributes of link
|
||||
BasicFileAttributes attrs;
|
||||
try {
|
||||
attrs = Files.readAttributes(file, BasicFileAttributes.class, linkOptions);
|
||||
BasicFileAttributeView view = Files.getFileAttributeView(file, BasicWithKeyFileAttributeView.class, linkOptions);
|
||||
if (view == null) {
|
||||
view = Files.getFileAttributeView(file, BasicFileAttributeView.class, linkOptions);
|
||||
}
|
||||
attrs = view.readAttributes();
|
||||
} catch (IOException ioe) {
|
||||
if (!followLinks)
|
||||
throw ioe;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2011, 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. 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.
|
||||
*/
|
||||
|
||||
package java.nio.file.attribute;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Similar to {@link BasicFileAttributeView} with a hint to implementors
|
||||
* to retrieve a valid {@link BasicFileAttributes#fileKey()} if possible, even
|
||||
* at a performance cost.
|
||||
*/
|
||||
|
||||
public interface BasicWithKeyFileAttributeView
|
||||
extends BasicFileAttributeView {
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -41,16 +41,16 @@ import static sun.nio.fs.WindowsConstants.*;
|
||||
class WindowsDirectoryStream
|
||||
implements DirectoryStream<Path>
|
||||
{
|
||||
private static final int NATIVE_BUFFER_SIZE = 8192;
|
||||
|
||||
private final WindowsPath dir;
|
||||
private final DirectoryStream.Filter<? super Path> filter;
|
||||
|
||||
// handle to directory
|
||||
private final long handle;
|
||||
// first entry in the directory
|
||||
private final String firstName;
|
||||
// Query directory information data structure
|
||||
private final QueryDirectoryInformation queryDirectoryInformation;
|
||||
|
||||
// buffer for WIN32_FIND_DATA structure that receives information about file
|
||||
private final NativeBuffer findDataBuffer;
|
||||
// Buffer used to receive file entries from NtQueryDirectoryInformation calls
|
||||
private final NativeBuffer queryDirectoryInformationBuffer;
|
||||
|
||||
private final Object closeLock = new Object();
|
||||
|
||||
@@ -65,21 +65,15 @@ class WindowsDirectoryStream
|
||||
this.dir = dir;
|
||||
this.filter = filter;
|
||||
|
||||
this.queryDirectoryInformationBuffer = NativeBuffers.getNativeBuffer(NATIVE_BUFFER_SIZE);
|
||||
try {
|
||||
// Need to append * or \* to match entries in directory.
|
||||
// Open the directory for reading and read the first set of entries in the native buffer
|
||||
String search = dir.getPathForWin32Calls();
|
||||
char last = search.charAt(search.length() -1);
|
||||
if (last == ':' || last == '\\') {
|
||||
search += "*";
|
||||
} else {
|
||||
search += "\\*";
|
||||
}
|
||||
|
||||
FirstFile first = FindFirstFile(search);
|
||||
this.handle = first.handle();
|
||||
this.firstName = first.name();
|
||||
this.findDataBuffer = WindowsFileAttributes.getBufferForFindData();
|
||||
this.queryDirectoryInformation = OpenNtQueryDirectoryInformation(search, this.queryDirectoryInformationBuffer);
|
||||
} catch (WindowsException x) {
|
||||
// Release the buffer, as this instance is not fully constructed
|
||||
this.queryDirectoryInformationBuffer.release();
|
||||
|
||||
if (x.lastError() == ERROR_DIRECTORY) {
|
||||
throw new NotDirectoryException(dir.getPathForExceptionMessage());
|
||||
}
|
||||
@@ -99,9 +93,9 @@ class WindowsDirectoryStream
|
||||
return;
|
||||
isOpen = false;
|
||||
}
|
||||
findDataBuffer.release();
|
||||
queryDirectoryInformationBuffer.release();
|
||||
try {
|
||||
FindClose(handle);
|
||||
CloseNtQueryDirectoryInformation(queryDirectoryInformation);
|
||||
} catch (WindowsException x) {
|
||||
x.rethrowAsIOException(dir);
|
||||
}
|
||||
@@ -115,20 +109,20 @@ class WindowsDirectoryStream
|
||||
synchronized (this) {
|
||||
if (iterator != null)
|
||||
throw new IllegalStateException("Iterator already obtained");
|
||||
iterator = new WindowsDirectoryIterator(firstName);
|
||||
iterator = new WindowsDirectoryIterator();
|
||||
return iterator;
|
||||
}
|
||||
}
|
||||
|
||||
private class WindowsDirectoryIterator implements Iterator<Path> {
|
||||
private boolean atEof;
|
||||
private String first;
|
||||
private Path nextEntry;
|
||||
private String prefix;
|
||||
private int nextOffset;
|
||||
|
||||
WindowsDirectoryIterator(String first) {
|
||||
WindowsDirectoryIterator() {
|
||||
atEof = false;
|
||||
this.first = first;
|
||||
nextOffset = 0;
|
||||
if (dir.needsSlashWhenResolving()) {
|
||||
prefix = dir.toString() + "\\";
|
||||
} else {
|
||||
@@ -156,44 +150,40 @@ class WindowsDirectoryStream
|
||||
|
||||
// reads next directory entry
|
||||
private Path readNextEntry() {
|
||||
// handle first element returned by search
|
||||
if (first != null) {
|
||||
nextEntry = isSelfOrParent(first) ? null : acceptEntry(first, null);
|
||||
first = null;
|
||||
if (nextEntry != null)
|
||||
return nextEntry;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
String name = null;
|
||||
String name;
|
||||
WindowsFileAttributes attrs;
|
||||
|
||||
// synchronize on closeLock to prevent close while reading
|
||||
synchronized (closeLock) {
|
||||
try {
|
||||
if (isOpen) {
|
||||
name = FindNextFile(handle, findDataBuffer.address());
|
||||
}
|
||||
} catch (WindowsException x) {
|
||||
IOException ioe = x.asIOException(dir);
|
||||
throw new DirectoryIteratorException(ioe);
|
||||
}
|
||||
|
||||
// NO_MORE_FILES or stream closed
|
||||
if (name == null) {
|
||||
// Fetch next set of entries if we don't have anything available in buffer
|
||||
if (!isOpen) {
|
||||
atEof = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
// ignore link to self and parent directories
|
||||
if (isSelfOrParent(name))
|
||||
continue;
|
||||
if (nextOffset < 0) {
|
||||
try {
|
||||
atEof = !NextNtQueryDirectoryInformation(queryDirectoryInformation, queryDirectoryInformationBuffer);
|
||||
} catch (WindowsException x) {
|
||||
IOException ioe = x.asIOException(dir);
|
||||
throw new DirectoryIteratorException(ioe);
|
||||
}
|
||||
if (atEof) {
|
||||
return null;
|
||||
}
|
||||
nextOffset = 0;
|
||||
}
|
||||
|
||||
// grab the attributes from the WIN32_FIND_DATA structure
|
||||
// (needs to be done while holding closeLock because close
|
||||
// will release the buffer)
|
||||
attrs = WindowsFileAttributes
|
||||
.fromFindData(findDataBuffer.address());
|
||||
long fullDirInformationAddress = queryDirectoryInformationBuffer.address() + nextOffset;
|
||||
int nextEntryOffset = WindowsFileAttributes.getNextOffsetFromFileIdFullDirInformation(fullDirInformationAddress);
|
||||
nextOffset = nextEntryOffset == 0 ? -1 : nextOffset + nextEntryOffset;
|
||||
name = WindowsFileAttributes.getFileNameFromFileIdFullDirInformation(fullDirInformationAddress);
|
||||
if (isSelfOrParent(name)) {
|
||||
// Skip "." and ".."
|
||||
continue;
|
||||
}
|
||||
attrs = WindowsFileAttributes.fromFileIdFullDirInformation(fullDirInformationAddress, queryDirectoryInformation.volSerialNumber());
|
||||
}
|
||||
|
||||
// return entry if accepted by filter
|
||||
|
||||
@@ -150,6 +150,23 @@ class WindowsFileAttributeViews {
|
||||
}
|
||||
}
|
||||
|
||||
private static class BasicWithKey extends Basic {
|
||||
BasicWithKey(WindowsPath file, boolean followLinks) {
|
||||
super(file, followLinks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowsFileAttributes readAttributes() throws IOException {
|
||||
file.checkRead();
|
||||
try {
|
||||
return WindowsFileAttributes.getWithFileKey(file, followLinks);
|
||||
} catch (WindowsException x) {
|
||||
x.rethrowAsIOException(file);
|
||||
return null; // keep compiler happy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Dos extends Basic implements DosFileAttributeView {
|
||||
private static final String READONLY_NAME = "readonly";
|
||||
private static final String ARCHIVE_NAME = "archive";
|
||||
@@ -289,6 +306,10 @@ class WindowsFileAttributeViews {
|
||||
return new Basic(file, followLinks);
|
||||
}
|
||||
|
||||
static Basic createBasicWithKeyView(WindowsPath file, boolean followLinks) {
|
||||
return new BasicWithKey(file, followLinks);
|
||||
}
|
||||
|
||||
static Dos createDosView(WindowsPath file, boolean followLinks) {
|
||||
return new Dos(file, followLinks);
|
||||
}
|
||||
|
||||
@@ -108,10 +108,42 @@ class WindowsFileAttributes
|
||||
private static final short OFFSETOF_FIND_DATA_SIZELOW = 32;
|
||||
private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36;
|
||||
|
||||
|
||||
// used to adjust values between Windows and java epochs
|
||||
private static final long WINDOWS_EPOCH_IN_MICROS = -11644473600000000L;
|
||||
private static final long WINDOWS_EPOCH_IN_100NS = -116444736000000000L;
|
||||
|
||||
/**
|
||||
* typedef struct _FILE_ID_FULL_DIR_INFORMATION {
|
||||
* ULONG NextEntryOffset; // offset = 0
|
||||
* ULONG FileIndex; // offset = 4
|
||||
* LARGE_INTEGER CreationTime; // offset = 8
|
||||
* LARGE_INTEGER LastAccessTime; // offset = 16
|
||||
* LARGE_INTEGER LastWriteTime; // offset = 24
|
||||
* LARGE_INTEGER ChangeTime; // offset = 32
|
||||
* LARGE_INTEGER EndOfFile; // offset = 40
|
||||
* LARGE_INTEGER AllocationSize; // offset = 48
|
||||
* ULONG FileAttributes; // offset = 56
|
||||
* ULONG FileNameLength; // offset = 60
|
||||
* ULONG EaSize; // offset = 64
|
||||
* LARGE_INTEGER FileId; // offset = 72
|
||||
* WCHAR FileName[1]; // offset = 80
|
||||
* } FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;
|
||||
*/
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_NEXT_ENTRY_OFFSET = 0;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_CREATION_TIME = 8;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_LAST_ACCESS_TIME = 16;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_LAST_WRITE_TIME = 24;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_END_OF_FILE = 40;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_FILE_ATTRIBUTES = 56;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_FILENAME_LENGTH = 60;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_EA_SIZE = 64;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_FILE_ID = 72;
|
||||
private static final int OFFSETOF_FULL_DIR_INFO_FILENAME = 80;
|
||||
|
||||
// used to adjust values between Windows and java epoch
|
||||
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
|
||||
|
||||
// indicates if accurate metadata is required (interesting on NTFS only)
|
||||
private static final boolean ensureAccurateMetadata;
|
||||
static {
|
||||
@@ -133,6 +165,9 @@ class WindowsFileAttributes
|
||||
private final int fileIndexHigh;
|
||||
private final int fileIndexLow;
|
||||
|
||||
// created lazily
|
||||
private volatile WindowsFileKey key;
|
||||
|
||||
/**
|
||||
* Convert 64-bit value representing the number of 100-nanosecond intervals
|
||||
* since January 1, 1601 to a FileTime.
|
||||
@@ -257,6 +292,47 @@ class WindowsFileAttributes
|
||||
0); // fileIndexLow
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a WindowsFileAttributes from a FILE_ID_FULL_DIR_INFORMATION structure
|
||||
*/
|
||||
static WindowsFileAttributes fromFileIdFullDirInformation(long address, int volSerialNumber) {
|
||||
int fileAttrs = unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_FILE_ATTRIBUTES);
|
||||
long creationTime = unsafe.getLong(address + OFFSETOF_FULL_DIR_INFO_CREATION_TIME);
|
||||
long lastAccessTime = unsafe.getLong(address + OFFSETOF_FULL_DIR_INFO_LAST_ACCESS_TIME);
|
||||
long lastWriteTime = unsafe.getLong(address + OFFSETOF_FULL_DIR_INFO_LAST_WRITE_TIME);
|
||||
long size = unsafe.getLong(address + OFFSETOF_FULL_DIR_INFO_END_OF_FILE);
|
||||
int reparseTag = isReparsePoint(fileAttrs) ?
|
||||
unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_EA_SIZE) : 0;
|
||||
int fileIndexLow = unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_FILE_ID);
|
||||
int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_FILE_ID + 4);
|
||||
|
||||
return new WindowsFileAttributes(fileAttrs,
|
||||
creationTime,
|
||||
lastAccessTime,
|
||||
lastWriteTime,
|
||||
size,
|
||||
reparseTag,
|
||||
volSerialNumber,
|
||||
fileIndexHigh, // fileIndexHigh
|
||||
fileIndexLow); // fileIndexLow
|
||||
}
|
||||
|
||||
static int getNextOffsetFromFileIdFullDirInformation(long address) {
|
||||
return unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_NEXT_ENTRY_OFFSET);
|
||||
}
|
||||
|
||||
static String getFileNameFromFileIdFullDirInformation(long address) {
|
||||
// copy the name
|
||||
int nameLengthInBytes = unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_FILENAME_LENGTH);
|
||||
if ((nameLengthInBytes % 2) != 0) {
|
||||
throw new AssertionError("FileNameLength is not a multiple of 2");
|
||||
}
|
||||
char[] nameAsArray = new char[nameLengthInBytes/2];
|
||||
unsafe.copyMemory(null, address + OFFSETOF_FULL_DIR_INFO_FILENAME, nameAsArray,
|
||||
Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes);
|
||||
return new String(nameAsArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the attributes of an open file
|
||||
*/
|
||||
@@ -347,6 +423,15 @@ class WindowsFileAttributes
|
||||
}
|
||||
|
||||
// file is reparse point so need to open file to get attributes
|
||||
return getWithFileKey(path, followLinks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns attributes of given file.
|
||||
*/
|
||||
static WindowsFileAttributes getWithFileKey(WindowsPath path, boolean followLinks)
|
||||
throws WindowsException
|
||||
{
|
||||
long handle = path.openForReadAttributeAccess(followLinks);
|
||||
try {
|
||||
return readAttributes(handle);
|
||||
@@ -414,7 +499,17 @@ class WindowsFileAttributes
|
||||
|
||||
@Override
|
||||
public Object fileKey() {
|
||||
return null;
|
||||
if (volSerialNumber == 0) {
|
||||
return null;
|
||||
}
|
||||
if (key == null) {
|
||||
synchronized (this) {
|
||||
if (key == null) {
|
||||
key = new WindowsFileKey(volSerialNumber, ((long)fileIndexHigh << 32) + fileIndexLow);
|
||||
}
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
// package private
|
||||
|
||||
67
src/java.base/windows/classes/sun/nio/fs/WindowsFileKey.java
Normal file
67
src/java.base/windows/classes/sun/nio/fs/WindowsFileKey.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 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. 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.
|
||||
*/
|
||||
|
||||
package sun.nio.fs;
|
||||
|
||||
/**
|
||||
* Container for volume/file id to uniquely identify file.
|
||||
*/
|
||||
|
||||
class WindowsFileKey {
|
||||
private final int volSerialNumber;
|
||||
private final long fileId;
|
||||
|
||||
WindowsFileKey(int volSerialNumber, long fileId) {
|
||||
this.volSerialNumber = volSerialNumber;
|
||||
this.fileId = fileId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (volSerialNumber ^ (volSerialNumber >>> 16)) +
|
||||
(int)(fileId ^ (fileId >>> 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (!(obj instanceof WindowsFileKey))
|
||||
return false;
|
||||
WindowsFileKey other = (WindowsFileKey)obj;
|
||||
return (this.volSerialNumber == other.volSerialNumber) && (this.fileId == other.fileId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(volId=")
|
||||
.append(Integer.toHexString(volSerialNumber))
|
||||
.append(",fileId=")
|
||||
.append(Long.toHexString(fileId))
|
||||
.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -168,6 +168,8 @@ class WindowsFileSystemProvider
|
||||
boolean followLinks = Util.followLinks(options);
|
||||
if (view == BasicFileAttributeView.class)
|
||||
return (V) WindowsFileAttributeViews.createBasicView(file, followLinks);
|
||||
if (view == BasicWithKeyFileAttributeView.class)
|
||||
return (V) WindowsFileAttributeViews.createBasicWithKeyView(file, followLinks);
|
||||
if (view == DosFileAttributeView.class)
|
||||
return (V) WindowsFileAttributeViews.createDosView(file, followLinks);
|
||||
if (view == AclFileAttributeView.class)
|
||||
@@ -205,6 +207,8 @@ class WindowsFileSystemProvider
|
||||
boolean followLinks = Util.followLinks(options);
|
||||
if (name.equals("basic"))
|
||||
return WindowsFileAttributeViews.createBasicView(file, followLinks);
|
||||
if (name.equals("basicwithkey"))
|
||||
return WindowsFileAttributeViews.createBasicWithKeyView(file, followLinks);
|
||||
if (name.equals("dos"))
|
||||
return WindowsFileAttributeViews.createDosView(file, followLinks);
|
||||
if (name.equals("acl"))
|
||||
|
||||
@@ -285,6 +285,38 @@ class WindowsNativeDispatcher {
|
||||
*/
|
||||
static native void FindClose(long handle) throws WindowsException;
|
||||
|
||||
static QueryDirectoryInformation OpenNtQueryDirectoryInformation(String path, NativeBuffer buffer) throws WindowsException {
|
||||
NativeBuffer pathBuffer = asNativeBuffer(path);
|
||||
try {
|
||||
QueryDirectoryInformation data = new QueryDirectoryInformation();
|
||||
OpenNtQueryDirectoryInformation0(pathBuffer.address(), buffer.address(), buffer.size(), data);
|
||||
return data;
|
||||
} finally {
|
||||
pathBuffer.release();
|
||||
}
|
||||
}
|
||||
static class QueryDirectoryInformation {
|
||||
private long handle;
|
||||
private int volSerialNumber;
|
||||
|
||||
private QueryDirectoryInformation() { }
|
||||
public long handle() { return handle; }
|
||||
public int volSerialNumber() { return volSerialNumber; }
|
||||
}
|
||||
private static native void OpenNtQueryDirectoryInformation0(long lpFileName, long buffer, int bufferSize, QueryDirectoryInformation obj)
|
||||
throws WindowsException;
|
||||
|
||||
static boolean NextNtQueryDirectoryInformation(QueryDirectoryInformation data, NativeBuffer buffer) throws WindowsException {
|
||||
return NextNtQueryDirectoryInformation0(data.handle(), buffer.address(), buffer.size());
|
||||
}
|
||||
|
||||
private static native boolean NextNtQueryDirectoryInformation0(long handle, long buffer, int bufferSize)
|
||||
throws WindowsException;
|
||||
|
||||
static void CloseNtQueryDirectoryInformation(QueryDirectoryInformation data) throws WindowsException {
|
||||
CloseHandle(data.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetFileInformationByHandle(
|
||||
* HANDLE hFile,
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "jni_util.h"
|
||||
#include "jlong.h"
|
||||
|
||||
#include "ntifs_min.h"
|
||||
|
||||
#include "sun_nio_fs_WindowsNativeDispatcher.h"
|
||||
|
||||
/**
|
||||
@@ -50,6 +52,9 @@ static jfieldID findFirst_attributes;
|
||||
static jfieldID findStream_handle;
|
||||
static jfieldID findStream_name;
|
||||
|
||||
static jfieldID queryDirectoryInformation_handle;
|
||||
static jfieldID queryDirectoryInformation_volSerialNumber;
|
||||
|
||||
static jfieldID volumeInfo_fsName;
|
||||
static jfieldID volumeInfo_volName;
|
||||
static jfieldID volumeInfo_volSN;
|
||||
@@ -71,6 +76,13 @@ static jfieldID completionStatus_error;
|
||||
static jfieldID completionStatus_bytesTransferred;
|
||||
static jfieldID completionStatus_completionKey;
|
||||
|
||||
typedef NTSYSCALLAPI NTSTATUS(NTAPI* NtQueryDirectoryFile_Proc) (HANDLE, HANDLE, PIO_APC_ROUTINE,
|
||||
PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN);
|
||||
typedef ULONG(NTAPI* RtlNtStatusToDosError_Proc) (NTSTATUS);
|
||||
|
||||
static NtQueryDirectoryFile_Proc NtQueryDirectoryFile_func;
|
||||
static RtlNtStatusToDosError_Proc RtlNtStatusToDosError_func;
|
||||
|
||||
static void throwWindowsException(JNIEnv* env, DWORD lastError) {
|
||||
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/WindowsException",
|
||||
"(I)V", lastError);
|
||||
@@ -87,6 +99,7 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
|
||||
{
|
||||
jclass clazz;
|
||||
HMODULE h;
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstFile");
|
||||
CHECK_NULL(clazz);
|
||||
@@ -104,6 +117,13 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
|
||||
findStream_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
|
||||
CHECK_NULL(findStream_name);
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$QueryDirectoryInformation");
|
||||
CHECK_NULL(clazz);
|
||||
queryDirectoryInformation_handle = (*env)->GetFieldID(env, clazz, "handle", "J");
|
||||
CHECK_NULL(queryDirectoryInformation_handle);
|
||||
queryDirectoryInformation_volSerialNumber = (*env)->GetFieldID(env, clazz, "volSerialNumber", "I");;
|
||||
CHECK_NULL(queryDirectoryInformation_volSerialNumber);
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$VolumeInformation");
|
||||
CHECK_NULL(clazz);
|
||||
volumeInfo_fsName = (*env)->GetFieldID(env, clazz, "fileSystemName", "Ljava/lang/String;");
|
||||
@@ -148,6 +168,16 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
|
||||
CHECK_NULL(completionStatus_bytesTransferred);
|
||||
completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "J");
|
||||
CHECK_NULL(completionStatus_completionKey);
|
||||
|
||||
// get handle to ntdll
|
||||
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
L"ntdll.dll", &h) != 0)
|
||||
{
|
||||
NtQueryDirectoryFile_func =
|
||||
(NtQueryDirectoryFile_Proc)GetProcAddress(h, "NtQueryDirectoryFile");
|
||||
RtlNtStatusToDosError_func =
|
||||
(RtlNtStatusToDosError_Proc)GetProcAddress(h, "RtlNtStatusToDosError");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
@@ -428,6 +458,118 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindClose(JNIEnv* env, jclass this,
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_WindowsNativeDispatcher_OpenNtQueryDirectoryInformation0(JNIEnv* env, jclass this,
|
||||
jlong address, jlong bufferAddress, jint bufferSize, jobject obj)
|
||||
{
|
||||
LPCWSTR lpFileName = jlong_to_ptr(address);
|
||||
BOOL ok;
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
HANDLE handle;
|
||||
NTSTATUS status;
|
||||
ULONG win32ErrorCode;
|
||||
IO_STATUS_BLOCK ioStatusBlock;
|
||||
|
||||
if ((NtQueryDirectoryFile_func == NULL) || (RtlNtStatusToDosError_func == NULL)) {
|
||||
JNU_ThrowInternalError(env, "Should not get here");
|
||||
return;
|
||||
}
|
||||
|
||||
handle = CreateFileW(lpFileName, FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
throwWindowsException(env, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
status = NtQueryDirectoryFile_func(
|
||||
handle, // FileHandle
|
||||
NULL, // Event
|
||||
NULL, // ApcRoutine
|
||||
NULL, // ApcContext
|
||||
&ioStatusBlock, // IoStatusBlock
|
||||
jlong_to_ptr(bufferAddress), // FileInformation
|
||||
bufferSize, // Length
|
||||
FileIdFullDirectoryInformation, // FileInformationClass
|
||||
FALSE, // ReturnSingleEntry
|
||||
NULL, // FileName
|
||||
FALSE); // RestartScan
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
/*
|
||||
* NtQueryDirectoryFile returns STATUS_INVALID_PARAMETER when
|
||||
* asked to enumerate an invalid directory (ie it is a file
|
||||
* instead of a directory). Verify that is the actual cause
|
||||
* of the error.
|
||||
*/
|
||||
if (status == STATUS_INVALID_PARAMETER) {
|
||||
DWORD attributes = GetFileAttributesW(lpFileName);
|
||||
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
||||
status = STATUS_NOT_A_DIRECTORY;
|
||||
}
|
||||
}
|
||||
|
||||
win32ErrorCode = RtlNtStatusToDosError_func(status);
|
||||
throwWindowsException(env, win32ErrorCode);
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
// This call allows retrieving the volume ID of this directory (and all its entries)
|
||||
ok = GetFileInformationByHandle(handle, &info);
|
||||
if (!ok) {
|
||||
throwWindowsException(env, GetLastError());
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
(*env)->SetLongField(env, obj, queryDirectoryInformation_handle, ptr_to_jlong(handle));
|
||||
(*env)->SetIntField(env, obj, queryDirectoryInformation_volSerialNumber, info.dwVolumeSerialNumber);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_fs_WindowsNativeDispatcher_NextNtQueryDirectoryInformation0(JNIEnv* env, jclass this,
|
||||
jlong handle, jlong address, jint size)
|
||||
{
|
||||
HANDLE h = (HANDLE)jlong_to_ptr(handle);
|
||||
ULONG win32ErrorCode;
|
||||
IO_STATUS_BLOCK ioStatusBlock;
|
||||
NTSTATUS status;
|
||||
|
||||
if ((NtQueryDirectoryFile_func == NULL) || (RtlNtStatusToDosError_func == NULL)) {
|
||||
JNU_ThrowInternalError(env, "Should not get here");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
status = NtQueryDirectoryFile_func(
|
||||
h, // FileHandle
|
||||
NULL, // Event
|
||||
NULL, // ApcRoutine
|
||||
NULL, // ApcContext
|
||||
&ioStatusBlock, // IoStatusBlock
|
||||
jlong_to_ptr(address), // FileInformation
|
||||
size, // Length
|
||||
FileIdFullDirectoryInformation, // FileInformationClass
|
||||
FALSE, // ReturnSingleEntry
|
||||
NULL, // FileName
|
||||
FALSE); // RestartScan
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
// Normal completion: no more files in directory
|
||||
if (status == STATUS_NO_MORE_FILES) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
win32ErrorCode = RtlNtStatusToDosError_func(status);
|
||||
throwWindowsException(env, win32ErrorCode);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_WindowsNativeDispatcher_GetFileInformationByHandle(JNIEnv* env, jclass this,
|
||||
jlong handle, jlong address)
|
||||
|
||||
160
src/java.base/windows/native/libnio/fs/ntifs_min.h
Normal file
160
src/java.base/windows/native/libnio/fs/ntifs_min.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2018, 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. 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 _NTIFS_MIN_
|
||||
#define _NTIFS_MIN_
|
||||
|
||||
/*
|
||||
* Copy necessary structures and definitions out of the Windows DDK
|
||||
* to enable calling NtQueryDirectoryFile()
|
||||
*/
|
||||
|
||||
typedef LONG NTSTATUS;
|
||||
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWCH Buffer;
|
||||
} UNICODE_STRING;
|
||||
typedef UNICODE_STRING *PUNICODE_STRING;
|
||||
typedef const UNICODE_STRING *PCUNICODE_STRING;
|
||||
|
||||
typedef enum _FILE_INFORMATION_CLASS {
|
||||
FileDirectoryInformation = 1,
|
||||
FileFullDirectoryInformation,
|
||||
FileBothDirectoryInformation,
|
||||
FileBasicInformation,
|
||||
FileStandardInformation,
|
||||
FileInternalInformation,
|
||||
FileEaInformation,
|
||||
FileAccessInformation,
|
||||
FileNameInformation,
|
||||
FileRenameInformation,
|
||||
FileLinkInformation,
|
||||
FileNamesInformation,
|
||||
FileDispositionInformation,
|
||||
FilePositionInformation,
|
||||
FileFullEaInformation,
|
||||
FileModeInformation,
|
||||
FileAlignmentInformation,
|
||||
FileAllInformation,
|
||||
FileAllocationInformation,
|
||||
FileEndOfFileInformation,
|
||||
FileAlternateNameInformation,
|
||||
FileStreamInformation,
|
||||
FilePipeInformation,
|
||||
FilePipeLocalInformation,
|
||||
FilePipeRemoteInformation,
|
||||
FileMailslotQueryInformation,
|
||||
FileMailslotSetInformation,
|
||||
FileCompressionInformation,
|
||||
FileObjectIdInformation,
|
||||
FileCompletionInformation,
|
||||
FileMoveClusterInformation,
|
||||
FileQuotaInformation,
|
||||
FileReparsePointInformation,
|
||||
FileNetworkOpenInformation,
|
||||
FileAttributeTagInformation,
|
||||
FileTrackingInformation,
|
||||
FileIdBothDirectoryInformation,
|
||||
FileIdFullDirectoryInformation,
|
||||
FileValidDataLengthInformation,
|
||||
FileShortNameInformation,
|
||||
FileIoCompletionNotificationInformation,
|
||||
FileIoStatusBlockRangeInformation,
|
||||
FileIoPriorityHintInformation,
|
||||
FileSfioReserveInformation,
|
||||
FileSfioVolumeInformation,
|
||||
FileHardLinkInformation,
|
||||
FileProcessIdsUsingFileInformation,
|
||||
FileNormalizedNameInformation,
|
||||
FileNetworkPhysicalNameInformation,
|
||||
FileIdGlobalTxDirectoryInformation,
|
||||
FileIsRemoteDeviceInformation,
|
||||
FileAttributeCacheInformation,
|
||||
FileNumaNodeInformation,
|
||||
FileStandardLinkInformation,
|
||||
FileRemoteProtocolInformation,
|
||||
FileMaximumInformation
|
||||
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _FILE_ID_FULL_DIR_INFORMATION {
|
||||
ULONG NextEntryOffset;
|
||||
ULONG FileIndex;
|
||||
LARGE_INTEGER CreationTime;
|
||||
LARGE_INTEGER LastAccessTime;
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
LARGE_INTEGER ChangeTime;
|
||||
LARGE_INTEGER EndOfFile;
|
||||
LARGE_INTEGER AllocationSize;
|
||||
ULONG FileAttributes;
|
||||
ULONG FileNameLength;
|
||||
ULONG EaSize;
|
||||
LARGE_INTEGER FileId;
|
||||
WCHAR FileName[1];
|
||||
} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;
|
||||
|
||||
typedef struct _IO_STATUS_BLOCK {
|
||||
union {
|
||||
NTSTATUS Status;
|
||||
PVOID Pointer;
|
||||
} u;
|
||||
ULONG_PTR Information;
|
||||
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||
|
||||
typedef VOID
|
||||
(NTAPI *PIO_APC_ROUTINE)(
|
||||
IN PVOID ApcContext,
|
||||
IN PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG Reserved);
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtQueryDirectoryFile(
|
||||
_In_ HANDLE FileHandle,
|
||||
_In_opt_ HANDLE Event,
|
||||
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
|
||||
_In_opt_ PVOID ApcContext,
|
||||
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
|
||||
_Out_ PVOID FileInformation,
|
||||
_In_ ULONG Length,
|
||||
_In_ FILE_INFORMATION_CLASS FileInformationClass,
|
||||
_In_ BOOLEAN ReturnSingleEntry,
|
||||
_In_opt_ PUNICODE_STRING FileName,
|
||||
_In_ BOOLEAN RestartScan
|
||||
);
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlNtStatusToDosError(
|
||||
NTSTATUS Status
|
||||
);
|
||||
|
||||
#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L)
|
||||
#define STATUS_NOT_A_DIRECTORY ((NTSTATUS)0xC0000103L)
|
||||
|
||||
#endif // _NTIFS_MIN_
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <jni.h>
|
||||
|
||||
extern NSMutableDictionary *sActions;
|
||||
extern NSMutableDictionary *sActionSelectors;
|
||||
extern NSMutableArray *sAllActionSelectors;
|
||||
void initializeActions();
|
||||
|
||||
@protocol JavaAccessibilityAction
|
||||
|
||||
|
||||
@@ -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))];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -50,17 +51,21 @@ static jclass sjc_CAccessibility = NULL;
|
||||
|
||||
NSSize getAxComponentSize(JNIEnv *env, jobject axComponent, jobject component)
|
||||
{
|
||||
GET_CACCESSIBILITY_CLASS_RETURN(NSZeroSize);
|
||||
DECLARE_CLASS_RETURN(jc_Dimension, "java/awt/Dimension", NSZeroSize);
|
||||
DECLARE_FIELD_RETURN(jf_width, jc_Dimension, "width", "I", NSZeroSize);
|
||||
DECLARE_FIELD_RETURN(jf_height, jc_Dimension, "height", "I", NSZeroSize);
|
||||
DECLARE_STATIC_METHOD_RETURN(jm_getSize, sjc_CAccessibility, "getSize",
|
||||
"(Ljavax/accessibility/AccessibleComponent;Ljava/awt/Component;)Ljava/awt/Dimension;", NSZeroSize);
|
||||
|
||||
jobject dimension = (*env)->CallStaticObjectMethod(env, jc_Dimension, jm_getSize, axComponent, component);
|
||||
jobject dimension = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getSize, axComponent, component);
|
||||
CHECK_EXCEPTION();
|
||||
|
||||
if (dimension == NULL) return NSZeroSize;
|
||||
return NSMakeSize((*env)->GetIntField(env, dimension, jf_width), (*env)->GetIntField(env, dimension, jf_height));
|
||||
|
||||
NSSize size = NSMakeSize((*env)->GetIntField(env, dimension, jf_width), (*env)->GetIntField(env, dimension, jf_height));
|
||||
(*env)->DeleteLocalRef(env, dimension);
|
||||
return size;
|
||||
}
|
||||
|
||||
NSString *getJavaRole(JNIEnv *env, jobject axComponent, jobject component)
|
||||
@@ -199,6 +204,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);
|
||||
@@ -211,7 +230,9 @@ NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject
|
||||
axComponent, component);
|
||||
CHECK_EXCEPTION();
|
||||
if (jpoint == NULL) return NSZeroPoint;
|
||||
return NSMakePoint((*env)->GetIntField(env, jpoint, sjf_X), (*env)->GetIntField(env, jpoint, sjf_Y));
|
||||
NSPoint p = NSMakePoint((*env)->GetIntField(env, jpoint, sjf_X), (*env)->GetIntField(env, jpoint, sjf_Y));
|
||||
(*env)->DeleteLocalRef(env, jpoint);
|
||||
return p;
|
||||
}
|
||||
|
||||
jint getAxTextCharCount(JNIEnv *env, jobject axText, jobject component)
|
||||
@@ -348,6 +369,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 +507,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"];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -39,7 +39,7 @@
|
||||
- (id _Nonnull) accessibilityValue
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
return [self accessibilityValueAttribute];
|
||||
return [super accessibilityValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#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);
|
||||
|
||||
static jmethodID sjm_getAccessibleSelection = NULL;
|
||||
#define GET_ACCESSIBLESELECTION_METHOD_RETURN(ret) \
|
||||
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
|
||||
GET_STATIC_METHOD_RETURN(sjm_getAccessibleSelection, sjc_CAccessibility, "getAccessibleSelection", \
|
||||
"(Ljavax/accessibility/AccessibleContext;Ljava/awt/Component;)Ljavax/accessibility/AccessibleSelection;", ret);
|
||||
|
||||
@implementation ComboBoxAccessibility
|
||||
|
||||
// NSAccessibilityElement protocol methods
|
||||
|
||||
- (id)accessibilityValue {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject axContext = [self axContextWithEnv:env];
|
||||
if (axContext == NULL) return nil;
|
||||
GET_ACCESSIBLESELECTION_METHOD_RETURN(nil);
|
||||
jobject axSelection = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleSelection, axContext, self->fComponent);
|
||||
CHECK_EXCEPTION();
|
||||
if (axSelection == NULL) {
|
||||
return nil;
|
||||
}
|
||||
jclass axSelectionClass = (*env)->GetObjectClass(env, axSelection);
|
||||
DECLARE_METHOD_RETURN(jm_getAccessibleSelection, axSelectionClass, "getAccessibleSelection", "(I)Ljavax/accessibility/Accessible;", nil);
|
||||
jobject axSelectedChild = (*env)->CallObjectMethod(env, axSelection, jm_getAccessibleSelection, 0);
|
||||
CHECK_EXCEPTION();
|
||||
(*env)->DeleteLocalRef(env, axSelection);
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
if (axSelectedChild == NULL) {
|
||||
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
|
||||
@@ -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
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -36,7 +36,17 @@
|
||||
|
||||
- (NSString * _Nullable)accessibilityLabel
|
||||
{
|
||||
return [self accessibilityTitleAttribute];
|
||||
return [super accessibilityLabel];
|
||||
}
|
||||
|
||||
- (NSRect)accessibilityFrame
|
||||
{
|
||||
return [super accessibilityFrame];
|
||||
}
|
||||
|
||||
- (id)accessibilityParent
|
||||
{
|
||||
return [super accessibilityParent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -39,7 +39,7 @@
|
||||
- (id _Nonnull) accessibilityValue
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
return [self accessibilityValueAttribute];
|
||||
return [super accessibilityValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -47,4 +47,14 @@
|
||||
return [self accessibilityVisibleCharacterRangeAttribute];
|
||||
}
|
||||
|
||||
- (NSRect)accessibilityFrame
|
||||
{
|
||||
return [super accessibilityFrame];
|
||||
}
|
||||
|
||||
- (id)accessibilityParent
|
||||
{
|
||||
return [super accessibilityParent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -86,7 +86,8 @@
|
||||
isAA:(jboolean)isAA;
|
||||
|
||||
- (id<MTLRenderCommandEncoder> _Nonnull)getTextEncoder:(const BMTLSDOps * _Nonnull)dstOps
|
||||
isSrcOpaque:(bool)isSrcOpaque;
|
||||
isSrcOpaque:(bool)isSrcOpaque
|
||||
gammaCorrection:(bool)gmc;
|
||||
|
||||
// Base method to obtain any MTLRenderCommandEncoder
|
||||
- (id<MTLRenderCommandEncoder> _Nonnull) getEncoder:(id<MTLTexture> _Nonnull)dest
|
||||
|
||||
@@ -40,19 +40,18 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||
- (id)init;
|
||||
- (void)dealloc;
|
||||
|
||||
- (void)reset:(id<MTLTexture>)destination
|
||||
isDstOpaque:(jboolean)isDstOpaque
|
||||
isDstPremultiplied:(jboolean)isDstPremultiplied
|
||||
isAA:(jboolean)isAA
|
||||
isText:(jboolean)isText
|
||||
isLCD:(jboolean)isLCD;
|
||||
- (void) reset:(id<MTLTexture>)destination
|
||||
isDstOpaque:(jboolean)isDstOpaque
|
||||
isDstPremultiplied:(jboolean)isDstPremultiplied
|
||||
isAA:(jboolean)isAA
|
||||
isGMCText:(jboolean)isGMCText
|
||||
isLCD:(jboolean)isLCD;
|
||||
|
||||
- (void)updateEncoder:(id<MTLRenderCommandEncoder>)encoder
|
||||
context:(MTLContext *)mtlc
|
||||
renderOptions:(const RenderOptions *)renderOptions
|
||||
forceUpdate:(jboolean)forceUpdate;
|
||||
@property (assign) jboolean aa;
|
||||
@property (assign) jboolean text;
|
||||
@property (assign) jboolean lcd;
|
||||
@property (assign) jboolean aaShader;
|
||||
@property (retain) MTLPaint* paint;
|
||||
@@ -67,7 +66,7 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||
SurfaceRasterFlags _dstFlags;
|
||||
|
||||
jboolean _isAA;
|
||||
jboolean _isText;
|
||||
jboolean _isGMCText;
|
||||
jboolean _isLCD;
|
||||
jboolean _isAAShader;
|
||||
|
||||
@@ -93,7 +92,6 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||
MTLTransform * _transform;
|
||||
}
|
||||
@synthesize aa = _isAA;
|
||||
@synthesize text = _isText;
|
||||
@synthesize lcd = _isLCD;
|
||||
@synthesize aaShader = _isAAShader;
|
||||
@synthesize paint = _paint;
|
||||
@@ -126,13 +124,13 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||
isDstOpaque:(jboolean)isDstOpaque
|
||||
isDstPremultiplied:(jboolean)isDstPremultiplied
|
||||
isAA:(jboolean)isAA
|
||||
isText:(jboolean)isText
|
||||
isGMCText:(jboolean)isGMCText
|
||||
isLCD:(jboolean)isLCD {
|
||||
_destination = destination;
|
||||
_dstFlags.isOpaque = isDstOpaque;
|
||||
_dstFlags.isPremultiplied = isDstPremultiplied;
|
||||
_isAA = isAA;
|
||||
_isText = isText;
|
||||
_isGMCText = isGMCText;
|
||||
_isLCD = isLCD;
|
||||
// NOTE: probably it's better to invalidate/reset all cached states now
|
||||
}
|
||||
@@ -182,7 +180,7 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||
&& (_isTexture == renderOptions->isTexture && (!renderOptions->isTexture || _interpolationMode == renderOptions->interpolation)) // interpolation is used only in texture mode
|
||||
&& _isAA == renderOptions->isAA
|
||||
&& _isAAShader == renderOptions->isAAShader
|
||||
&& _isText == renderOptions->isText
|
||||
&& _isGMCText == renderOptions->isGMCText
|
||||
&& _isLCD == renderOptions->isLCD
|
||||
&& _srcFlags.isOpaque == renderOptions->srcFlags.isOpaque && _srcFlags.isPremultiplied == renderOptions->srcFlags.isPremultiplied)
|
||||
return;
|
||||
@@ -193,7 +191,7 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||
_interpolationMode = renderOptions->interpolation;
|
||||
_isAA = renderOptions->isAA;
|
||||
_isAAShader = renderOptions->isAAShader;
|
||||
_isText = renderOptions->isText;
|
||||
_isGMCText = renderOptions->isGMCText;
|
||||
_isLCD = renderOptions->isLCD;
|
||||
_srcFlags = renderOptions->srcFlags;
|
||||
|
||||
@@ -352,9 +350,11 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||
}
|
||||
|
||||
- (id<MTLRenderCommandEncoder> _Nonnull) getTextEncoder:(const BMTLSDOps * _Nonnull)dstOps
|
||||
isSrcOpaque:(bool)isSrcOpaque
|
||||
isSrcOpaque:(bool)isSrcOpaque
|
||||
gammaCorrection:(bool)gmc
|
||||
{
|
||||
RenderOptions roptions = {JNI_TRUE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, { isSrcOpaque, JNI_TRUE }, {dstOps->isOpaque, JNI_TRUE}, JNI_TRUE, JNI_FALSE, JNI_FALSE};
|
||||
RenderOptions roptions = {JNI_TRUE, JNI_FALSE, INTERPOLATION_NEAREST_NEIGHBOR, { isSrcOpaque, JNI_TRUE },
|
||||
{dstOps->isOpaque, JNI_TRUE}, gmc, JNI_FALSE, JNI_FALSE};
|
||||
return [self getEncoder:dstOps->pTexture renderOptions:&roptions];
|
||||
}
|
||||
|
||||
@@ -437,11 +437,11 @@ const SurfaceRasterFlags defaultRasterFlags = { JNI_FALSE, JNI_TRUE };
|
||||
_encoder = [[cbw getCommandBuffer] renderCommandEncoderWithDescriptor:rpd];
|
||||
|
||||
[_encoderStates reset:dest
|
||||
isDstOpaque:renderOptions->dstFlags.isOpaque
|
||||
isDstPremultiplied:YES
|
||||
isAA:renderOptions->isAA
|
||||
isText:renderOptions->isText
|
||||
isLCD:renderOptions->isLCD];
|
||||
isDstOpaque:renderOptions->dstFlags.isOpaque
|
||||
isDstPremultiplied:YES
|
||||
isAA:renderOptions->isAA
|
||||
isGMCText:renderOptions->isGMCText
|
||||
isLCD:renderOptions->isLCD];
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -56,7 +56,8 @@ static MTLRenderPipelineDescriptor * templateLCDPipelineDesc = nil;
|
||||
static MTLRenderPipelineDescriptor * templateAAPipelineDesc = nil;
|
||||
static void
|
||||
setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder, int interpolation, bool repeat,
|
||||
jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, const SurfaceRasterFlags *dstFlags, int mode);
|
||||
jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, const SurfaceRasterFlags *dstFlags, int mode,
|
||||
bool gmcText);
|
||||
|
||||
static void initTemplatePipelineDescriptors() {
|
||||
if (templateRenderPipelineDesc != nil && templateTexturePipelineDesc != nil &&
|
||||
@@ -189,6 +190,7 @@ jint _color;
|
||||
|
||||
NSString *vertShader = @"vert_col";
|
||||
NSString *fragShader = @"frag_col";
|
||||
bool gmcText = NO;
|
||||
|
||||
if (renderOptions->isTexture) {
|
||||
vertShader = @"vert_txt";
|
||||
@@ -198,8 +200,9 @@ jint _color;
|
||||
fragShader = @"aa_frag_txt";
|
||||
rpDesc = [[templateAATexturePipelineDesc copy] autorelease];
|
||||
}
|
||||
if (renderOptions->isText) {
|
||||
fragShader = @"frag_text";
|
||||
if (renderOptions->isGMCText) {
|
||||
fragShader = @"frag_gmc_text";
|
||||
gmcText = YES;
|
||||
}
|
||||
if (renderOptions->isLCD) {
|
||||
vertShader = @"vert_txt_lcd";
|
||||
@@ -208,7 +211,7 @@ jint _color;
|
||||
}
|
||||
setTxtUniforms(mtlc, _color, encoder,
|
||||
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha], &renderOptions->srcFlags,
|
||||
&renderOptions->dstFlags, 1);
|
||||
&renderOptions->dstFlags, 1, gmcText);
|
||||
} else if (renderOptions->isAAShader) {
|
||||
vertShader = @"vert_col_aa";
|
||||
fragShader = @"frag_col_aa";
|
||||
@@ -251,7 +254,7 @@ jint _color;
|
||||
|
||||
setTxtUniforms(mtlc, col, encoder,
|
||||
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
|
||||
&renderOptions->srcFlags, &renderOptions->dstFlags, 1);
|
||||
&renderOptions->srcFlags, &renderOptions->dstFlags, 1, NO);
|
||||
[encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex:0];
|
||||
|
||||
[encoder setFragmentTexture:dstOps->pTexture atIndex:1];
|
||||
@@ -792,7 +795,7 @@ jint _color;
|
||||
const SurfaceRasterFlags srcFlags = {_isOpaque, renderOptions->srcFlags.isPremultiplied};
|
||||
setTxtUniforms(mtlc, 0, encoder,
|
||||
renderOptions->interpolation, YES, [mtlc.composite getExtraAlpha],
|
||||
&srcFlags, &renderOptions->dstFlags, 0);
|
||||
&srcFlags, &renderOptions->dstFlags, 0, NO);
|
||||
|
||||
id <MTLRenderPipelineState> pipelineState = [pipelineStateStorage getPipelineState:rpDesc
|
||||
vertexShaderId:vertShader
|
||||
@@ -874,9 +877,41 @@ jint _color;
|
||||
|
||||
static void
|
||||
setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder, int interpolation, bool repeat,
|
||||
jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, const SurfaceRasterFlags *dstFlags, int mode) {
|
||||
struct TxtFrameUniforms uf = {RGBA_TO_V4(color), mode, srcFlags->isOpaque, dstFlags->isOpaque, extraAlpha};
|
||||
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||
jfloat extraAlpha, const SurfaceRasterFlags *srcFlags, const SurfaceRasterFlags *dstFlags, int mode,
|
||||
bool gmcText)
|
||||
{
|
||||
if (gmcText) {
|
||||
float ca = (((color) >> 24) & 0xFF)/255.0f;
|
||||
float cr = (((color) >> 16) & (0xFF))/255.0f;
|
||||
float cg = (((color) >> 8) & 0xFF)/255.0f;
|
||||
float cb = ((color) & 0xFF)/255.0f;
|
||||
float inv_light_gamma = 1.666f;
|
||||
float inv_dark_gamma = 0.333f;
|
||||
float inv_light_exp = 0.454f;
|
||||
float inv_dark_exp = 1.4f;
|
||||
|
||||
// calculate brightness of the fragment
|
||||
float b = (cr/3.0f + cg/3.0f + cb/3.0f)*ca;
|
||||
|
||||
// adjust fragment coverage
|
||||
float exp = inv_dark_exp*(1.0f - b) + inv_light_exp*b;
|
||||
|
||||
// adjust fragment color and alpha for alpha < 1.0
|
||||
if (ca < 1.0f) {
|
||||
float g = inv_dark_gamma*(1.0f - b) + inv_light_gamma*b;
|
||||
cr = pow(cr, g);
|
||||
cg = pow(cr, g);
|
||||
cb = pow(cr, g);
|
||||
ca = pow(ca, exp);
|
||||
}
|
||||
|
||||
struct GMCFrameUniforms uf = {{cr, cg, cb, ca}, exp};
|
||||
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||
} else {
|
||||
struct TxtFrameUniforms uf =
|
||||
{RGBA_TO_V4(color), mode, srcFlags->isOpaque, dstFlags->isOpaque, extraAlpha};
|
||||
[encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
|
||||
}
|
||||
[mtlc.samplerManager setSamplerWithEncoder:encoder interpolation:interpolation repeat:repeat];
|
||||
}
|
||||
|
||||
@@ -938,7 +973,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder
|
||||
setTxtUniforms(mtlc, 0, encoder,
|
||||
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
|
||||
&renderOptions->srcFlags,
|
||||
&renderOptions->dstFlags, 0);
|
||||
&renderOptions->dstFlags, 0, NO);
|
||||
|
||||
}
|
||||
id <MTLRenderPipelineState> pipelineState = [pipelineStateStorage getPipelineState:rpDesc
|
||||
@@ -969,7 +1004,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder
|
||||
const int col = 0 ^ xorColor;
|
||||
setTxtUniforms(mtlc, col, encoder,
|
||||
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
|
||||
&renderOptions->srcFlags, &renderOptions->dstFlags, 0);
|
||||
&renderOptions->srcFlags, &renderOptions->dstFlags, 0, NO);
|
||||
[encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex: 0];
|
||||
|
||||
BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination();
|
||||
@@ -978,7 +1013,7 @@ setTxtUniforms(MTLContext *mtlc, int color, id <MTLRenderCommandEncoder> encoder
|
||||
setTxtUniforms(mtlc, 0, encoder,
|
||||
renderOptions->interpolation, NO, [mtlc.composite getExtraAlpha],
|
||||
&renderOptions->srcFlags,
|
||||
&renderOptions->dstFlags, 0);
|
||||
&renderOptions->dstFlags, 0, NO);
|
||||
|
||||
id <MTLRenderPipelineState> pipelineState = [pipelineStateStorage getPipelineState:rpDesc
|
||||
vertexShaderId:vertShader
|
||||
|
||||
@@ -297,7 +297,8 @@ J2dTraceLn(J2D_TRACE_INFO, "MTLTR_EnableGlyphVertexCache");
|
||||
return;
|
||||
}
|
||||
}
|
||||
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);
|
||||
|
||||
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps, YES);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -82,5 +82,5 @@ void
|
||||
MTLVertexCache_AddGlyphQuad(MTLContext *mtlc,
|
||||
jfloat tx1, jfloat ty1, jfloat tx2, jfloat ty2,
|
||||
jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2);
|
||||
void MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps);
|
||||
void MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps, bool gmc);
|
||||
#endif /* MTLVertexCache_h_Included */
|
||||
|
||||
@@ -44,6 +44,7 @@ static jint vertexCacheIndex = 0;
|
||||
|
||||
static MTLPooledTextureHandle * maskCacheTex = NULL;
|
||||
static jint maskCacheIndex = 0;
|
||||
static bool gammaCorrection = NO;
|
||||
static id<MTLRenderCommandEncoder> encoder = NULL;
|
||||
|
||||
#define MTLVC_ADD_VERTEX(TX, TY, DX, DY, DZ) \
|
||||
@@ -182,7 +183,7 @@ MTLVertexCache_EnableMaskCache(MTLContext *mtlc, BMTLSDOps *dstOps)
|
||||
return;
|
||||
}
|
||||
}
|
||||
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);
|
||||
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps, gammaCorrection);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -194,15 +195,18 @@ MTLVertexCache_DisableMaskCache(MTLContext *mtlc)
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_DisableMaskCache");
|
||||
MTLVertexCache_FlushVertexCache(mtlc);
|
||||
maskCacheIndex = 0;
|
||||
gammaCorrection = NO;
|
||||
free(vertexCache);
|
||||
vertexCache = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps) {
|
||||
MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps, bool gmc) {
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_CreateSamplingEncoder");
|
||||
gammaCorrection = gmc;
|
||||
encoder = [mtlc.encoderManager getTextEncoder:dstOps
|
||||
isSrcOpaque:NO];
|
||||
isSrcOpaque:NO
|
||||
gammaCorrection:gmc];
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -36,7 +36,7 @@ typedef struct {
|
||||
int interpolation;
|
||||
SurfaceRasterFlags srcFlags;
|
||||
SurfaceRasterFlags dstFlags;
|
||||
jboolean isText;
|
||||
jboolean isGMCText;
|
||||
jboolean isLCD;
|
||||
jboolean isAAShader;
|
||||
} RenderOptions;
|
||||
|
||||
@@ -157,6 +157,11 @@ struct LCDFrameUniforms {
|
||||
vector_float3 invgamma;
|
||||
};
|
||||
|
||||
struct GMCFrameUniforms {
|
||||
vector_float4 color;
|
||||
float exp;
|
||||
};
|
||||
|
||||
struct SwizzleUniforms {
|
||||
unsigned char swizzle[4];
|
||||
unsigned char hasAlpha;
|
||||
|
||||
@@ -332,6 +332,20 @@ fragment half4 frag_text(
|
||||
return half4(uniforms.color * pixelColor.a);
|
||||
}
|
||||
|
||||
fragment half4 frag_gmc_text(
|
||||
TxtShaderInOut vert [[stage_in]],
|
||||
texture2d<float, access::sample> renderTexture [[texture(0)]],
|
||||
constant GMCFrameUniforms& uniforms [[buffer(1)]],
|
||||
sampler textureSampler [[sampler(0)]]
|
||||
) {
|
||||
float4 pixelColor = renderTexture.sample(textureSampler, vert.texCoords);
|
||||
float a = uniforms.color.a;
|
||||
float3 col = uniforms.color.rgb;
|
||||
// adjust fragment coverage
|
||||
float frag_cov = pow(pixelColor.a, uniforms.exp);
|
||||
return half4(col.r*frag_cov, col.g*frag_cov, col.b*frag_cov, a*frag_cov);
|
||||
}
|
||||
|
||||
fragment half4 frag_txt_tp(TxtShaderInOut vert [[stage_in]],
|
||||
texture2d<float, access::sample> renderTexture [[texture(0)]],
|
||||
texture2d<float, access::sample> paintTexture [[texture(1)]],
|
||||
|
||||
@@ -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) { \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 (Insets)cachedInsets.computeIfAbsent(gc, this::getScreenInsetsImpl).clone();
|
||||
} 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")));
|
||||
}
|
||||
|
||||
@@ -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,33 @@ public final class X11GraphicsDevice extends GraphicsDevice
|
||||
return rect;
|
||||
}
|
||||
|
||||
private Rectangle boundsCached;
|
||||
private final Object boundsCacheLock = new Object();
|
||||
|
||||
private Rectangle getBoundsCached() {
|
||||
synchronized (boundsCacheLock) {
|
||||
if (boundsCached == null) {
|
||||
boundsCached = getBoundsImpl();
|
||||
}
|
||||
return boundsCached;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetBoundsCache() {
|
||||
synchronized (boundsCacheLock) {
|
||||
boundsCached = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Rectangle getBounds() {
|
||||
if (X11GraphicsEnvironment.useBoundsCache()) {
|
||||
return new Rectangle(getBoundsCached());
|
||||
}
|
||||
else {
|
||||
return getBoundsImpl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identification string associated with this graphics
|
||||
* device.
|
||||
@@ -633,5 +661,6 @@ public final class X11GraphicsDevice extends GraphicsDevice
|
||||
|
||||
public void invalidate(X11GraphicsDevice device) {
|
||||
screen = device.screen;
|
||||
if (X11GraphicsEnvironment.useBoundsCache()) resetBoundsCache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
110
src/java.desktop/unix/native/libawt_xawt/xawt/keycode_cache.c
Normal file
110
src/java.desktop/unix/native/libawt_xawt/xawt/keycode_cache.c
Normal 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 */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user