mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-27 03:39:40 +01:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
363650bbf4 | ||
|
|
420865b278 | ||
|
|
f60792e700 | ||
|
|
46829b3102 | ||
|
|
dda07e42db | ||
|
|
fc1fc0fd8e | ||
|
|
814f267c04 | ||
|
|
6ba79774d8 | ||
|
|
c63802fe59 | ||
|
|
37975e6b67 | ||
|
|
24ccad3a09 | ||
|
|
b146b6d64e | ||
|
|
42c3f9235d | ||
|
|
f9483505d9 | ||
|
|
37d2b153a6 | ||
|
|
21a4de02a2 | ||
|
|
a0da2bd267 | ||
|
|
4fd22dd235 | ||
|
|
ce379a03cd | ||
|
|
da41adf366 | ||
|
|
c7d8fa3914 | ||
|
|
18e0b4fa5c | ||
|
|
025e3f0f76 | ||
|
|
e068de8629 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,7 +6,6 @@ JTreport
|
||||
.idea/modules.xml
|
||||
.idea/shelf/
|
||||
JetBrainsRuntime.iml
|
||||
build/
|
||||
# Project exclude paths
|
||||
/jb/project/java-gradle/.gradle/
|
||||
/build/
|
||||
|
||||
@@ -8,7 +8,7 @@ HEAD_REVISION=0
|
||||
|
||||
function do_exit() {
|
||||
exit_code=$1
|
||||
[ $do_reset_changes -eq 1 ] && git checkout HEAD modules.list src/java.desktop/share/classes/module-info.java
|
||||
[ $do_reset_changes -eq 1 ] && git checkout HEAD jb/project/tools/common/modules.list src/java.desktop/share/classes/module-info.java
|
||||
if [ $do_reset_dcevm -eq 1 ]; then
|
||||
[ ! -z $HEAD_REVISION ] && git reset --hard $HEAD_REVISION
|
||||
fi
|
||||
|
||||
@@ -82,7 +82,7 @@ JBR_BASE_NAME=jbr-$JBSDK_VERSION
|
||||
rm -rf $BASE_DIR/$JBR_BUNDLE
|
||||
|
||||
JBR=$JBR_BASE_NAME-linux-aarch64-b$build_number
|
||||
grep -v javafx modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.aarch64
|
||||
grep -v javafx jb/project/tools/common/modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.aarch64
|
||||
echo Running jlink....
|
||||
${JSDK}/bin/jlink \
|
||||
--module-path ${JSDK}/jmods --no-man-pages --compress=2 \
|
||||
|
||||
@@ -70,7 +70,7 @@ function create_jbr {
|
||||
echo "***ERR*** bundle was not specified" && do_exit 1
|
||||
;;
|
||||
esac
|
||||
cat modules.list > modules_tmp.list
|
||||
cat jb/project/tools/common/modules.list > modules_tmp.list
|
||||
rm -rf ${BASE_DIR}/${JBR_BUNDLE}
|
||||
|
||||
JBR=${JBR_BASE_NAME}-linux-x64-b${build_number}
|
||||
@@ -167,4 +167,4 @@ if [ "$bundle_type" == "jcef" ]; then
|
||||
gzip -f ${JBRSDK_TEST}.tar || do_exit $?
|
||||
fi
|
||||
|
||||
do_exit 0
|
||||
do_exit 0
|
||||
|
||||
@@ -63,7 +63,7 @@ JBR_BASE_NAME=jbr-$JBSDK_VERSION
|
||||
rm -rf $BASE_DIR/$JBR_BUNDLE
|
||||
|
||||
JBR=$JBR_BASE_NAME-linux-x86-b$build_number
|
||||
grep -v javafx modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.x86
|
||||
grep -v javafx jb/project/tools/common/modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.x86
|
||||
echo Running jlink....
|
||||
${JSDK}/bin/jlink \
|
||||
--module-path ${JSDK}/jmods --no-man-pages --compress=2 \
|
||||
@@ -79,4 +79,4 @@ gzip $JBR.tar || exit $?
|
||||
JBRSDK_TEST=$JBRSDK_BASE_NAME-linux-test-x86-b$build_number
|
||||
echo Creating $JBRSDK_TEST.tar.gz ...
|
||||
tar -pcf $JBRSDK_TEST.tar -C $BASE_DIR --exclude='test/jdk/demos' --exclude='test/hotspot/gtest' test || exit $?
|
||||
gzip $JBRSDK_TEST.tar || exit $?
|
||||
gzip $JBRSDK_TEST.tar || exit $?
|
||||
|
||||
@@ -103,11 +103,11 @@ function create_jbr {
|
||||
if [[ "${architecture}" == *aarch64* ]] && [[ "${enable_aot}" != *enable_aot* ]]; then
|
||||
# aot isn't supported yet, so remove dependent modules
|
||||
echo "Exclude jdk.internal.vm.compiler and jdk.aot (because aot not supported yet)"
|
||||
cat modules.list | \
|
||||
cat jb/project/tools/common/modules.list | \
|
||||
grep -v "jdk.internal.vm.compiler\|jdk.aot" \
|
||||
> modules_tmp.list
|
||||
else
|
||||
cat modules.list > modules_tmp.list
|
||||
cat jb/project/tools/common/modules.list > modules_tmp.list
|
||||
fi
|
||||
rm -rf ${BASE_DIR}/${JBR_BUNDLE}
|
||||
|
||||
@@ -218,4 +218,4 @@ if [ "$bundle_type" == "jcef" ]; then
|
||||
--exclude='test/jdk/demos' test || do_exit $?
|
||||
fi
|
||||
|
||||
do_exit 0
|
||||
do_exit 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
diff --git modules.list modules.list
|
||||
diff --git jb/project/tools/common/modules.list jb/project/tools/common/modules.list
|
||||
index 33375b527c4..76539cbc0e0 100644
|
||||
--- modules.list
|
||||
+++ modules.list
|
||||
--- jb/project/tools/common/modules.list
|
||||
+++ jb/project/tools/common/modules.list
|
||||
@@ -55,4 +55,7 @@ jdk.unsupported,
|
||||
jdk.xml.dom,
|
||||
jdk.zipfs,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
diff --git modules.list modules.list
|
||||
diff --git jb/project/tools/common/modules.list jb/project/tools/common/modules.list
|
||||
index 33375b527c4..76539cbc0e0 100644
|
||||
--- modules.list
|
||||
+++ modules.list
|
||||
--- jb/project/tools/common/modules.list
|
||||
+++ jb/project/tools/common/modules.list
|
||||
@@ -55,4 +55,5 @@ jdk.unsupported,
|
||||
jdk.xml.dom,
|
||||
jdk.zipfs,
|
||||
|
||||
72
jb/project/tools/test/check_jbr_size.sh
Normal file
72
jb/project/tools/test/check_jbr_size.sh
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
NEWFILEPATH=$1
|
||||
CONFIGID=$2
|
||||
BUILDID=$3
|
||||
TOKEN=$4
|
||||
#
|
||||
# Get the size of new artifact
|
||||
#
|
||||
unameOut="$(uname -s)"
|
||||
case "${unameOut}" in
|
||||
Linux*)
|
||||
NEWFILESIZE=$(stat -c%s "$NEWFILEPATH")
|
||||
;;
|
||||
Darwin*)
|
||||
NEWFILESIZE=$(stat -f%z "$NEWFILEPATH")
|
||||
;;
|
||||
CYGWIN*)
|
||||
NEWFILESIZE=$(stat -c%s "$NEWFILEPATH")
|
||||
;;
|
||||
MINGW*)
|
||||
NEWFILESIZE=$(stat -c%s "$NEWFILEPATH")
|
||||
;;
|
||||
*)
|
||||
echo "Unknown machine: ${unameOut}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
echo "New size of $NEWFILEPATH = $NEWFILESIZE bytes."
|
||||
|
||||
# example: IntellijCustomJdk_Jdk17_Master_LinuxX64jcef
|
||||
|
||||
CURL_RESPONSE=$(curl --header "Authorization: Bearer $TOKEN" "https://buildserver.labs.intellij.net/app/rest/builds/?locator=buildType:(id:$CONFIGID),status:success,count:1,finishDate:(build:$BUILDID,condition:before)")
|
||||
|
||||
re='id=\"([0-9]+)\".+number=\"([0-9]+)\"'
|
||||
ID=0
|
||||
|
||||
if [[ $CURL_RESPONSE =~ $re ]]; then
|
||||
ID=${BASH_REMATCH[1]}
|
||||
echo "BUILD Number: ${BASH_REMATCH[2]}"
|
||||
else
|
||||
echo "ERROR: can't find previous build"
|
||||
echo $CURL_RESPONSE
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CURL_RESPONSE=$(curl --header "Authorization: Bearer $TOKEN" "https://buildserver.labs.intellij.net/app/rest/builds/$ID?fields=id,number,artifacts(file(name,size))")
|
||||
|
||||
echo "Atrifacts of last pinned build of $CONFIGID :\n"
|
||||
echo $CURL_RESPONSE
|
||||
|
||||
# Find size (in response) with reg exp
|
||||
re='name=\"(jbrsdk[^\"]+\.tar\.gz)\" size=\"([0-9]+)\"'
|
||||
|
||||
if [[ $CURL_RESPONSE =~ $re ]]; then
|
||||
OLDFILENAME=${BASH_REMATCH[1]}
|
||||
echo "Prev artifact name: $OLDFILENAME"
|
||||
OLDFILESIZE=${BASH_REMATCH[2]}
|
||||
echo "Prev artifact size = $OLDFILESIZE"
|
||||
|
||||
let allowedSize=OLDFILESIZE+OLDFILESIZE/20 # use 5% threshold
|
||||
echo "Allowed size = $allowedSize"
|
||||
if [[ "$NEWFILESIZE" -gt "$allowedSize" ]]; then
|
||||
echo "ERROR: new size is significally greater than prev size (need to investigate)"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "ERROR: can't find string with size in xml response:"
|
||||
echo $CURL_RESPONSE
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -81,9 +81,10 @@ function create_jbr {
|
||||
esac
|
||||
|
||||
echo "Exclude jdk.internal.vm.compiler and jdk.aot (because aot is not supported yet)"
|
||||
cat modules.list | \
|
||||
cat jb/project/tools/common/modules.list | \
|
||||
grep -v "jdk.internal.vm.compiler\|jdk.aot" \
|
||||
> modules_tmp.list
|
||||
echo ",jdk.crypto.mscapi" >> modules_tmp.list
|
||||
|
||||
rm -rf ${JBR_BUNDLE}
|
||||
|
||||
@@ -160,4 +161,4 @@ fi
|
||||
|
||||
create_jbr || do_exit $?
|
||||
|
||||
do_exit 0
|
||||
do_exit 0
|
||||
|
||||
@@ -75,7 +75,8 @@ function create_jbr {
|
||||
echo "***ERR*** bundle was not specified" && do_exit 1
|
||||
;;
|
||||
esac
|
||||
cat modules.list > modules_tmp.list
|
||||
cat jb/project/tools/common/modules.list > modules_tmp.list
|
||||
echo ",jdk.crypto.mscapi" >> modules_tmp.list
|
||||
rm -rf ${JBR_BUNDLE}
|
||||
|
||||
echo Running jlink....
|
||||
@@ -151,4 +152,4 @@ fi
|
||||
|
||||
create_jbr || do_exit $?
|
||||
|
||||
do_exit 0
|
||||
do_exit 0
|
||||
|
||||
@@ -57,7 +57,8 @@ mv release ${JBRSDK_BUNDLE}/release
|
||||
|
||||
JBR_BUNDLE=jbr
|
||||
rm -rf ${JBR_BUNDLE}
|
||||
grep -v javafx modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.x86
|
||||
grep -v javafx jb/project/tools/common/modules.list | grep -v "jdk.internal.vm\|jdk.aot\|jcef" > modules.list.x86
|
||||
echo ",jdk.crypto.mscapi" >> modules.list.x86
|
||||
${JSDK}/bin/jlink \
|
||||
--module-path ${JSDK}/jmods --no-man-pages --compress=2 \
|
||||
--add-modules $(xargs < modules.list.x86 | sed s/" "//g) --output ${JBR_BUNDLE} || exit $?
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.jetbrains.internal;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -158,13 +159,52 @@ public class JBRApi {
|
||||
RegisteredProxyInfo info = registeredProxyInfoByTargetName.get(targetName);
|
||||
if (info == null) return null;
|
||||
try {
|
||||
return (info.type == ProxyInfo.Type.CLIENT_PROXY ? info.apiModule : outerLookup)
|
||||
return (info.type.isPublicApi() ? outerLookup : info.apiModule)
|
||||
.findClass(info.interfaceName);
|
||||
} catch (ClassNotFoundException | IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static InternalServiceBuilder internalServiceBuilder(Lookup interFace, String target) {
|
||||
return new InternalServiceBuilder(new RegisteredProxyInfo(
|
||||
interFace, interFace.lookupClass().getName(), target, ProxyInfo.Type.INTERNAL_SERVICE, new ArrayList<>()));
|
||||
}
|
||||
|
||||
public static class InternalServiceBuilder {
|
||||
|
||||
private final RegisteredProxyInfo info;
|
||||
|
||||
private InternalServiceBuilder(RegisteredProxyInfo info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public InternalServiceBuilder withStatic(String methodName, String clazz) {
|
||||
return withStatic(methodName, clazz, methodName);
|
||||
}
|
||||
|
||||
public InternalServiceBuilder withStatic(String interfaceMethodName, String clazz, String methodName) {
|
||||
info.staticMethods.add(
|
||||
new RegisteredProxyInfo.StaticMethodMapping(interfaceMethodName, clazz, methodName));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object build() {
|
||||
ProxyInfo info = ProxyInfo.resolve(this.info);
|
||||
if (info == null) return null;
|
||||
ProxyGenerator generator = new ProxyGenerator(info);
|
||||
if (!generator.areAllMethodsImplemented()) return null;
|
||||
generator.defineClasses();
|
||||
MethodHandle constructor = generator.findConstructor();
|
||||
generator.init();
|
||||
try {
|
||||
return constructor.invoke();
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@linkplain com.jetbrains.bootstrap.JBRApiBootstrap#MODULES registry classes}
|
||||
* to register a new mapping for corresponding modules.
|
||||
|
||||
@@ -78,7 +78,7 @@ class ProxyGenerator {
|
||||
*/
|
||||
ProxyGenerator(ProxyInfo info) {
|
||||
this.info = info;
|
||||
generateBridge = info.type != ProxyInfo.Type.CLIENT_PROXY;
|
||||
generateBridge = info.type.isPublicApi();
|
||||
int nameId = nameCounter.getAndIncrement();
|
||||
proxyName = Type.getInternalName(info.interFace) + "$$JBRApiProxy$" + nameId;
|
||||
bridgeName = generateBridge ? info.apiModule.lookupClass().getPackageName().replace('.', '/') + "/" +
|
||||
@@ -153,7 +153,7 @@ class ProxyGenerator {
|
||||
} else {
|
||||
MethodHandle c = generatedProxy.findConstructor(generatedProxy.lookupClass(),
|
||||
MethodType.methodType(void.class, Object.class));
|
||||
if (info.type == ProxyInfo.Type.SERVICE) {
|
||||
if (info.type.isService()) {
|
||||
try {
|
||||
return MethodHandles.foldArguments(c, info.target.findConstructor(info.target.lookupClass(),
|
||||
MethodType.methodType(void.class)).asType(MethodType.methodType(Object.class)));
|
||||
|
||||
@@ -66,7 +66,7 @@ class ProxyInfo {
|
||||
}
|
||||
|
||||
Lookup getInterfaceLookup() {
|
||||
return type == Type.CLIENT_PROXY ? apiModule : JBRApi.outerLookup;
|
||||
return type == Type.CLIENT_PROXY || type == Type.INTERNAL_SERVICE ? apiModule : JBRApi.outerLookup;
|
||||
}
|
||||
|
||||
Lookup getTargetLookup() {
|
||||
@@ -74,12 +74,18 @@ class ProxyInfo {
|
||||
}
|
||||
|
||||
private Lookup lookup(Lookup lookup, String clazz) {
|
||||
try {
|
||||
return MethodHandles.privateLookupIn(lookup.findClass(clazz), lookup);
|
||||
} catch (ClassNotFoundException | IllegalAccessException e) {
|
||||
if (lookup == JBRApi.outerLookup) return null;
|
||||
else throw new RuntimeException(e);
|
||||
String[] nestedClasses = clazz.split("\\$");
|
||||
clazz = "";
|
||||
for (int i = 0; i < nestedClasses.length; i++) {
|
||||
try {
|
||||
if (i != 0) clazz += "$";
|
||||
clazz += nestedClasses[i];
|
||||
lookup = MethodHandles.privateLookupIn(lookup.findClass(clazz), lookup);
|
||||
} catch (ClassNotFoundException | IllegalAccessException ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
|
||||
static class StaticMethodMapping {
|
||||
@@ -98,6 +104,15 @@ class ProxyInfo {
|
||||
enum Type {
|
||||
PROXY,
|
||||
SERVICE,
|
||||
CLIENT_PROXY
|
||||
CLIENT_PROXY,
|
||||
INTERNAL_SERVICE;
|
||||
|
||||
public boolean isPublicApi() {
|
||||
return this == PROXY || this == SERVICE;
|
||||
}
|
||||
|
||||
public boolean isService() {
|
||||
return this == SERVICE || this == INTERNAL_SERVICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,10 +32,9 @@ import java.beans.*;
|
||||
import java.lang.annotation.Native;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.accessibility.*;
|
||||
@@ -46,24 +45,18 @@ import sun.awt.AWTAccessor;
|
||||
|
||||
class CAccessibility implements PropertyChangeListener {
|
||||
private static Set<String> ignoredRoles;
|
||||
private static final int INVOKE_TIMEOUT_SECONDS_DEFAULT = 1;
|
||||
private static final int INVOKE_TIMEOUT_SECONDS;
|
||||
|
||||
static {
|
||||
AtomicInteger invokeTimeoutSecondsRef = new AtomicInteger();
|
||||
// Need to load the native library for this code.
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("awt");
|
||||
invokeTimeoutSecondsRef.set(
|
||||
// (-1) for the infinite timeout
|
||||
Integer.getInteger("sun.lwawt.macosx.CAccessibility.invokeTimeoutSeconds",
|
||||
INVOKE_TIMEOUT_SECONDS_DEFAULT));
|
||||
return null;
|
||||
}
|
||||
// (-1) for the infinite timeout
|
||||
@SuppressWarnings("removal")
|
||||
int value = java.security.AccessController.doPrivileged(
|
||||
(PrivilegedAction<Integer>) () -> {
|
||||
// Need to load the native library for this code.
|
||||
System.loadLibrary("awt");
|
||||
return Integer.getInteger("sun.lwawt.macosx.CAccessibility.invokeTimeoutSeconds", 1);
|
||||
});
|
||||
INVOKE_TIMEOUT_SECONDS = invokeTimeoutSecondsRef.get();
|
||||
INVOKE_TIMEOUT_SECONDS = value;
|
||||
}
|
||||
|
||||
static CAccessibility sAccessibility;
|
||||
@@ -634,7 +627,7 @@ class CAccessibility implements PropertyChangeListener {
|
||||
int rowChildIndex = rowChildContext.getAccessibleIndexInParent();
|
||||
int accessibleColumnCount = ((AccessibleTable) ac).getAccessibleColumnCount();
|
||||
if (accessibleColumnCount <= 0) return -1;
|
||||
|
||||
|
||||
return rowChildIndex / accessibleColumnCount;
|
||||
};
|
||||
int firstVisibleRow = calcRowIndex.apply(location1);
|
||||
|
||||
@@ -270,9 +270,8 @@ final class CPlatformResponder {
|
||||
LWCToolkit lwcToolkit = (LWCToolkit)Toolkit.getDefaultToolkit();
|
||||
if ((lwcToolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) &&
|
||||
Locale.SIMPLIFIED_CHINESE.equals(lwcToolkit.getDefaultKeyboardLocale())) ||
|
||||
(LWCToolkit.isLocaleUSInternationalPC(lwcToolkit.getDefaultKeyboardLocale()) &&
|
||||
LWCToolkit.isCharModifierKeyInUSInternationalPC(testChar) &&
|
||||
(testChar != testCharIgnoringModifiers))) {
|
||||
((testChar != testCharIgnoringModifiers) &&
|
||||
LWCToolkit.isCharModifierKeyInLocale(lwcToolkit.getDefaultKeyboardLocale(), testChar))) {
|
||||
testChar = testCharIgnoringModifiers;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -188,7 +189,7 @@ public final class LWCToolkit extends LWToolkit {
|
||||
*/
|
||||
private static final boolean inAWT;
|
||||
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.lwawt.macosx.LWCToolkit");
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger(LWCToolkit.class.getName());
|
||||
|
||||
public LWCToolkit() {
|
||||
areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
|
||||
@@ -490,9 +491,8 @@ public final class LWCToolkit extends LWToolkit {
|
||||
if (!(gd instanceof CGraphicsDevice)) {
|
||||
return super.getScreenInsets(gc);
|
||||
}
|
||||
// Avoid deadlock with input methods
|
||||
CGraphicsDevice cgd = (CGraphicsDevice) gd;
|
||||
return AWTThreading.executeWaitToolkit(cgd::getScreenInsets);
|
||||
return cgd.getScreenInsets();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -660,30 +660,12 @@ public final class LWCToolkit extends LWToolkit {
|
||||
return invokeAndWait(callable, component, -1);
|
||||
}
|
||||
|
||||
static <T> T invokeAndWait(final Callable<T> callable, Component component, int timeoutSeconds) throws Exception {
|
||||
public static <T> T invokeAndWait(final Callable<T> callable, Component component, int timeoutSeconds) throws Exception {
|
||||
final CallableWrapper<T> wrapper = new CallableWrapper<>(callable);
|
||||
invokeAndWait(wrapper, component, false, timeoutSeconds);
|
||||
return wrapper.getResult();
|
||||
}
|
||||
|
||||
static final class CancelableRunnable implements Runnable {
|
||||
volatile Runnable runnable;
|
||||
|
||||
public CancelableRunnable(Runnable runnable) {
|
||||
this.runnable = runnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Runnable r = runnable;
|
||||
if (r != null) r.run();
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
runnable = null;
|
||||
}
|
||||
}
|
||||
|
||||
static final class CallableWrapper<T> implements Runnable {
|
||||
final Callable<T> callable;
|
||||
T object;
|
||||
@@ -761,15 +743,28 @@ public final class LWCToolkit extends LWToolkit {
|
||||
invokeAndWait(runnable, component, false, -1);
|
||||
}
|
||||
|
||||
static void invokeAndWait(Runnable runnable, Component component, boolean processEvents, int timeoutSeconds)
|
||||
public static void invokeAndWait(Runnable runnable, Component component, boolean processEvents, int timeoutSeconds)
|
||||
throws InvocationTargetException
|
||||
{
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("invokeAndWait started: " + runnable);
|
||||
}
|
||||
|
||||
if (isBlockingEventDispatchThread()) {
|
||||
String msg = "invokeAndWait is discarded as the EventDispatch thread is currently blocked";
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(msg, new Throwable());
|
||||
log.fine(AWTThreading.getInstance(component).printEventDispatchThreadStackTrace().toString());
|
||||
} else if (log.isLoggable(PlatformLogger.Level.INFO)) {
|
||||
StackTraceElement[] stack = new Throwable().getStackTrace();
|
||||
log.info(msg + ". Originated at " + stack[stack.length - 1]);
|
||||
Thread dispatchThread = AWTThreading.getInstance(component).getEventDispatchThread();
|
||||
log.info(dispatchThread.getName() + " at: " + dispatchThread.getStackTrace()[0].toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
boolean nonBlockingRunLoop;
|
||||
CancelableRunnable cancelableRunnable = new CancelableRunnable(runnable);
|
||||
|
||||
if (!processEvents) {
|
||||
synchronized (priorityInvocationPending) {
|
||||
@@ -781,17 +776,11 @@ public final class LWCToolkit extends LWToolkit {
|
||||
nonBlockingRunLoop = true;
|
||||
}
|
||||
|
||||
final long mediator = createAWTRunLoopMediator();
|
||||
AWTThreading.TrackedInvocationEvent invocationEvent =
|
||||
AWTThreading.createAndTrackInvocationEvent(component, runnable, true);
|
||||
|
||||
InvocationEvent invocationEvent =
|
||||
AWTThreading.createAndTrackInvocationEvent(component,
|
||||
cancelableRunnable,
|
||||
() -> {
|
||||
if (mediator != 0) {
|
||||
stopAWTRunLoop(mediator);
|
||||
}
|
||||
},
|
||||
true);
|
||||
long mediator = createAWTRunLoopMediator();
|
||||
invocationEvent.onDone(() -> stopAWTRunLoop(mediator));
|
||||
|
||||
if (component != null) {
|
||||
AppContext appContext = SunToolkit.targetToAppContext(component);
|
||||
@@ -805,10 +794,21 @@ public final class LWCToolkit extends LWToolkit {
|
||||
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
|
||||
}
|
||||
|
||||
CompletableFuture<Void> eventDispatchThreadFreeFuture =
|
||||
AWTThreading.getInstance(component).onEventDispatchThreadFree(() -> {
|
||||
if (!invocationEvent.isDone()) {
|
||||
// EventQueue is now empty but the posted InvocationEvent is still not dispatched,
|
||||
// consider it lost then.
|
||||
invocationEvent.dispose("InvocationEvent was lost");
|
||||
}
|
||||
});
|
||||
|
||||
invocationEvent.onDone(() -> eventDispatchThreadFreeFuture.cancel(false));
|
||||
|
||||
if (!doAWTRunLoop(mediator, nonBlockingRunLoop, timeoutSeconds)) {
|
||||
new Throwable("Invocation timed out (" + timeoutSeconds + "sec)").printStackTrace();
|
||||
cancelableRunnable.cancel();
|
||||
invocationEvent.dispose("InvocationEvent has timed out");
|
||||
}
|
||||
|
||||
if (!nonBlockingRunLoop) blockingRunLoopCounter.decrementAndGet();
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
@@ -818,6 +818,8 @@ public final class LWCToolkit extends LWToolkit {
|
||||
checkException(invocationEvent);
|
||||
}
|
||||
|
||||
private static native boolean isBlockingEventDispatchThread();
|
||||
|
||||
public static void invokeLater(Runnable event, Component component)
|
||||
throws InvocationTargetException {
|
||||
Objects.requireNonNull(component, "Null component provided to invokeLater");
|
||||
@@ -860,6 +862,11 @@ public final class LWCToolkit extends LWToolkit {
|
||||
*/
|
||||
static native void performOnMainThreadAfterDelay(Runnable r, long delay);
|
||||
|
||||
/**
|
||||
* Schedules a {@code Runnable} execution on the Appkit thread and waits for completion.
|
||||
*/
|
||||
public static native void performOnMainThreadAndWait(Runnable r);
|
||||
|
||||
// DnD support
|
||||
|
||||
@Override
|
||||
@@ -914,21 +921,8 @@ public final class LWCToolkit extends LWToolkit {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public static boolean isLocaleUSInternationalPC(Locale locale) {
|
||||
return (locale != null ?
|
||||
locale.toString().equals("_US_UserDefined_15000") : false);
|
||||
}
|
||||
|
||||
public static boolean isCharModifierKeyInUSInternationalPC(char ch) {
|
||||
// 5 characters: APOSTROPHE, QUOTATION MARK, ACCENT GRAVE, SMALL TILDE,
|
||||
// CIRCUMFLEX ACCENT
|
||||
final char[] modifierKeys = {'\'', '"', '`', '\u02DC', '\u02C6'};
|
||||
for (char modKey : modifierKeys) {
|
||||
if (modKey == ch) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
public static boolean isCharModifierKeyInLocale(Locale locale, char ch) {
|
||||
return KeyboardCombiningCharacters.isCharacterCombiningInKeyboardLocale(ch, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1164,3 +1158,233 @@ public final class LWCToolkit extends LWToolkit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final class KeyboardCombiningCharacters {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static boolean isCharacterCombiningInKeyboardLocale(final char ch, final Locale locale) {
|
||||
if (locale == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String localeStr = locale.toString();
|
||||
if (localeStr == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final char[] localeCombiningChars = keyboardCombiningCharacters.get(localeStr);
|
||||
if (localeCombiningChars == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (final char combiningChar : localeCombiningChars) {
|
||||
if (ch == combiningChar) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static final Map<String, char[]> keyboardCombiningCharacters;
|
||||
|
||||
static {
|
||||
/*
|
||||
* All arrays the map contains MUST be sorted into ASCENDING order (for binary search).
|
||||
* (UPD: the binary search proved to be slower than linear on the such small arrays so the linear is used now)
|
||||
*
|
||||
* Also, the syntax '<backslash>u<hex-digits>' is not used to avoid the traps about
|
||||
* early parsing of the unicode sequences.
|
||||
*/
|
||||
|
||||
// [U+0027 ('''), U+0060 ('`'), U+02c6, U+0022 ('"'), U+02dc, U+00b4, U+00a8]
|
||||
final char[] ENGLISH_US_INTERNATIONAL_PC =
|
||||
{(char)0x0022, (char)0x0027, (char)0x0060, (char)0x00A8,
|
||||
(char)0x00B4, (char)0x02C6, (char)0x02DC};
|
||||
|
||||
|
||||
// [U+0027 ('''), U+00a8, U+00b0, U+005e ('^'), U+02c7,
|
||||
// U+002c (','), U+002d ('-'), U+0022 ('"'), U+007e ('~')]
|
||||
final char[] CZECH_CZECH =
|
||||
{(char)0x0022, (char)0x0027, (char)0x002C, (char)0x002D,
|
||||
(char)0x005E, (char)0x007E, (char)0x00A8, (char)0x00B0, (char)0x02C7};
|
||||
|
||||
// [U+0027 ('''), U+00a8, U+02c7, U+00b0, U+005e ('^'),
|
||||
// U+002c (','), U+002d ('-'), U+0022 ('"'), U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] CZECH_CZECH_QWERTY = CZECH_CZECH;
|
||||
|
||||
|
||||
// [U+00b4, U+00a8, U+0060 ('`'), U+005e ('^'), U+007e ('~')]
|
||||
final char[] DANISH_DANISH =
|
||||
{(char)0x005E, (char)0x0060, (char)0x007E, (char)0x00A8, (char)0x00B4};
|
||||
|
||||
|
||||
// [U+0060 ('`'), U+00b4, U+00a8, U+005e ('^'), U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] DUTCH_DUTCH = DANISH_DANISH;
|
||||
|
||||
// [U+005e ('^'), U+0060 ('`'), U+00a8, U+007e ('~'), U+00b4]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] DUTCH_BELGIAN = DUTCH_DUTCH;
|
||||
|
||||
|
||||
// [U+00b4, U+00a8, U+0060 ('`'), U+005e ('^'), U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] FINNISH_FINNISH = DANISH_DANISH;
|
||||
|
||||
// [U+00b4, U+00a8, U+0060 ('`'), U+02c6, U+2038, U+02dd, U+002c (','),
|
||||
// U+02c7, U+02d8, U+02c0, U+02bc, U+02d9, U+02da, U+00af, U+002e ('.'),
|
||||
// U+02db, U+00a0, U+0330, U+02dc, U+002d ('-'), U+02cd, U+00b8, U+2116, U+0294]
|
||||
final char[] FINNISH_FINNISH_EXTENDED =
|
||||
{(char)0x002C, (char)0x002D, (char)0x002E, (char)0x0060,
|
||||
(char)0x00A0, (char)0x00A8, (char)0x00AF, (char)0x00B4, (char)0x00B8,
|
||||
(char)0x0294, (char)0x02BC, (char)0x02C0, (char)0x02C6,
|
||||
(char)0x02C7, (char)0x02CD, (char)0x02D8, (char)0x02D9,
|
||||
(char)0x02DA, (char)0x02DB, (char)0x02DC, (char)0x02DD,
|
||||
(char)0x0330, (char)0x2038, (char)0x2116};
|
||||
|
||||
// [U+00b4, U+00a8, U+0060 ('`'), U+02c6, U+2038, U+02dd, U+002c (','),
|
||||
// U+02c7, U+02d8, U+02c0, U+02d9, U+02da, U+02db, U+00a0, U+0330, U+002d ('-'), U+02cd]
|
||||
final char[] FINNISH_SAMI_PC =
|
||||
{(char)0x002C, (char)0x002D, (char)0x0060, (char)0x00A0, (char)0x00A8, (char)0x00B4,
|
||||
(char)0x02C0, (char)0x02C6, (char)0x02C7, (char)0x02CD,
|
||||
(char)0x02D8, (char)0x02D9, (char)0x02DA, (char)0x02DB, (char)0x02DD,
|
||||
(char)0x0330, (char)0x2038};
|
||||
|
||||
|
||||
// [U+005e ('^'), U+0060 ('`'), U+00a8, U+007e ('~'), U+00b4]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] FRENCH_ABC_AZERTY = DANISH_DANISH;
|
||||
|
||||
// [U+005e ('^'), U+00a8, U+0060 ('`'), U+007e ('~'), U+00b4]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] FRENCH_CANADIAN_FRENCH_CSA = FRENCH_ABC_AZERTY;
|
||||
|
||||
// [U+005e ('^'), U+0060 ('`'), U+00a8, U+007e ('~'), U+00b4]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] FRENCH_FRENCH = FRENCH_ABC_AZERTY;
|
||||
|
||||
// [U+005e ('^'), U+0060 ('`'), U+00a8, U+007e ('~'), U+00b4]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] FRENCH_FRENCH_NUMERICAL = FRENCH_ABC_AZERTY;
|
||||
|
||||
// [U+005e ('^'), U+00a8, U+007e ('~'), U+0060 ('`'), U+00b4]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] FRENCH_FRENCH_PC = FRENCH_ABC_AZERTY;
|
||||
|
||||
// [U+005e ('^'), U+00a8, U+0060 ('`'), U+00b4, U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] FRENCH_SWISS_FRENCH = FRENCH_ABC_AZERTY;
|
||||
|
||||
|
||||
// [U+00b4, U+0060 ('`'), U+00a8, U+007e ('~'), U+005e ('^')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] GERMAN_ABC_QWERTZ = DANISH_DANISH;
|
||||
|
||||
// [U+00b4, U+0060 ('`'), U+00a8, U+007e ('~'), U+005e ('^')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] GERMAN_AUSTRIAN = GERMAN_ABC_QWERTZ;
|
||||
|
||||
// [U+00b4, U+0060 ('`'), U+00a8, U+007e ('~'), U+005e ('^')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] GERMAN_GERMAN = GERMAN_ABC_QWERTZ;
|
||||
|
||||
// [U+00b4, U+0060 ('`'), U+02d9, U+02c7, U+02dd, U+007e ('~'),
|
||||
// U+00a8, U+02d8, U+00af, U+02da, U+02c0, U+02bc,
|
||||
// U+02cd, U+00b8, U+002c (','), U+02db, U+002e ('.'), U+002d ('-')]
|
||||
final char[] GERMAN_GERMAN_STANDARD =
|
||||
{(char)0x002C, (char)0x002D, (char)0x002E, (char)0x0060, (char)0x007E,
|
||||
(char)0x00A8, (char)0x00AF, (char)0x00B4, (char)0x00B8,
|
||||
(char)0x02BC, (char)0x02C0, (char)0x02C7, (char)0x02CD,
|
||||
(char)0x02D8, (char)0x02D9, (char)0x02DA, (char)0x02DB, (char)0x02DD};
|
||||
|
||||
// [U+005e ('^'), U+00a8, U+0060 ('`'), U+00b4, U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] GERMAN_SWISS_GERMAN = GERMAN_ABC_QWERTZ;
|
||||
|
||||
|
||||
// [U+00b4, U+007e ('~'), U+00a8, U+0060 ('`'), U+005e ('^')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] PORTUGUESE_BRAZILIAN_ABNT2 = DANISH_DANISH;
|
||||
|
||||
// [U+0060 ('`'), U+0027 ('''), U+02dc, U+02c6, U+0022 ('"'), U+00b4, U+00a8]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] PORTUGUESE_BRAZILIAN_PRO = ENGLISH_US_INTERNATIONAL_PC;
|
||||
|
||||
|
||||
// [U+00b4, U+00a8, U+007e ('~'), U+0060 ('`'), U+005e ('^')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] SPANISH_LATIN_AMERICA = DANISH_DANISH;
|
||||
|
||||
// [U+00b4, U+0060 ('`'), U+00a8, U+005e ('^'), U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] SPANISH_SPANISH = SPANISH_LATIN_AMERICA;
|
||||
|
||||
// [U+0060 ('`'), U+00b4, U+005e ('^'), U+00a8, U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] SPANISH_SPANISH_ISO = SPANISH_LATIN_AMERICA;
|
||||
|
||||
|
||||
// [U+00b4, U+00a8, U+0060 ('`'), U+005e ('^'), U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] SWEDISH_SWEDISH = DANISH_DANISH;
|
||||
|
||||
// [U+00b4, U+00a8, U+0060 ('`'), U+005e ('^'), U+007e ('~')]
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final char[] SWEDISH_SWEDISH_PRO = SWEDISH_SWEDISH;
|
||||
|
||||
// [U+00b4, U+00a8, U+0060 ('`'), U+02c6, U+2038, U+02dd, U+002c (','), U+02c7,
|
||||
// U+02d8, U+02c0, U+02d9, U+02da, U+02db, <U+00a0, U+0330>, U+002d ('-'), U+02cd]
|
||||
final char[] SWEDISH_SWEDISH_SAMI_PC =
|
||||
{(char)0x002C, (char)0x002D, (char)0x0060, (char)0x00A0, (char)0x00A8, (char)0x00B4,
|
||||
(char)0x02C0, (char)0x02C6, (char)0x02C7, (char)0x02CD,
|
||||
(char)0x02D8, (char)0x02D9, (char)0x02DA, (char)0x02DB, (char)0x02DD,
|
||||
(char)0x0330, (char)0x2038};
|
||||
|
||||
|
||||
final Map<String, char[]> keyboardCombiningCharactersInitializer = new HashMap<>();
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_15000", ENGLISH_US_INTERNATIONAL_PC);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "cs", CZECH_CZECH);
|
||||
keyboardCombiningCharactersInitializer.put( "cs__QWERTY", CZECH_CZECH_QWERTY);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "da", DANISH_DANISH);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "nl_BE", DUTCH_BELGIAN);
|
||||
keyboardCombiningCharactersInitializer.put( "nl", DUTCH_DUTCH);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "fi", FINNISH_FINNISH);
|
||||
keyboardCombiningCharactersInitializer.put( "fi__Extended", FINNISH_FINNISH_EXTENDED);
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_-18", FINNISH_SAMI_PC);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_251", FRENCH_ABC_AZERTY);
|
||||
keyboardCombiningCharactersInitializer.put( "fr_CA", FRENCH_CANADIAN_FRENCH_CSA);
|
||||
keyboardCombiningCharactersInitializer.put( "fr", FRENCH_FRENCH);
|
||||
keyboardCombiningCharactersInitializer.put( "fr__numerical", FRENCH_FRENCH_NUMERICAL);
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_60", FRENCH_FRENCH_PC);
|
||||
keyboardCombiningCharactersInitializer.put( "fr_CH", FRENCH_SWISS_FRENCH);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_253", GERMAN_ABC_QWERTZ);
|
||||
keyboardCombiningCharactersInitializer.put( "de_AT", GERMAN_AUSTRIAN);
|
||||
keyboardCombiningCharactersInitializer.put( "de", GERMAN_GERMAN);
|
||||
keyboardCombiningCharactersInitializer.put("_US_UserDefined_-18133", GERMAN_GERMAN_STANDARD);
|
||||
keyboardCombiningCharactersInitializer.put( "de_CH", GERMAN_SWISS_GERMAN);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_128", PORTUGUESE_BRAZILIAN_ABNT2);
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_72", PORTUGUESE_BRAZILIAN_PRO);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_89", SPANISH_LATIN_AMERICA);
|
||||
keyboardCombiningCharactersInitializer.put( "es", SPANISH_SPANISH);
|
||||
keyboardCombiningCharactersInitializer.put( "es__ISO", SPANISH_SPANISH_ISO);
|
||||
|
||||
keyboardCombiningCharactersInitializer.put( "sv", SWEDISH_SWEDISH);
|
||||
keyboardCombiningCharactersInitializer.put( "sv__Pro", SWEDISH_SWEDISH_PRO);
|
||||
keyboardCombiningCharactersInitializer.put( "_US_UserDefined_-15", SWEDISH_SWEDISH_SAMI_PC);
|
||||
|
||||
|
||||
keyboardCombiningCharacters = keyboardCombiningCharactersInitializer;
|
||||
}
|
||||
}
|
||||
@@ -1011,7 +1011,9 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
// the new key window
|
||||
NSWindow *keyWindow = [NSApp keyWindow];
|
||||
AWTWindow *opposite = nil;
|
||||
opposite = (AWTWindow *)[keyWindow delegate];
|
||||
if (keyWindow != self.nsWindow) {
|
||||
opposite = (AWTWindow *)[keyWindow delegate];
|
||||
}
|
||||
[AWTWindow setLastKeyWindow: self];
|
||||
|
||||
[self _deliverWindowFocusEvent:NO oppositeWindow: opposite];
|
||||
|
||||
@@ -593,6 +593,8 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
jboolean result = JNI_TRUE;
|
||||
JNI_COCOA_ENTER(env);
|
||||
|
||||
if (ThreadUtilities.blockingEventDispatchThread) return JNI_FALSE;
|
||||
|
||||
AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
|
||||
|
||||
if (mediatorObject == nil) return JNI_TRUE;
|
||||
@@ -627,6 +629,17 @@ JNI_COCOA_EXIT(env);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
* Method: isBlockingEventDispatchThread
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isBlockingEventDispatchThread
|
||||
(JNIEnv *env, jclass clz)
|
||||
{
|
||||
return ThreadUtilities.blockingEventDispatchThread;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
* Method: stopAWTRunLoop
|
||||
@@ -639,6 +652,8 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
|
||||
|
||||
if (mediatorObject == nil) return;
|
||||
|
||||
[ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO];
|
||||
|
||||
[mediatorObject release];
|
||||
@@ -664,6 +679,23 @@ JNI_COCOA_ENTER(env);
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
* Method: performOnMainThreadAndWait
|
||||
* Signature: (Ljava/lang/Runnable)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_performOnMainThreadAndWait
|
||||
(JNIEnv *env, jclass clz, jobject runnable)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
jobject gRunnable = (*env)->NewGlobalRef(env, runnable);
|
||||
CHECK_NULL(gRunnable);
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
|
||||
JavaRunnable* performer = [[JavaRunnable alloc] initWithRunnable:gRunnable];
|
||||
[performer perform];
|
||||
}];
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
|
||||
@@ -127,6 +127,13 @@ do { \
|
||||
__attribute__((visibility("default")))
|
||||
@interface ThreadUtilities : NSObject { } /* Extend NSObject so can call performSelectorOnMainThread */
|
||||
|
||||
/*
|
||||
* When a blocking performSelectorOnMainThread is executed from the EventDispatch thread,
|
||||
* and the executed code triggers an opposite blocking a11y call (via LWCToolkit.invokeAndWait)
|
||||
* this is a deadlock case, and then this property is used to discard LWCToolkit.invokeAndWait.
|
||||
*/
|
||||
@property (class, atomic, readonly) BOOL blockingEventDispatchThread;
|
||||
|
||||
+ (JNIEnv*)getJNIEnv;
|
||||
+ (JNIEnv*)getJNIEnvUncached;
|
||||
+ (void)detachCurrentThread;
|
||||
|
||||
@@ -50,6 +50,23 @@ static inline void attachCurrentThread(void** env) {
|
||||
|
||||
@implementation ThreadUtilities
|
||||
|
||||
// A backing store for the [blockingEventDispatchThread] class level property
|
||||
static BOOL _blockingEventDispatchThread = NO;
|
||||
static long eventDispatchThreadPtr = (long)nil;
|
||||
|
||||
// The [blockingEventDispatchThread] property is readonly, so we implement a private setter
|
||||
static void setBlockingEventDispatchThread(BOOL value) {
|
||||
@synchronized([ThreadUtilities class]) {
|
||||
_blockingEventDispatchThread = value;
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL) blockingEventDispatchThread {
|
||||
@synchronized([ThreadUtilities class]) {
|
||||
return _blockingEventDispatchThread;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
/* All the standard modes plus ours */
|
||||
javaModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode,
|
||||
@@ -116,7 +133,12 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
if ([NSThread isMainThread] && wait == YES) {
|
||||
[target performSelector:aSelector withObject:arg];
|
||||
} else {
|
||||
[target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait modes:javaModes];
|
||||
setBlockingEventDispatchThread((long)[NSThread currentThread] == eventDispatchThreadPtr);
|
||||
@try {
|
||||
[target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait modes:javaModes];
|
||||
} @finally {
|
||||
setBlockingEventDispatchThread(NO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,3 +165,16 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CThreading_isMainThread
|
||||
return [NSThread isMainThread];
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_AWTThreading
|
||||
* Method: notifyEventDispatchThreadStartedNative
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_awt_AWTThreading_notifyEventDispatchThreadStartedNative
|
||||
(JNIEnv *env, jclass c)
|
||||
{
|
||||
@synchronized([ThreadUtilities class]) {
|
||||
eventDispatchThreadPtr = (long)[NSThread currentThread];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ public class JBRApiModule {
|
||||
.withStatic("getSubpixelResolution", "sun.font.FontUtilities")
|
||||
.service("com.jetbrains.JBRFileDialogService", null)
|
||||
.withStatic("getFileDialog", "com.jetbrains.desktop.JBRFileDialog", "get")
|
||||
.proxy("com.jetbrains.JBRFileDialog", "com.jetbrains.desktop.JBRFileDialog");
|
||||
.proxy("com.jetbrains.JBRFileDialog", "com.jetbrains.desktop.JBRFileDialog")
|
||||
.service("com.jetbrains.CustomWindowDecoration", "java.awt.Window$CustomWindowDecoration");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.awt.event.WindowEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import sun.awt.AWTThreading;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import sun.awt.dnd.SunDragSourceContextPeer;
|
||||
@@ -86,6 +87,7 @@ class EventDispatchThread extends Thread {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
AWTThreading.getInstance(Thread.currentThread()).notifyEventDispatchThreadStarted();
|
||||
try {
|
||||
pumpEvents(new Conditional() {
|
||||
public boolean evaluate() {
|
||||
@@ -97,6 +99,8 @@ class EventDispatchThread extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
private static native void registerEventDispatchThread();
|
||||
|
||||
void pumpEvents(Conditional cond) {
|
||||
pumpEvents(ANY_EVENT, cond);
|
||||
}
|
||||
|
||||
@@ -357,6 +357,7 @@ public class EventQueue {
|
||||
if (shouldNotify) {
|
||||
if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
|
||||
AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
|
||||
AWTThreading.getInstance(dispatchThread).notifyEventDispatchThreadBusy();
|
||||
}
|
||||
pushPopCond.signalAll();
|
||||
} else if (notifyID) {
|
||||
@@ -569,6 +570,7 @@ public class EventQueue {
|
||||
return event;
|
||||
}
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
|
||||
AWTThreading.getInstance(dispatchThread).notifyEventDispatchThreadFree();
|
||||
pushPopCond.await();
|
||||
} finally {
|
||||
pushPopLock.unlock();
|
||||
@@ -1126,6 +1128,7 @@ public class EventQueue {
|
||||
t.setPriority(Thread.NORM_PRIORITY + 1);
|
||||
t.setDaemon(false);
|
||||
AWTAutoShutdown.getInstance().notifyThreadBusy(t);
|
||||
AWTThreading.getInstance(t).notifyEventDispatchThreadBusy();
|
||||
return t;
|
||||
}
|
||||
}
|
||||
@@ -1156,6 +1159,7 @@ public class EventQueue {
|
||||
dispatchThread = null;
|
||||
}
|
||||
AWTAutoShutdown.getInstance().notifyThreadFree(edt);
|
||||
AWTThreading.getInstance(edt).notifyEventDispatchThreadFree();
|
||||
/*
|
||||
* Event was posted after EDT events pumping had stopped, so start
|
||||
* another EDT to handle this event
|
||||
|
||||
@@ -43,6 +43,9 @@ import sun.awt.SunToolkit;
|
||||
import sun.awt.image.SunWritableRaster;
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
|
||||
import static sun.java2d.SunGraphicsEnvironment.toDeviceSpace;
|
||||
import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs;
|
||||
|
||||
/**
|
||||
* This class is used to generate native system input events
|
||||
* for the purposes of test automation, self-running demos, and
|
||||
@@ -377,13 +380,9 @@ public class Robot {
|
||||
*/
|
||||
public synchronized Color getPixelColor(int x, int y) {
|
||||
checkScreenCaptureAllowed();
|
||||
AffineTransform tx = GraphicsEnvironment.
|
||||
getLocalGraphicsEnvironment().getDefaultScreenDevice().
|
||||
getDefaultConfiguration().getDefaultTransform();
|
||||
x = (int) (x * tx.getScaleX());
|
||||
y = (int) (y * tx.getScaleY());
|
||||
Color color = new Color(peer.getRGBPixel(x, y));
|
||||
return color;
|
||||
Point point = peer.useAbsoluteCoordinates() ? toDeviceSpaceAbs(x, y)
|
||||
: toDeviceSpace(x, y);
|
||||
return new Color(peer.getRGBPixel(point.x, point.y));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -516,16 +515,17 @@ public class Robot {
|
||||
|
||||
} else {
|
||||
|
||||
int sX = (int) Math.floor(screenRect.x * uiScaleX);
|
||||
int sY = (int) Math.floor(screenRect.y * uiScaleY);
|
||||
int sWidth = (int) Math.ceil(screenRect.width * uiScaleX);
|
||||
int sHeight = (int) Math.ceil(screenRect.height * uiScaleY);
|
||||
int temppixels[];
|
||||
Rectangle scaledRect = new Rectangle(sX, sY, sWidth, sHeight);
|
||||
temppixels = peer.getRGBPixels(scaledRect);
|
||||
Rectangle scaledRect;
|
||||
if (peer.useAbsoluteCoordinates()) {
|
||||
scaledRect = toDeviceSpaceAbs(gc, screenRect.x,
|
||||
screenRect.y, screenRect.width, screenRect.height);
|
||||
} else {
|
||||
scaledRect = toDeviceSpace(gc, screenRect.x,
|
||||
screenRect.y, screenRect.width, screenRect.height);
|
||||
}
|
||||
|
||||
// HighResolutionImage
|
||||
pixels = temppixels;
|
||||
pixels = peer.getRGBPixels(scaledRect);
|
||||
buffer = new DataBufferInt(pixels, pixels.length);
|
||||
raster = Raster.createPackedRaster(buffer, scaledRect.width,
|
||||
scaledRect.height, scaledRect.width, bandmasks, null);
|
||||
|
||||
@@ -45,13 +45,16 @@ import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OptionalDataException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Native;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EventListener;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
@@ -3989,7 +3992,52 @@ public class Window extends Container implements Accessible {
|
||||
}
|
||||
|
||||
private volatile boolean hasCustomDecoration;
|
||||
private volatile List<Map.Entry<Shape, Integer>> customDecorHitTestSpots;
|
||||
private volatile int customDecorTitleBarHeight = -1; // 0 can be a legal value when no title bar is expected
|
||||
|
||||
// called from native
|
||||
private int hitTestCustomDecoration(int x, int y) {
|
||||
var spots = customDecorHitTestSpots;
|
||||
if (spots == null) return CustomWindowDecoration.NO_HIT_SPOT;
|
||||
for (var spot : spots) {
|
||||
if (spot.getKey().contains(x, y)) return spot.getValue();
|
||||
}
|
||||
return CustomWindowDecoration.NO_HIT_SPOT;
|
||||
}
|
||||
|
||||
private static class CustomWindowDecoration {
|
||||
|
||||
@Native public static final int
|
||||
NO_HIT_SPOT = 0,
|
||||
OTHER_HIT_SPOT = 1,
|
||||
MINIMIZE_BUTTON = 2,
|
||||
MAXIMIZE_BUTTON = 3,
|
||||
CLOSE_BUTTON = 4,
|
||||
MENU_BAR = 5;
|
||||
|
||||
void setCustomDecorationEnabled(Window window, boolean enabled) {
|
||||
window.hasCustomDecoration = enabled;
|
||||
}
|
||||
boolean isCustomDecorationEnabled(Window window) {
|
||||
return window.hasCustomDecoration;
|
||||
}
|
||||
|
||||
void setCustomDecorationHitTestSpots(Window window, List<Map.Entry<Shape, Integer>> spots) {
|
||||
window.customDecorHitTestSpots = List.copyOf(spots);
|
||||
}
|
||||
List<Map.Entry<Shape, Integer>> getCustomDecorationHitTestSpots(Window window) {
|
||||
return window.customDecorHitTestSpots;
|
||||
}
|
||||
|
||||
void setCustomDecorationTitleBarHeight(Window window, int height) {
|
||||
if (height >= 0) window.customDecorTitleBarHeight = height;
|
||||
}
|
||||
int getCustomDecorationTitleBarHeight(Window window) {
|
||||
return window.customDecorTitleBarHeight;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
boolean hasCustomDecoration() {
|
||||
return hasCustomDecoration;
|
||||
}
|
||||
@@ -3997,6 +4045,7 @@ public class Window extends Container implements Accessible {
|
||||
/**
|
||||
* Set via reflection (JB JdkEx API).
|
||||
*/
|
||||
@Deprecated
|
||||
void setHasCustomDecoration() {
|
||||
hasCustomDecoration = true;
|
||||
}
|
||||
|
||||
@@ -117,4 +117,14 @@ public interface RobotPeer
|
||||
* @see Robot#createScreenCapture(Rectangle)
|
||||
*/
|
||||
int[] getRGBPixels(Rectangle bounds);
|
||||
|
||||
/**
|
||||
* Determines if absolute coordinates should be used by this peer.
|
||||
*
|
||||
* @return {@code true} if absolute coordinates should be used,
|
||||
* {@code false} otherwise
|
||||
*/
|
||||
default boolean useAbsoluteCoordinates() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,33 @@ import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Used to perform a cross threads (EventDispatch, Toolkit) execution so that the execution does not cause a deadlock.
|
||||
*
|
||||
* Note: the log messages are tested by jdk/jb/java/awt/Toolkit/LWCToolkitInvokeAndWaitTest.java
|
||||
*/
|
||||
public class AWTThreading {
|
||||
private static final PlatformLogger logger = PlatformLogger.getLogger("sun.awt.AWTThreading");
|
||||
private static final PlatformLogger logger = PlatformLogger.getLogger(AWTThreading.class.getName());
|
||||
|
||||
private static final Runnable EMPTY_RUNNABLE = () -> {};
|
||||
|
||||
private static final AtomicReference<Function<Thread, AWTThreading>> theAWTThreadingFactory =
|
||||
new AtomicReference<>(AWTThreading::new);
|
||||
|
||||
private final Thread eventDispatchThread;
|
||||
|
||||
private ExecutorService executor;
|
||||
// every invokeAndWait() pushes a queue of invocations
|
||||
@@ -24,12 +39,20 @@ public class AWTThreading {
|
||||
|
||||
private int level; // re-entrance level
|
||||
|
||||
private final List<CompletableFuture<Void>> eventDispatchThreadStateNotifiers = new ArrayList<>();
|
||||
private volatile boolean isEventDispatchThreadFree;
|
||||
|
||||
// invocations should be dispatched on proper EDT (per AppContext)
|
||||
private static final Map<Thread, AWTThreading> EDT_TO_INSTANCE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private static class TrackingQueue extends LinkedBlockingQueue<InvocationEvent> {}
|
||||
|
||||
private AWTThreading() {}
|
||||
/**
|
||||
* WARNING: for testing purpose, use {@link AWTThreading#getInstance(Thread)} instead.
|
||||
*/
|
||||
public AWTThreading(Thread edt) {
|
||||
eventDispatchThread = edt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a callable from EventDispatch thread (EDT). It's assumed the callable either performs a blocking execution on Toolkit
|
||||
@@ -54,14 +77,25 @@ public class AWTThreading {
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #executeWaitToolkit(Callable)}, but without returning a value. If requested (as indicated by
|
||||
* the passed parameter), the invoked native method is supposed to wait for the result of invocation on AppKit
|
||||
* thread, and vice versa.
|
||||
* A boolean value passed to the consumer indicates whether the consumer should perform
|
||||
* a synchronous invocation on the Toolkit thread and wait, or return immediately.
|
||||
*
|
||||
* @see #executeWaitToolkit(Callable).
|
||||
*/
|
||||
public static void executeWaitToolkit(Task runnable) {
|
||||
public static void executeWaitToolkit(Consumer<Boolean> consumer) {
|
||||
boolean wait = EventQueue.isDispatchThread();
|
||||
executeWaitToolkit(() -> {
|
||||
runnable.run(wait);
|
||||
consumer.accept(wait);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #executeWaitToolkit(Callable).
|
||||
*/
|
||||
public static void executeWaitToolkit(Runnable runnable) {
|
||||
executeWaitToolkit(() -> {
|
||||
runnable.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@@ -81,12 +115,6 @@ public class AWTThreading {
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEDT && logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
// this can cause deadlock if calling thread is holding a lock which EDT might require (e.g. AWT tree lock)
|
||||
logger.fine("AWTThreading.executeWaitToolkit invoked from non-EDT thread", new Throwable());
|
||||
}
|
||||
|
||||
// fallback to default
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
@@ -176,8 +204,15 @@ public class AWTThreading {
|
||||
* <li>If the event is first dispatched from EventQueue - it gets removed from the tracking queue.
|
||||
* <li>If the event is first dispatched from the tracking queue - its dispatching on EventQueue will be noop.
|
||||
* <ul>
|
||||
*
|
||||
* @param source the source of the event
|
||||
* @param onDispatched called back on event dispatching
|
||||
* @param catchThrowables should catch Throwable's or propagate to the EventDispatch thread's loop
|
||||
*/
|
||||
public static InvocationEvent createAndTrackInvocationEvent(Object source, Runnable runnable, Runnable listener, boolean catchThrowables) {
|
||||
public static TrackedInvocationEvent createAndTrackInvocationEvent(Object source,
|
||||
Runnable onDispatched,
|
||||
boolean catchThrowables)
|
||||
{
|
||||
AWTThreading instance = getInstance(source);
|
||||
if (instance != null) {
|
||||
synchronized (instance.invocations) {
|
||||
@@ -185,68 +220,225 @@ public class AWTThreading {
|
||||
instance.invocations.push(new TrackingQueue());
|
||||
}
|
||||
final TrackingQueue queue = instance.invocations.peek();
|
||||
final InvocationEvent[] eventRef = new InvocationEvent[1];
|
||||
final AtomicReference<TrackedInvocationEvent> eventRef = new AtomicReference<>();
|
||||
|
||||
queue.add(eventRef[0] = new InvocationEvent(
|
||||
source,
|
||||
runnable,
|
||||
// Wrap the original completion listener so that it:
|
||||
// - guarantees a single run either from dispatch or dispose
|
||||
// - removes the invocation event from the tracking queue
|
||||
new Runnable() {
|
||||
WeakReference<TrackingQueue> queueRef = new WeakReference<>(queue);
|
||||
eventRef.set(TrackedInvocationEvent.create(
|
||||
source,
|
||||
onDispatched,
|
||||
new Runnable() {
|
||||
final WeakReference<TrackingQueue> queueRef = new WeakReference<>(queue);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (queueRef != null) {
|
||||
if (listener != null) {
|
||||
listener.run();
|
||||
}
|
||||
TrackingQueue q = queueRef.get();
|
||||
if (q != null) {
|
||||
q.remove(eventRef[0]);
|
||||
}
|
||||
queueRef = null;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
TrackingQueue queue = queueRef.get();
|
||||
queueRef.clear();
|
||||
if (queue != null) {
|
||||
queue.remove(eventRef.get());
|
||||
}
|
||||
},
|
||||
catchThrowables)
|
||||
{
|
||||
@Override
|
||||
public void dispatch() {
|
||||
if (!isDispatched()) {
|
||||
super.dispatch();
|
||||
}
|
||||
}
|
||||
});
|
||||
return eventRef[0];
|
||||
},
|
||||
catchThrowables));
|
||||
|
||||
queue.add(eventRef.get());
|
||||
return eventRef.get();
|
||||
}
|
||||
}
|
||||
return new InvocationEvent(source, runnable, listener, catchThrowables);
|
||||
return TrackedInvocationEvent.create(source, onDispatched, () -> {}, catchThrowables);
|
||||
}
|
||||
|
||||
private static AWTThreading getInstance(Object obj) {
|
||||
if (obj == null) return null;
|
||||
@SuppressWarnings("serial")
|
||||
public static class TrackedInvocationEvent extends InvocationEvent {
|
||||
private final long creationTime = System.currentTimeMillis();
|
||||
private final Throwable throwable = new Throwable();
|
||||
private final CompletableFuture<Void> futureResult = new CompletableFuture<>();
|
||||
|
||||
// dispatched or disposed
|
||||
private final AtomicBoolean isFinished = new AtomicBoolean(false);
|
||||
|
||||
static TrackedInvocationEvent create(Object source,
|
||||
Runnable onDispatch,
|
||||
Runnable onDone,
|
||||
boolean catchThrowables)
|
||||
{
|
||||
final AtomicReference<TrackedInvocationEvent> eventRef = new AtomicReference<>();
|
||||
eventRef.set(new TrackedInvocationEvent(
|
||||
source,
|
||||
onDispatch,
|
||||
() -> {
|
||||
if (onDone != null) {
|
||||
onDone.run();
|
||||
}
|
||||
TrackedInvocationEvent thisEvent = eventRef.get();
|
||||
if (!thisEvent.isDispatched()) {
|
||||
// If we're here - this {onDone} is being disposed.
|
||||
thisEvent.finishIfNotYet(() ->
|
||||
// If we're here - this {onDone} is called by the outer AWTAccessor.getInvocationEventAccessor().dispose()
|
||||
// which we do not control, so complete here.
|
||||
thisEvent.futureResult.completeExceptionally(new Throwable("InvocationEvent was disposed"))
|
||||
);
|
||||
}
|
||||
},
|
||||
catchThrowables));
|
||||
return eventRef.get();
|
||||
}
|
||||
|
||||
protected TrackedInvocationEvent(Object source, Runnable onDispatched, Runnable onDone, boolean catchThrowables) {
|
||||
super(source,
|
||||
Optional.of(onDispatched).orElse(EMPTY_RUNNABLE),
|
||||
Optional.of(onDone).orElse(EMPTY_RUNNABLE),
|
||||
catchThrowables);
|
||||
|
||||
futureResult.whenComplete((r, ex) -> {
|
||||
if (ex != null) {
|
||||
String message = ex.getMessage() + " (awaiting " + (System.currentTimeMillis() - creationTime) + " ms)";
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
ex.initCause(throwable);
|
||||
logger.fine(message, ex);
|
||||
} else if (logger.isLoggable(PlatformLogger.Level.INFO)) {
|
||||
StackTraceElement[] stack = throwable.getStackTrace();
|
||||
logger.info(message + ". Originated at " + stack[stack.length - 1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch() {
|
||||
finishIfNotYet(super::dispatch);
|
||||
futureResult.complete(null);
|
||||
}
|
||||
|
||||
public void dispose(String reason) {
|
||||
finishIfNotYet(() -> AWTAccessor.getInvocationEventAccessor().dispose(this));
|
||||
futureResult.completeExceptionally(new Throwable(reason));
|
||||
}
|
||||
|
||||
private void finishIfNotYet(Runnable finish) {
|
||||
if (!isFinished.getAndSet(true)) {
|
||||
finish.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the event is dispatched or disposed.
|
||||
*/
|
||||
public boolean isDone() {
|
||||
return futureResult.isDone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the runnable when it's done (immediately if it's done).
|
||||
*/
|
||||
public void onDone(Runnable runnable) {
|
||||
futureResult.whenComplete((r, ex) -> Optional.of(runnable).orElse(EMPTY_RUNNABLE).run());
|
||||
}
|
||||
}
|
||||
|
||||
public static AWTThreading getInstance(Object obj) {
|
||||
if (obj == null) {
|
||||
return getInstance(Toolkit.getDefaultToolkit().getSystemEventQueue());
|
||||
}
|
||||
|
||||
AppContext appContext = SunToolkit.targetToAppContext(obj);
|
||||
if (appContext == null) return null;
|
||||
if (appContext == null) {
|
||||
return getInstance(Toolkit.getDefaultToolkit().getSystemEventQueue());
|
||||
}
|
||||
|
||||
return getInstance((EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY));
|
||||
}
|
||||
|
||||
private static AWTThreading getInstance(EventQueue eq) {
|
||||
public static AWTThreading getInstance(EventQueue eq) {
|
||||
if (eq == null) return null;
|
||||
|
||||
return getInstance(AWTAccessor.getEventQueueAccessor().getDispatchThread(eq));
|
||||
}
|
||||
|
||||
private static AWTThreading getInstance(Thread edt) {
|
||||
if (edt == null) return null;
|
||||
public static AWTThreading getInstance(Thread edt) {
|
||||
assert edt != null;
|
||||
|
||||
return EDT_TO_INSTANCE_MAP.computeIfAbsent(edt, key -> new AWTThreading());
|
||||
return EDT_TO_INSTANCE_MAP.computeIfAbsent(edt, key -> theAWTThreadingFactory.get().apply(edt));
|
||||
}
|
||||
|
||||
public interface Task {
|
||||
void run(boolean wait);
|
||||
public Thread getEventDispatchThread() {
|
||||
return eventDispatchThread;
|
||||
}
|
||||
|
||||
public StringWriter printEventDispatchThreadStackTrace() {
|
||||
return printEventDispatchThreadStackTrace(new StringWriter());
|
||||
}
|
||||
|
||||
public StringWriter printEventDispatchThreadStackTrace(StringWriter writer) {
|
||||
assert writer != null;
|
||||
var printer = new PrintWriter(writer);
|
||||
Thread dispatchThread = getEventDispatchThread();
|
||||
printer.println(dispatchThread.getName());
|
||||
Arrays.asList(dispatchThread.getStackTrace()).forEach(frame -> printer.append("\tat ").println(frame));
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code AWTThreading} instance factory.
|
||||
* WARNING: for testing purpose.
|
||||
*/
|
||||
public static void setAWTThreadingFactory(Function<Thread, AWTThreading> factory) {
|
||||
theAWTThreadingFactory.set(factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called on the EventDispatch thread.
|
||||
*/
|
||||
public void notifyEventDispatchThreadStarted() {
|
||||
if (FontUtilities.isMacOSX) notifyEventDispatchThreadStartedNative();
|
||||
}
|
||||
|
||||
private static native void notifyEventDispatchThreadStartedNative();
|
||||
|
||||
public void notifyEventDispatchThreadFree() {
|
||||
List<CompletableFuture<Void>> notifiers = Collections.emptyList();
|
||||
synchronized (eventDispatchThreadStateNotifiers) {
|
||||
isEventDispatchThreadFree = true;
|
||||
if (eventDispatchThreadStateNotifiers.size() > 0) {
|
||||
notifiers = List.copyOf(eventDispatchThreadStateNotifiers);
|
||||
}
|
||||
}
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
logger.finer("notifyEventDispatchThreadFree");
|
||||
}
|
||||
// notify callbacks out of the synchronization block
|
||||
notifiers.forEach(f -> f.complete(null));
|
||||
}
|
||||
|
||||
public void notifyEventDispatchThreadBusy() {
|
||||
synchronized (eventDispatchThreadStateNotifiers) {
|
||||
isEventDispatchThreadFree = false;
|
||||
}
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
logger.finer("notifyEventDispatchThreadBusy");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a callback and returns a {@code CompletableFuture} reporting the case when the associated EventDispatch thread
|
||||
* has gone sleeping and stopped dispatching events because of empty EventQueue. If the EventDispatch thread is free
|
||||
* at the moment then the callback is called immediately on the caller's thread and the future completes.
|
||||
*/
|
||||
public CompletableFuture<Void> onEventDispatchThreadFree(Runnable runnable) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
future.thenRun(Optional.of(runnable).orElse(EMPTY_RUNNABLE));
|
||||
|
||||
if (!isEventDispatchThreadFree) {
|
||||
synchronized (eventDispatchThreadStateNotifiers) {
|
||||
if (!isEventDispatchThreadFree) {
|
||||
eventDispatchThreadStateNotifiers.add(future);
|
||||
future.whenComplete((r, ex) -> eventDispatchThreadStateNotifiers.remove(future));
|
||||
return future;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINER)) {
|
||||
logger.finer("onEventDispatchThreadFree: free at the moment");
|
||||
}
|
||||
future.complete(null);
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package sun.awt;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* TODO: remove it in JBR 202
|
||||
*
|
||||
* @deprecated
|
||||
* @see AWTThreading
|
||||
*/
|
||||
public class InvokeOnToolkitHelper {
|
||||
public static <T> T invokeAndBlock(Callable<T> callable) {
|
||||
return AWTThreading.executeWaitToolkit(callable);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ package sun.java2d;
|
||||
|
||||
import java.awt.AWTError;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
@@ -452,54 +453,125 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bounds of the graphics configuration in device space.
|
||||
*
|
||||
* @param config the graphics configuration which bounds are requested
|
||||
* @return the bounds of the area covered by this
|
||||
* {@code GraphicsConfiguration} in device space (pixels)
|
||||
*/
|
||||
public static Rectangle getGCDeviceBounds(GraphicsConfiguration config) {
|
||||
AffineTransform tx = config.getDefaultTransform();
|
||||
Rectangle bounds = config.getBounds();
|
||||
bounds.width *= tx.getScaleX();
|
||||
bounds.height *= tx.getScaleY();
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the size (w, h) from the device space to the user's space using
|
||||
* passed graphics configuration.
|
||||
*
|
||||
* @param gc the graphics configuration to be used for transformation
|
||||
* @param w the width in the device space
|
||||
* @param h the height in the device space
|
||||
* @return the size in the user's space
|
||||
*/
|
||||
public static Dimension toUserSpace(GraphicsConfiguration gc,
|
||||
int w, int h) {
|
||||
AffineTransform tx = gc.getDefaultTransform();
|
||||
return new Dimension(
|
||||
Region.clipRound(w / tx.getScaleX()),
|
||||
Region.clipRound(h / tx.getScaleY())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts absolute coordinates from the user's space to the device space
|
||||
* using appropriate device transformation.
|
||||
*
|
||||
* @param x absolute coordinate in the user's space
|
||||
* @param y absolute coordinate in the user's space
|
||||
* @return the point which uses device space (pixels)
|
||||
*/
|
||||
public static Point toDeviceSpaceAbs(int x, int y) {
|
||||
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice().getDefaultConfiguration();
|
||||
gc = getGraphicsConfigurationAtPoint(gc, x, y);
|
||||
return toDeviceSpaceAbs(gc, x, y, 0, 0).getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the rectangle from the user's space to the device space using
|
||||
* appropriate device transformation.
|
||||
*
|
||||
* @param rect the rectangle in the user's space
|
||||
* @return the rectangle which uses device space (pixels)
|
||||
*/
|
||||
public static Rectangle toDeviceSpaceAbs(Rectangle rect) {
|
||||
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice().getDefaultConfiguration();
|
||||
gc = getGraphicsConfigurationAtPoint(gc, rect.x, rect.y);
|
||||
return toDeviceSpaceAbs(gc, rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts absolute coordinates (x, y) and the size (w, h) from the user's
|
||||
* space to the device space using passed graphics configuration.
|
||||
*
|
||||
* @param gc the graphics configuration to be used for transformation
|
||||
* @param x absolute coordinate in the user's space
|
||||
* @param y absolute coordinate in the user's space
|
||||
* @param w the width in the user's space
|
||||
* @param h the height in the user's space
|
||||
* @return the rectangle which uses device space (pixels)
|
||||
*/
|
||||
public static Rectangle toDeviceSpaceAbs(GraphicsConfiguration gc,
|
||||
int x, int y, int w, int h) {
|
||||
AffineTransform tx = gc.getDefaultTransform();
|
||||
Rectangle screen = gc.getBounds();
|
||||
return new Rectangle(
|
||||
screen.x + Region.clipRound((x - screen.x) * tx.getScaleX()),
|
||||
screen.y + Region.clipRound((y - screen.y) * tx.getScaleY()),
|
||||
Region.clipRound(w * tx.getScaleX()),
|
||||
Region.clipRound(h * tx.getScaleY())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts coordinates from the user's space to the device space using
|
||||
* appropriate device transformation.
|
||||
*
|
||||
* @param x coordinate in the user space
|
||||
* @param y coordinate in the user space
|
||||
* @return the point which uses device space(pixels)
|
||||
* @param x coordinate in the user's space
|
||||
* @param y coordinate in the user's space
|
||||
* @return the point which uses device space (pixels)
|
||||
*/
|
||||
public static Point convertToDeviceSpace(double x, double y) {
|
||||
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice().getDefaultConfiguration();
|
||||
gc = getGraphicsConfigurationAtPoint(gc, x, y);
|
||||
|
||||
AffineTransform tx = gc.getDefaultTransform();
|
||||
x = Region.clipRound(x * tx.getScaleX());
|
||||
y = Region.clipRound(y * tx.getScaleY());
|
||||
return new Point((int) x, (int) y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts bounds from the user's space to the device space using
|
||||
* appropriate device transformation.
|
||||
*
|
||||
* @param bounds the rectangle in the user space
|
||||
* @return the rectangle which uses device space(pixels)
|
||||
*/
|
||||
public static Rectangle convertToDeviceSpace(Rectangle bounds) {
|
||||
public static Point toDeviceSpace(int x, int y) {
|
||||
GraphicsConfiguration gc = getLocalGraphicsEnvironment()
|
||||
.getDefaultScreenDevice().getDefaultConfiguration();
|
||||
gc = getGraphicsConfigurationAtPoint(gc, bounds.x, bounds.y);
|
||||
return convertToDeviceSpace(gc, bounds);
|
||||
gc = getGraphicsConfigurationAtPoint(gc, x, y);
|
||||
return toDeviceSpace(gc, x, y, 0, 0).getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts bounds from the user's space to the device space using
|
||||
* appropriate device transformation of the passed graphics configuration.
|
||||
* Converts coordinates (x, y) and the size (w, h) from the user's
|
||||
* space to the device space using passed graphics configuration.
|
||||
*
|
||||
* @param bounds the rectangle in the user space
|
||||
* @return the rectangle which uses device space(pixels)
|
||||
* @param gc the graphics configuration to be used for transformation
|
||||
* @param x coordinate in the user's space
|
||||
* @param y coordinate in the user's space
|
||||
* @param w the width in the user's space
|
||||
* @param h the height in the user's space
|
||||
* @return the rectangle which uses device space (pixels)
|
||||
*/
|
||||
public static Rectangle convertToDeviceSpace(GraphicsConfiguration gc,
|
||||
Rectangle bounds) {
|
||||
public static Rectangle toDeviceSpace(GraphicsConfiguration gc,
|
||||
int x, int y, int w, int h) {
|
||||
AffineTransform tx = gc.getDefaultTransform();
|
||||
return new Rectangle(
|
||||
Region.clipRound(bounds.x * tx.getScaleX()),
|
||||
Region.clipRound(bounds.y * tx.getScaleY()),
|
||||
Region.clipRound(bounds.width * tx.getScaleX()),
|
||||
Region.clipRound(bounds.height * tx.getScaleY())
|
||||
Region.clipRound(x * tx.getScaleX()),
|
||||
Region.clipRound(y * tx.getScaleY()),
|
||||
Region.clipRound(w * tx.getScaleX()),
|
||||
Region.clipRound(h * tx.getScaleY())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ public class Win32GraphicsDevice extends GraphicsDevice implements
|
||||
// display mode
|
||||
Rectangle screenBounds = getDefaultConfiguration().getBounds();
|
||||
w.setBounds(screenBounds.x, screenBounds.y,
|
||||
dm.getWidth(), dm.getHeight());
|
||||
screenBounds.width, screenBounds.height);
|
||||
// Note: no call to replaceSurfaceData is required here since
|
||||
// replacement will be caused by an upcoming display change event
|
||||
} else {
|
||||
|
||||
@@ -520,7 +520,11 @@ public abstract class WComponentPeer extends WObjectPeer
|
||||
|
||||
@Override
|
||||
public boolean updateGraphicsData(GraphicsConfiguration gc) {
|
||||
var old = getGraphicsConfiguration().getDefaultTransform();
|
||||
winGraphicsConfig = (Win32GraphicsConfig)gc;
|
||||
if (gc != null && !old.equals(gc.getDefaultTransform())) {
|
||||
syncBounds(); // the bounds of the peer depend on the DPI
|
||||
}
|
||||
try {
|
||||
replaceSurfaceData();
|
||||
} catch (InvalidPipeException e) {
|
||||
@@ -529,6 +533,15 @@ public abstract class WComponentPeer extends WObjectPeer
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the native peer's coordinates are in sync with the target.
|
||||
*/
|
||||
void syncBounds() {
|
||||
Rectangle r = ((Component) target).getBounds();
|
||||
setBounds(r.x, r.y, r.width, r.height, SET_BOUNDS);
|
||||
}
|
||||
|
||||
|
||||
//This will return null for Components not yet added to a Container
|
||||
@Override
|
||||
public ColorModel getColorModel() {
|
||||
|
||||
@@ -36,6 +36,8 @@ import java.awt.peer.DialogPeer;
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.im.InputMethodManager;
|
||||
|
||||
import static sun.java2d.SunGraphicsEnvironment.toUserSpace;
|
||||
|
||||
final class WDialogPeer extends WWindowPeer implements DialogPeer {
|
||||
// Toolkit & peer internals
|
||||
|
||||
@@ -117,8 +119,8 @@ final class WDialogPeer extends WWindowPeer implements DialogPeer {
|
||||
if (((Dialog)target).isUndecorated()) {
|
||||
return super.getMinimumSize();
|
||||
}
|
||||
return new Dimension(scaleDownX(getSysMinWidth()),
|
||||
scaleDownY(getSysMinHeight()));
|
||||
return toUserSpace(getGraphicsConfiguration(),
|
||||
getSysMinWidth(), getSysMinHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,7 +39,9 @@ import sun.awt.SunToolkit;
|
||||
import sun.awt.im.InputMethodManager;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import static sun.java2d.SunGraphicsEnvironment.convertToDeviceSpace;
|
||||
import static sun.java2d.SunGraphicsEnvironment.getGCDeviceBounds;
|
||||
import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs;
|
||||
import static sun.java2d.SunGraphicsEnvironment.toUserSpace;
|
||||
|
||||
class WFramePeer extends WWindowPeer implements FramePeer {
|
||||
|
||||
@@ -98,10 +100,10 @@ class WFramePeer extends WWindowPeer implements FramePeer {
|
||||
*/
|
||||
private Rectangle adjustMaximizedBounds(Rectangle bounds) {
|
||||
// All calculations should be done in the device space
|
||||
bounds = convertToDeviceSpace(bounds);
|
||||
bounds = toDeviceSpaceAbs(bounds);
|
||||
|
||||
GraphicsConfiguration gc = getGraphicsConfiguration();
|
||||
Rectangle currentDevBounds = convertToDeviceSpace(gc, gc.getBounds());
|
||||
Rectangle currentDevBounds = getGCDeviceBounds(gc);
|
||||
// Prepare data for WM_GETMINMAXINFO message.
|
||||
// ptMaxPosition should be in coordinate system of the current monitor,
|
||||
// not the main monitor, or monitor on which we maximize the window.
|
||||
@@ -126,16 +128,6 @@ class WFramePeer extends WWindowPeer implements FramePeer {
|
||||
public void displayChanged() {
|
||||
super.displayChanged();
|
||||
SunToolkit.executeOnEventHandlerThread(target, this::updateIcon);
|
||||
if (!screenChangedFlag &&
|
||||
(getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 &&
|
||||
(getExtendedState() & Frame.ICONIFIED) == 0) {
|
||||
// A workaround to update the maximized state of the frame
|
||||
SunToolkit.executeOnEventHandlerThread(target, ()->{
|
||||
int state = getExtendedState();
|
||||
setState(Frame.NORMAL);
|
||||
setState(state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private native void updateIcon();
|
||||
@@ -167,13 +159,13 @@ class WFramePeer extends WWindowPeer implements FramePeer {
|
||||
|
||||
@Override
|
||||
public final Dimension getMinimumSize() {
|
||||
GraphicsConfiguration gc = getGraphicsConfiguration();
|
||||
Dimension d = new Dimension();
|
||||
if (!((Frame)target).isUndecorated()) {
|
||||
d.setSize(scaleDownX(getSysMinWidth()),
|
||||
scaleDownY(getSysMinHeight()));
|
||||
d.setSize(toUserSpace(gc, getSysMinWidth(), getSysMinHeight()));
|
||||
}
|
||||
if (((Frame)target).getMenuBar() != null) {
|
||||
d.height += scaleDownY(getSysMenuHeight());
|
||||
d.height += toUserSpace(gc, 0, getSysMenuHeight()).height;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.peer.RobotPeer;
|
||||
|
||||
import sun.java2d.SunGraphicsEnvironment;
|
||||
import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs;
|
||||
|
||||
final class WRobotPeer implements RobotPeer {
|
||||
|
||||
@@ -40,7 +40,7 @@ final class WRobotPeer implements RobotPeer {
|
||||
public native void mouseMoveImpl(int x, int y);
|
||||
@Override
|
||||
public void mouseMove(int x, int y) {
|
||||
Point point = SunGraphicsEnvironment.convertToDeviceSpace(x, y);
|
||||
Point point = toDeviceSpaceAbs(x, y);
|
||||
mouseMoveImpl(point.x, point.y);
|
||||
}
|
||||
@Override
|
||||
@@ -61,6 +61,11 @@ final class WRobotPeer implements RobotPeer {
|
||||
return getRGBPixels(new Rectangle(x, y, 1, 1))[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAbsoluteCoordinates() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int [] getRGBPixels(Rectangle bounds) {
|
||||
int pixelArray[] = new int[bounds.width*bounds.height];
|
||||
|
||||
@@ -37,7 +37,6 @@ import java.awt.Graphics;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.IllegalComponentStateException;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
@@ -58,8 +57,11 @@ import java.awt.image.DataBufferInt;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
@@ -75,6 +77,8 @@ import sun.java2d.pipe.Region;
|
||||
import sun.java2d.SunGraphics2D;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import static sun.java2d.SunGraphicsEnvironment.toUserSpace;
|
||||
|
||||
public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
DisplayChangedListener
|
||||
{
|
||||
@@ -90,9 +94,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
|
||||
private TranslucentWindowPainter painter;
|
||||
|
||||
private int screenNum = 0;
|
||||
protected boolean screenChangedFlag;
|
||||
|
||||
/*
|
||||
* A key used for storing a list of active windows in AppContext. The value
|
||||
* is a list of windows, sorted by the time of activation: later a window is
|
||||
@@ -121,8 +122,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
private WindowListener windowListener;
|
||||
private MouseMotionListener mouseMotionListener;
|
||||
private MouseListener mouseListener;
|
||||
private float scaleX;
|
||||
private float scaleY;
|
||||
|
||||
private Insets sysInsets; // set from native updateInsets
|
||||
|
||||
@@ -216,13 +215,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
super(target);
|
||||
// update GC based on the current bounds
|
||||
updateGC();
|
||||
try {
|
||||
screenNum = getScreenImOn();
|
||||
} catch (IllegalComponentStateException e) {
|
||||
if (log.isLoggable(PlatformLogger.Level.WARNING)) {
|
||||
log.warning(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,8 +239,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
GraphicsConfiguration gc = getGraphicsConfiguration();
|
||||
Win32GraphicsDevice gd = (Win32GraphicsDevice) gc.getDevice();
|
||||
gd.addDisplayChangedListener(this);
|
||||
scaleX = gd.getDefaultScaleX();
|
||||
scaleY = gd.getDefaultScaleY();
|
||||
|
||||
initActiveWindowsTracking((Window)target);
|
||||
|
||||
@@ -335,6 +325,12 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final void syncBounds() {
|
||||
// Windows will take care of the top-level window/frame/dialog, and
|
||||
// update the location/size when DPI changes.
|
||||
}
|
||||
|
||||
// Synchronize the insets members (here & in helper) with actual window
|
||||
// state.
|
||||
native void updateInsets(Insets i);
|
||||
@@ -516,9 +512,10 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
minimumSize = ((Component)target).getMinimumSize();
|
||||
}
|
||||
if (minimumSize != null) {
|
||||
int w = Math.max(minimumSize.width, scaleDownX(getSysMinWidth()));
|
||||
int h = Math.max(minimumSize.height, scaleDownY(getSysMinHeight()));
|
||||
setMinSize(w, h);
|
||||
Dimension sysMin = toUserSpace(getGraphicsConfiguration(),
|
||||
getSysMinWidth(), getSysMinHeight());
|
||||
setMinSize(Math.max(minimumSize.width, sysMin.width),
|
||||
Math.max(minimumSize.height, sysMin.height));
|
||||
} else {
|
||||
setMinSize(0, 0);
|
||||
}
|
||||
@@ -676,23 +673,8 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
|
||||
AWTAccessor.getComponentAccessor().
|
||||
setGraphicsConfiguration((Component)target, winGraphicsConfig);
|
||||
|
||||
// checkDPIChange(oldDev, newDev);
|
||||
}
|
||||
|
||||
/*private void checkDPIChange(Win32GraphicsDevice oldDev,
|
||||
Win32GraphicsDevice newDev) {
|
||||
float newScaleX = newDev.getDefaultScaleX();
|
||||
float newScaleY = newDev.getDefaultScaleY();
|
||||
|
||||
if (scaleX != newScaleX || scaleY != newScaleY) {
|
||||
windowDPIChange(oldDev.getScreen(), scaleX, scaleY,
|
||||
newDev.getScreen(), newScaleX, newScaleY);
|
||||
scaleX = newScaleX;
|
||||
scaleY = newScaleY;
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* From the DisplayChangedListener interface.
|
||||
*
|
||||
@@ -706,17 +688,9 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
*/
|
||||
@Override
|
||||
public void displayChanged() {
|
||||
int scrn = getScreenImOn();
|
||||
screenChangedFlag = scrn != screenNum;
|
||||
screenNum = scrn;
|
||||
SunToolkit.executeOnEventHandlerThread(target, ()->{
|
||||
updateGC();
|
||||
adjustBoundsOnDPIChange();
|
||||
});
|
||||
SunToolkit.executeOnEventHandlerThread(target, this::updateGC);
|
||||
}
|
||||
|
||||
private native void adjustBoundsOnDPIChange();
|
||||
|
||||
/**
|
||||
* Part of the DisplayChangedListener interface: components
|
||||
* do not need to react to this event
|
||||
@@ -752,78 +726,9 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
return true;
|
||||
}
|
||||
|
||||
// These are the peer bounds. They get updated at:
|
||||
// 1. the WWindowPeer.setBounds() method.
|
||||
// 2. the native code (on WM_SIZE/WM_MOVE)
|
||||
private volatile int sysX = 0;
|
||||
private volatile int sysY = 0;
|
||||
private volatile int sysW = 0;
|
||||
private volatile int sysH = 0;
|
||||
|
||||
@Override
|
||||
public native void repositionSecurityWarning();
|
||||
|
||||
@Override
|
||||
public void setBounds(int x, int y, int width, int height, int op) {
|
||||
sysX = x;
|
||||
sysY = y;
|
||||
sysW = width;
|
||||
sysH = height;
|
||||
|
||||
/* [tav] JDK-8176097 fixed by JRE-119
|
||||
int cx = x + width / 2;
|
||||
int cy = y + height / 2;
|
||||
GraphicsConfiguration current = getGraphicsConfiguration();
|
||||
GraphicsConfiguration other = SunGraphicsEnvironment
|
||||
.getGraphicsConfigurationAtPoint(current, cx, cy);
|
||||
if (!current.equals(other)) {
|
||||
AffineTransform tx = other.getDefaultTransform();
|
||||
double otherScaleX = tx.getScaleX();
|
||||
double otherScaleY = tx.getScaleY();
|
||||
initScales();
|
||||
if (scaleX != otherScaleX || scaleY != otherScaleY) {
|
||||
x = (int) Math.floor(x * otherScaleX / scaleX);
|
||||
y = (int) Math.floor(y * otherScaleY / scaleY);
|
||||
}
|
||||
}*/
|
||||
|
||||
super.setBounds(x, y, width, height, op);
|
||||
}
|
||||
|
||||
private void initScales() {
|
||||
|
||||
if (scaleX >= 1 && scaleY >= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
GraphicsConfiguration gc = getGraphicsConfiguration();
|
||||
if (gc instanceof Win32GraphicsConfig) {
|
||||
Win32GraphicsDevice gd = ((Win32GraphicsConfig) gc).getDevice();
|
||||
scaleX = gd.getDefaultScaleX();
|
||||
scaleY = gd.getDefaultScaleY();
|
||||
} else {
|
||||
AffineTransform tx = gc.getDefaultTransform();
|
||||
scaleX = (float) tx.getScaleX();
|
||||
scaleY = (float) tx.getScaleY();
|
||||
}
|
||||
}
|
||||
|
||||
final int scaleUpX(int x) {
|
||||
return Region.clipRound(x * scaleX);
|
||||
}
|
||||
|
||||
final int scaleUpY(int y) {
|
||||
return Region.clipRound(y * scaleY);
|
||||
}
|
||||
|
||||
final int scaleDownX(int x) {
|
||||
return Region.clipRound(x / scaleX);
|
||||
}
|
||||
|
||||
final int scaleDownY(int y) {
|
||||
return Region.clipRound(y / scaleY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(Graphics g) {
|
||||
// We assume we print the whole frame,
|
||||
@@ -992,9 +897,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
}
|
||||
}
|
||||
|
||||
/*native void windowDPIChange(int prevScreen, float prevScaleX, float prevScaleY,
|
||||
int newScreen, float newScaleX, float newScaleY);*/
|
||||
|
||||
/*
|
||||
* The method maps the list of the active windows to the window's AppContext,
|
||||
* then the method registers ActiveWindowListener, GuiDisposedListener listeners;
|
||||
@@ -1146,31 +1048,29 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer,
|
||||
return err;
|
||||
}
|
||||
|
||||
private volatile List<Rectangle> customDecorHitTestSpots;
|
||||
private volatile int customDecorTitleBarHeight = -1; // 0 can be a legal value when no title bar is expected
|
||||
|
||||
// called from client via reflection
|
||||
@Deprecated
|
||||
private void setCustomDecorationHitTestSpots(List<Rectangle> hitTestSpots) {
|
||||
this.customDecorHitTestSpots = new CopyOnWriteArrayList<>(hitTestSpots);
|
||||
List<Map.Entry<Shape, Integer>> spots = new ArrayList<>();
|
||||
for (Rectangle spot : hitTestSpots) spots.add(Map.entry(spot, 1));
|
||||
try {
|
||||
Field f = Window.class.getDeclaredField("customDecorHitTestSpots");
|
||||
f.setAccessible(true);
|
||||
f.set(target, spots);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// called from client via reflection
|
||||
@Deprecated
|
||||
private void setCustomDecorationTitleBarHeight(int height) {
|
||||
if (height >= 0) customDecorTitleBarHeight = height;
|
||||
}
|
||||
|
||||
// called from native
|
||||
private boolean hitTestCustomDecoration(int x, int y) {
|
||||
List<Rectangle> spots = customDecorHitTestSpots;
|
||||
if (spots == null) return false;
|
||||
for (Rectangle spot : spots) {
|
||||
if (spot.contains(x, y)) return true;
|
||||
try {
|
||||
Field f = Window.class.getDeclaredField("customDecorTitleBarHeight");
|
||||
f.setAccessible(true);
|
||||
f.set(target, height);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// called from native
|
||||
private int getCustomDecorationTitleBarHeight() {
|
||||
return customDecorTitleBarHeight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,6 @@ Java_sun_awt_windows_WMouseInfoPeer_fillPointWithCoords(JNIEnv *env, jclass cls,
|
||||
POINT pt;
|
||||
|
||||
VERIFY(::GetCursorPos(&pt));
|
||||
AwtWin32GraphicsDevice::ScaleDownDPoint(&pt);
|
||||
if (pointClass == NULL) {
|
||||
jclass pointClassLocal = env->FindClass("java/awt/Point");
|
||||
DASSERT(pointClassLocal != NULL);
|
||||
@@ -107,6 +106,9 @@ Java_sun_awt_windows_WMouseInfoPeer_fillPointWithCoords(JNIEnv *env, jclass cls,
|
||||
yID = env->GetFieldID(pointClass, "y", "I");
|
||||
CHECK_NULL_RETURN(yID, (jint)0);
|
||||
|
||||
int x = (device == NULL) ? pt.x : device->ScaleDownAbsX(pt.x);
|
||||
int y = (device == NULL) ? pt.y : device->ScaleDownAbsY(pt.y);
|
||||
|
||||
env->SetIntField(point, xID, pt.x);
|
||||
env->SetIntField(point, yID, pt.y);
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
#include "awt_Toolkit.h"
|
||||
#include "awt_Window.h"
|
||||
#include "awt_Win32GraphicsDevice.h"
|
||||
#include "awt_Win32GraphicsConfig.h"
|
||||
#include "Hashtable.h"
|
||||
#include "ComCtl32Util.h"
|
||||
|
||||
@@ -598,7 +597,7 @@ AwtComponent::CreateHWnd(JNIEnv *env, LPCWSTR title,
|
||||
/*
|
||||
* Fix for 4046446.
|
||||
*/
|
||||
SetWindowPos(GetHWnd(), 0, x, y, w, h, SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOACTIVATE);
|
||||
Reshape(x, y, w, h);
|
||||
|
||||
/* Set default colors. */
|
||||
m_colorForeground = colorForeground;
|
||||
@@ -964,11 +963,11 @@ AwtComponent::SetWindowPos(HWND wnd, HWND after,
|
||||
}
|
||||
|
||||
void AwtComponent::Reshape(int x, int y, int w, int h) {
|
||||
/* ReshapeNoScale(ScaleUpX(x), ScaleUpY(y), ScaleUpX(w), ScaleUpY(h));
|
||||
ReshapeNoScale(ScaleUpX(x), ScaleUpY(y), ScaleUpX(w), ScaleUpY(h));
|
||||
}
|
||||
|
||||
void AwtComponent::ReshapeNoScale(int x, int y, int w, int h)
|
||||
{*/
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
RECT rc;
|
||||
::GetWindowRect(GetHWnd(), &rc);
|
||||
@@ -976,57 +975,9 @@ void AwtComponent::ReshapeNoScale(int x, int y, int w, int h)
|
||||
DTRACE_PRINTLN4("AwtComponent::Reshape from %d, %d, %d, %d", rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top);
|
||||
#endif
|
||||
|
||||
int usrX = x;
|
||||
int usrY = y;
|
||||
|
||||
AwtWin32GraphicsDevice* device = UGetDeviceByBounds(URectBounds(x, y, w, h, USER_SPACE), this);
|
||||
x = device->ScaleUpX(x);
|
||||
y = device->ScaleUpY(y);
|
||||
w = device->ScaleUpX(w);
|
||||
h = device->ScaleUpY(h);
|
||||
|
||||
AwtWindow* container = GetContainer();
|
||||
AwtComponent* parent = GetParent();
|
||||
|
||||
// [tav] Handle the fact that an owned window is most likely positioned relative to its owner, and it may
|
||||
// require pixel-perfect alignment. For that, compensate rounding errors (caused by converting from the device
|
||||
// space to the integer user space and back) for the owner's origin and for the owner's client area origin.
|
||||
if (IsTopLevel() && parent != NULL &&
|
||||
(device->GetScaleX() > 1 || device->GetScaleY() > 1))
|
||||
{
|
||||
RECT parentInsets;
|
||||
parent->GetInsets(&parentInsets);
|
||||
// Convert the owner's client area origin to user space
|
||||
int parentInsetsUsrX = device->ScaleDownX(parentInsets.left);
|
||||
int parentInsetsUsrY = device->ScaleDownY(parentInsets.top);
|
||||
|
||||
RECT parentRect;
|
||||
VERIFY(::GetWindowRect(parent->GetHWnd(), &parentRect));
|
||||
// Convert the owner's origin to user space
|
||||
int parentUsrX = device->ScaleDownX(parentRect.left);
|
||||
int parentUsrY = device->ScaleDownY(parentRect.top);
|
||||
|
||||
// Calc the offset from the owner's client area in user space
|
||||
int offsetUsrX = usrX - parentUsrX - parentInsetsUsrX;
|
||||
int offsetUsrY = usrY - parentUsrY - parentInsetsUsrY;
|
||||
|
||||
// Convert the offset to device space
|
||||
int offsetDevX = device->ScaleUpX(offsetUsrX);
|
||||
int offsetDevY = device->ScaleUpY(offsetUsrY);
|
||||
|
||||
// Finally calc the window's location based on the frame's and its insets system numbers.
|
||||
int devX = parentRect.left + parentInsets.left + offsetDevX;
|
||||
int devY = parentRect.top + parentInsets.top + offsetDevY;
|
||||
|
||||
// Check the toplevel is not going to be moved to another screen.
|
||||
::SetRect(&parentRect, devX, devY, devX + w, devY + h);
|
||||
HMONITOR hmon = ::MonitorFromRect(&parentRect, MONITOR_DEFAULTTONEAREST);
|
||||
if (hmon != NULL && AwtWin32GraphicsDevice::GetScreenFromHMONITOR(hmon) == device->GetDeviceIndex()) {
|
||||
x = devX;
|
||||
y = devY;
|
||||
}
|
||||
}
|
||||
|
||||
if (container != NULL && container == parent) {
|
||||
container->SubtractInsetPoint(x, y);
|
||||
}
|
||||
@@ -1133,6 +1084,7 @@ void SpyWinMessage(HWND hwnd, UINT message, LPCTSTR szComment) {
|
||||
WIN_MSG(WM_DESTROY)
|
||||
WIN_MSG(WM_MOVE)
|
||||
WIN_MSG(WM_SIZE)
|
||||
WIN_MSG(WM_DPICHANGED)
|
||||
WIN_MSG(WM_ACTIVATE)
|
||||
WIN_MSG(WM_SETFOCUS)
|
||||
WIN_MSG(WM_KILLFOCUS)
|
||||
@@ -1571,9 +1523,9 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
case WM_SIZE:
|
||||
{
|
||||
RECT r;
|
||||
// fix 4128317 : use GetClientRect for full 32-bit int precision and
|
||||
// fix 4128317 : use GetWindowRect for full 32-bit int precision and
|
||||
// to avoid negative client area dimensions overflowing 16-bit params - robi
|
||||
::GetClientRect( GetHWnd(), &r );
|
||||
::GetWindowRect(GetHWnd(), &r);
|
||||
mr = WmSize(static_cast<UINT>(wParam), r.right - r.left, r.bottom - r.top);
|
||||
//mr = WmSize(wParam, LOWORD(lParam), HIWORD(lParam));
|
||||
SetCompositionWindow(r);
|
||||
@@ -1590,11 +1542,9 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
break;
|
||||
case WM_ENTERSIZEMOVE:
|
||||
m_inMoveResizeLoop = TRUE;
|
||||
mr = WmEnterSizeMove();
|
||||
break;
|
||||
case WM_EXITSIZEMOVE:
|
||||
m_inMoveResizeLoop = FALSE;
|
||||
mr = WmExitSizeMove();
|
||||
break;
|
||||
// Bug #4039858 (Selecting menu item causes bogus mouse click event)
|
||||
@@ -1699,6 +1649,9 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
case WM_NCRBUTTONDOWN:
|
||||
mr = WmNcMouseDown(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), RIGHT_BUTTON);
|
||||
break;
|
||||
case WM_NCMOUSEMOVE:
|
||||
mr = WmNcMouseMove(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
if (ignoreNextLBTNUP) {
|
||||
ignoreNextLBTNUP = FALSE;
|
||||
@@ -2015,10 +1968,6 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
mr = WmContextMenu((HWND)wParam,
|
||||
GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
break;
|
||||
#define WM_DPICHANGED 0x02E0 // Since Win 8.1 in WinUser.h
|
||||
case WM_DPICHANGED:
|
||||
mr = WmDPIChanged(HIWORD(wParam), LOWORD(wParam), (RECT*)lParam);
|
||||
break;
|
||||
|
||||
/*
|
||||
* These messages are used to route Win32 calls to the
|
||||
@@ -2387,6 +2336,9 @@ MsgRouting AwtComponent::WmNcMouseDown(WPARAM hitTest, int x, int y, int button)
|
||||
MsgRouting AwtComponent::WmNcMouseUp(WPARAM hitTest, int x, int y, int button) {
|
||||
return mrDoDefault;
|
||||
}
|
||||
MsgRouting AwtComponent::WmNcMouseMove(WPARAM hitTest, int x, int y) {
|
||||
return mrDoDefault;
|
||||
}
|
||||
|
||||
MsgRouting AwtComponent::WmWindowPosChanging(LPARAM windowPos) {
|
||||
return mrDoDefault;
|
||||
@@ -4057,8 +4009,8 @@ void AwtComponent::OpenCandidateWindow(int x, int y)
|
||||
}
|
||||
HWND hTop = GetTopLevelParentForWindow(hWnd);
|
||||
::ClientToScreen(hTop, &p);
|
||||
int sx = ScaleUpX(x, ABSOLUTE_COORD) - p.x;
|
||||
int sy = ScaleUpY(y, ABSOLUTE_COORD) - p.y;
|
||||
int sx = ScaleUpAbsX(x) - p.x;
|
||||
int sy = ScaleUpAbsY(y) - p.y;
|
||||
if (!m_bitsCandType) {
|
||||
SetCandidateWindow(m_bitsCandType, sx, sy);
|
||||
return;
|
||||
@@ -4944,64 +4896,70 @@ void AwtComponent::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha)
|
||||
}
|
||||
}
|
||||
|
||||
int AwtComponent::ScaleUpX(int x, const UCoordRelativity& relativity) {
|
||||
if (relativity == ABSOLUTE_COORD) return ScaleUpDX(x);
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
|
||||
int AwtComponent::GetScreenImOn() {
|
||||
HWND hWindow = GetAncestor(GetHWnd(), GA_ROOT);
|
||||
AwtComponent *comp = AwtComponent::GetComponent(hWindow);
|
||||
if (comp && comp->IsTopLevel()) {
|
||||
return comp->GetScreenImOn();
|
||||
}
|
||||
return AwtWin32GraphicsDevice::DeviceIndexForWindow(hWindow);
|
||||
}
|
||||
|
||||
|
||||
int AwtComponent::ScaleUpX(int x) {
|
||||
int screen = GetScreenImOn();
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? x : device->ScaleUpX(x);
|
||||
}
|
||||
|
||||
int AwtComponent::ScaleUpDX(int x) {
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
|
||||
int AwtComponent::ScaleUpAbsX(int x) {
|
||||
int screen = GetScreenImOn();
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? x : device->ScaleUpDX(x);
|
||||
return device == NULL ? x : device->ScaleUpAbsX(x);
|
||||
}
|
||||
|
||||
int AwtComponent::ScaleUpY(int y, const UCoordRelativity& relativity) {
|
||||
if (relativity == ABSOLUTE_COORD) return ScaleUpDY(y);
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
|
||||
int AwtComponent::ScaleUpY(int y) {
|
||||
int screen = GetScreenImOn();
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? y : device->ScaleUpY(y);
|
||||
}
|
||||
|
||||
int AwtComponent::ScaleUpDY(int y) {
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
|
||||
int AwtComponent::ScaleUpAbsY(int y) {
|
||||
int screen = GetScreenImOn();
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? y : device->ScaleUpDY(y);
|
||||
return device == NULL ? y : device->ScaleUpAbsY(y);
|
||||
}
|
||||
|
||||
int AwtComponent::ScaleDownX(int x, const UCoordRelativity& relativity) {
|
||||
if (relativity == ABSOLUTE_COORD) return ScaleDownDX(x);
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
|
||||
int AwtComponent::ScaleDownX(int x) {
|
||||
int screen = GetScreenImOn();
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? x : device->ScaleDownX(x);
|
||||
}
|
||||
|
||||
int AwtComponent::ScaleDownDX(int x) {
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
|
||||
int AwtComponent::ScaleDownAbsX(int x) {
|
||||
int screen = GetScreenImOn();
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? x : device->ScaleDownDX(x);
|
||||
return device == NULL ? x : device->ScaleDownAbsX(x);
|
||||
}
|
||||
|
||||
int AwtComponent::ScaleDownY(int y, const UCoordRelativity& relativity) {
|
||||
if (relativity == ABSOLUTE_COORD) return ScaleUpDY(y);
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
|
||||
int AwtComponent::ScaleDownY(int y) {
|
||||
int screen = GetScreenImOn();
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? y : device->ScaleDownY(y);
|
||||
}
|
||||
|
||||
int AwtComponent::ScaleDownDY(int y) {
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd());
|
||||
int AwtComponent::ScaleDownAbsY(int y) {
|
||||
int screen = GetScreenImOn();
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? y : device->ScaleDownDY(y);
|
||||
return device == NULL ? y : device->ScaleDownAbsY(y);
|
||||
}
|
||||
|
||||
void AwtComponent::ScaleDownRect(RECT& r) {
|
||||
@@ -5309,7 +5267,7 @@ void AwtComponent::SendMouseEvent(jint id, jlong when, jint x, jint y,
|
||||
id, when, modifiers,
|
||||
ScaleDownX(x + insets.left),
|
||||
ScaleDownY(y + insets.top),
|
||||
ScaleDownX(xAbs), ScaleDownY(yAbs),
|
||||
ScaleDownAbsX(xAbs), ScaleDownAbsY(yAbs),
|
||||
clickCount, popupTrigger, button);
|
||||
|
||||
if (safe_ExceptionOccurred(env)) {
|
||||
@@ -5382,8 +5340,8 @@ AwtComponent::SendMouseWheelEvent(jint id, jlong when, jint x, jint y,
|
||||
id, when, modifiers,
|
||||
ScaleDownX(x + insets.left),
|
||||
ScaleDownY(y + insets.top),
|
||||
ScaleDownX(xAbs),
|
||||
ScaleDownY(yAbs),
|
||||
ScaleDownAbsX(xAbs),
|
||||
ScaleDownAbsY(yAbs),
|
||||
clickCount, popupTrigger,
|
||||
scrollType, scrollAmount,
|
||||
roundedWheelRotation, preciseWheelRotation);
|
||||
@@ -5893,8 +5851,8 @@ jobject AwtComponent::_GetLocationOnScreen(void *param)
|
||||
RECT rect;
|
||||
VERIFY(::GetWindowRect(p->GetHWnd(),&rect));
|
||||
result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V",
|
||||
p->ScaleDownX(rect.left),
|
||||
p->ScaleDownY(rect.top));
|
||||
p->ScaleDownAbsX(rect.left),
|
||||
p->ScaleDownAbsY(rect.top));
|
||||
}
|
||||
ret:
|
||||
env->DeleteGlobalRef(self);
|
||||
@@ -7494,8 +7452,8 @@ void AwtComponent::VerifyState()
|
||||
target = parent;
|
||||
}
|
||||
|
||||
x = ScaleUpX(x, RELATIVITY_FOR_COMP_XY(this));
|
||||
y = ScaleUpY(y, RELATIVITY_FOR_COMP_XY(this));
|
||||
x = ScaleUpX(x);
|
||||
y = ScaleUpY(y);
|
||||
width = ScaleUpX(width);
|
||||
height = ScaleUpY(height);
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "awt_Brush.h"
|
||||
#include "awt_Pen.h"
|
||||
#include "awt_Win32GraphicsDevice.h"
|
||||
#include "awt_Util.h"
|
||||
|
||||
#include "GDIWindowSurfaceData.h"
|
||||
|
||||
@@ -272,10 +271,11 @@ public:
|
||||
/*
|
||||
* methods on this component
|
||||
*/
|
||||
virtual int GetScreenImOn();
|
||||
virtual void Show();
|
||||
virtual void Hide();
|
||||
virtual void Reshape(int x, int y, int w, int h);
|
||||
// void ReshapeNoScale(int x, int y, int w, int h);
|
||||
void ReshapeNoScale(int x, int y, int w, int h);
|
||||
|
||||
/*
|
||||
* Fix for 4046446.
|
||||
@@ -526,6 +526,7 @@ public:
|
||||
int wheelRotation, BOOL isHorizontal);
|
||||
virtual MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
|
||||
virtual MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
|
||||
virtual MsgRouting WmNcMouseMove(WPARAM hitTest, int x, int y);
|
||||
virtual MsgRouting WmWindowPosChanging(LPARAM windowPos);
|
||||
virtual MsgRouting WmWindowPosChanged(LPARAM windowPos);
|
||||
virtual void WmTouch(WPARAM wParam, LPARAM lParam);
|
||||
@@ -605,10 +606,6 @@ public:
|
||||
return mrDoDefault;
|
||||
}
|
||||
|
||||
virtual MsgRouting WmDPIChanged(UINT xDPI, UINT yDPI, RECT* bounds) {
|
||||
return mrDoDefault;
|
||||
}
|
||||
|
||||
void UpdateColorModel();
|
||||
|
||||
jintArray CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha);
|
||||
@@ -731,14 +728,14 @@ public:
|
||||
return m_bPauseDestroy;
|
||||
}
|
||||
|
||||
int ScaleUpX(int x, const UCoordRelativity& relativity = RELATIVE_COORD);
|
||||
int ScaleUpY(int y, const UCoordRelativity& relativity = RELATIVE_COORD);
|
||||
int ScaleDownX(int x, const UCoordRelativity& relativity = RELATIVE_COORD);
|
||||
int ScaleDownY(int y, const UCoordRelativity& relativity = RELATIVE_COORD);
|
||||
int ScaleUpDX(int x);
|
||||
int ScaleUpDY(int y);
|
||||
int ScaleDownDX(int x);
|
||||
int ScaleDownDY(int y);
|
||||
int ScaleUpX(int x);
|
||||
int ScaleUpAbsX(int x);
|
||||
int ScaleUpY(int y);
|
||||
int ScaleUpAbsY(int y);
|
||||
int ScaleDownX(int x);
|
||||
int ScaleDownAbsX(int x);
|
||||
int ScaleDownY(int y);
|
||||
int ScaleDownAbsY(int y);
|
||||
void ScaleDownRect(RECT& r);
|
||||
//void ScaleDownDRect(RECT& r);
|
||||
|
||||
@@ -755,8 +752,6 @@ protected:
|
||||
static BOOL sm_suppressFocusAndActivation;
|
||||
static BOOL sm_restoreFocusAndActivation;
|
||||
|
||||
INLINE BOOL IsInMoveResizeLoop() { return m_inMoveResizeLoop; }
|
||||
|
||||
/*
|
||||
* The function sets the focus-restore flag ON/OFF.
|
||||
* When the flag is ON, focus is restored immidiately after the proxy loses it.
|
||||
@@ -853,8 +848,6 @@ private:
|
||||
int m_wheelRotationAmountX;
|
||||
int m_wheelRotationAmountY;
|
||||
|
||||
BOOL m_inMoveResizeLoop;
|
||||
|
||||
BOOL deadKeyActive;
|
||||
|
||||
/*
|
||||
|
||||
@@ -473,9 +473,14 @@ Java_sun_awt_windows_WGlobalCursorManager_getCursorPos(JNIEnv *env,
|
||||
|
||||
POINT p;
|
||||
::GetCursorPos(&p);
|
||||
AwtWin32GraphicsDevice::ScaleDownDPoint(&p);
|
||||
env->SetIntField(point, AwtCursor::pointXID, (jint)p.x);
|
||||
env->SetIntField(point, AwtCursor::pointYID, (jint)p.y);
|
||||
HMONITOR monitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
|
||||
int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
|
||||
int x = (device == NULL) ? p.x : device->ScaleDownAbsX(p.x);
|
||||
int y = (device == NULL) ? p.y : device->ScaleDownAbsY(p.y);
|
||||
env->SetIntField(point, AwtCursor::pointXID, x);
|
||||
env->SetIntField(point, AwtCursor::pointYID, y);
|
||||
|
||||
CATCH_BAD_ALLOC;
|
||||
}
|
||||
|
||||
@@ -1178,14 +1178,14 @@ HRESULT __stdcall AwtDragSource::GetProcessId(FORMATETC __RPC_FAR *pFormatEtc, S
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void ScaleDown(POINT &pt) {
|
||||
static void ScaleDownAbs(POINT &pt) {
|
||||
HMONITOR monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
|
||||
int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
|
||||
if (device) {
|
||||
pt.x = device->ScaleDownX(pt.x);
|
||||
pt.y = device->ScaleDownY(pt.y);
|
||||
pt.x = device->ScaleDownAbsX(pt.x);
|
||||
pt.y = device->ScaleDownAbsY(pt.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1194,7 +1194,7 @@ DECLARE_JAVA_CLASS(dSCClazz, "sun/awt/windows/WDragSourceContextPeer")
|
||||
void
|
||||
AwtDragSource::call_dSCenter(JNIEnv* env, jobject self, jint targetActions,
|
||||
jint modifiers, POINT pt) {
|
||||
ScaleDown(pt);
|
||||
ScaleDownAbs(pt);
|
||||
DECLARE_VOID_JAVA_METHOD(dSCenter, dSCClazz, "dragEnter", "(IIII)V");
|
||||
DASSERT(!JNU_IsNull(env, self));
|
||||
env->CallVoidMethod(self, dSCenter, targetActions, modifiers, pt.x, pt.y);
|
||||
@@ -1207,7 +1207,7 @@ AwtDragSource::call_dSCenter(JNIEnv* env, jobject self, jint targetActions,
|
||||
void
|
||||
AwtDragSource::call_dSCmotion(JNIEnv* env, jobject self, jint targetActions,
|
||||
jint modifiers, POINT pt) {
|
||||
ScaleDown(pt);
|
||||
ScaleDownAbs(pt);
|
||||
DECLARE_VOID_JAVA_METHOD(dSCmotion, dSCClazz, "dragMotion", "(IIII)V");
|
||||
DASSERT(!JNU_IsNull(env, self));
|
||||
env->CallVoidMethod(self, dSCmotion, targetActions, modifiers, pt.x, pt.y);
|
||||
@@ -1220,7 +1220,7 @@ AwtDragSource::call_dSCmotion(JNIEnv* env, jobject self, jint targetActions,
|
||||
void
|
||||
AwtDragSource::call_dSCchanged(JNIEnv* env, jobject self, jint targetActions,
|
||||
jint modifiers, POINT pt) {
|
||||
ScaleDown(pt);
|
||||
ScaleDownAbs(pt);
|
||||
DECLARE_VOID_JAVA_METHOD(dSCchanged, dSCClazz, "operationChanged",
|
||||
"(IIII)V");
|
||||
DASSERT(!JNU_IsNull(env, self));
|
||||
@@ -1233,7 +1233,7 @@ AwtDragSource::call_dSCchanged(JNIEnv* env, jobject self, jint targetActions,
|
||||
|
||||
void
|
||||
AwtDragSource::call_dSCexit(JNIEnv* env, jobject self, POINT pt) {
|
||||
ScaleDown(pt);
|
||||
ScaleDownAbs(pt);
|
||||
DECLARE_VOID_JAVA_METHOD(dSCexit, dSCClazz, "dragExit", "(II)V");
|
||||
DASSERT(!JNU_IsNull(env, self));
|
||||
env->CallVoidMethod(self, dSCexit, pt.x, pt.y);
|
||||
@@ -1246,7 +1246,7 @@ AwtDragSource::call_dSCexit(JNIEnv* env, jobject self, POINT pt) {
|
||||
void
|
||||
AwtDragSource::call_dSCddfinished(JNIEnv* env, jobject self, jboolean success,
|
||||
jint operations, POINT pt) {
|
||||
ScaleDown(pt);
|
||||
ScaleDownAbs(pt);
|
||||
DECLARE_VOID_JAVA_METHOD(dSCddfinished, dSCClazz, "dragDropFinished", "(ZIII)V");
|
||||
DASSERT(!JNU_IsNull(env, self));
|
||||
env->CallVoidMethod(self, dSCddfinished, success, operations, pt.x, pt.y);
|
||||
@@ -1259,7 +1259,7 @@ AwtDragSource::call_dSCddfinished(JNIEnv* env, jobject self, jboolean success,
|
||||
void
|
||||
AwtDragSource::call_dSCmouseMoved(JNIEnv* env, jobject self, jint targetActions,
|
||||
jint modifiers, POINT pt) {
|
||||
ScaleDown(pt);
|
||||
ScaleDownAbs(pt);
|
||||
DECLARE_VOID_JAVA_METHOD(dSCmouseMoved, dSCClazz, "dragMouseMoved",
|
||||
"(IIII)V");
|
||||
DASSERT(!JNU_IsNull(env, self));
|
||||
|
||||
@@ -1320,18 +1320,18 @@ Java_sun_awt_windows_WFileDialogPeer_toBack(JNIEnv *env, jobject peer)
|
||||
CATCH_BAD_ALLOC;
|
||||
}
|
||||
|
||||
int ScaleDownX(int x, HWND hwnd) {
|
||||
int ScaleDownAbsX(int x, HWND hwnd) {
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd);
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? x : device->ScaleDownX(x);
|
||||
return device == NULL ? x : device->ScaleDownAbsX(x);
|
||||
}
|
||||
|
||||
int ScaleDownY(int y, HWND hwnd) {
|
||||
int ScaleDownAbsY(int y, HWND hwnd) {
|
||||
int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd);
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
return device == NULL ? y : device->ScaleDownY(y);
|
||||
return device == NULL ? y : device->ScaleDownAbsY(y);
|
||||
}
|
||||
|
||||
jobject AwtFileDialog::_GetLocationOnScreen(void *param)
|
||||
@@ -1346,7 +1346,8 @@ jobject AwtFileDialog::_GetLocationOnScreen(void *param)
|
||||
RECT rect;
|
||||
VERIFY(::GetWindowRect(hwnd, &rect));
|
||||
result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V",
|
||||
ScaleDownX(rect.left, hwnd), ScaleDownY(rect.top, hwnd));
|
||||
ScaleDownAbsX(rect.left, hwnd),
|
||||
ScaleDownAbsY(rect.top, hwnd));
|
||||
}
|
||||
|
||||
if (result != NULL)
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <dwmapi.h>
|
||||
|
||||
#include <java_lang_Integer.h>
|
||||
#include <java_awt_Window_CustomWindowDecoration.h>
|
||||
#include <sun_awt_windows_WEmbeddedFrame.h>
|
||||
#include <sun_awt_windows_WEmbeddedFramePeer.h>
|
||||
|
||||
@@ -332,17 +333,13 @@ AwtFrame* AwtFrame::Create(jobject self, jobject parent)
|
||||
frame->CreateHWnd(env, L"",
|
||||
style,
|
||||
exStyle,
|
||||
0, 0, 0, 0,
|
||||
x, y, width, height,
|
||||
hwndParent,
|
||||
NULL,
|
||||
::GetSysColor(COLOR_WINDOWTEXT),
|
||||
::GetSysColor(COLOR_WINDOWFRAME),
|
||||
self);
|
||||
/*
|
||||
* Reshape here instead of during create, so that a
|
||||
* WM_NCCALCSIZE is sent.
|
||||
*/
|
||||
frame->Reshape(x, y, width, height);
|
||||
frame->RecalcNonClient();
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
@@ -626,6 +623,23 @@ MsgRouting AwtFrame::WmNcMouseDown(WPARAM hitTest, int x, int y, int button) {
|
||||
if (m_grabbedWindow != NULL/* && !m_grabbedWindow->IsOneOfOwnersOf(this)*/) {
|
||||
m_grabbedWindow->Ungrab();
|
||||
}
|
||||
// For windows with custom decorations, handle caption-related mouse events
|
||||
// Do not handle events from caption itself to preserve native drag behavior
|
||||
if (HasCustomDecoration()) {
|
||||
switch (hitTest) {
|
||||
case HTMINBUTTON:
|
||||
case HTMAXBUTTON:
|
||||
case HTCLOSE:
|
||||
case HTMENU:
|
||||
RECT rcWindow;
|
||||
GetWindowRect(GetHWnd(), &rcWindow);
|
||||
WmMouseDown(GetButtonMK(button),
|
||||
x - rcWindow.left,
|
||||
y - rcWindow.top,
|
||||
button);
|
||||
return mrConsume;
|
||||
}
|
||||
}
|
||||
if (!IsFocusableWindow() && (button & LEFT_BUTTON)) {
|
||||
switch (hitTest) {
|
||||
case HTTOP:
|
||||
@@ -657,6 +671,24 @@ MsgRouting AwtFrame::WmNcMouseDown(WPARAM hitTest, int x, int y, int button) {
|
||||
return AwtWindow::WmNcMouseDown(hitTest, x, y, button);
|
||||
}
|
||||
|
||||
MsgRouting AwtFrame::WmNcMouseMove(WPARAM hitTest, int x, int y) {
|
||||
// For windows with custom decorations, handle caption-related mouse events
|
||||
if (HasCustomDecoration()) {
|
||||
switch (hitTest) {
|
||||
case HTMINBUTTON:
|
||||
case HTMAXBUTTON:
|
||||
case HTCLOSE:
|
||||
case HTMENU:
|
||||
case HTCAPTION:
|
||||
RECT rcWindow;
|
||||
GetWindowRect(GetHWnd(), &rcWindow);
|
||||
WmMouseMove(0, x - rcWindow.left, y - rcWindow.top);
|
||||
if (hitTest != HTCAPTION) return mrConsume; // Preserve default window drag for HTCAPTION
|
||||
}
|
||||
}
|
||||
return AwtWindow::WmNcMouseMove(hitTest, x, y);
|
||||
}
|
||||
|
||||
// Override AwtWindow::Reshape() to handle minimized/maximized
|
||||
// frames (see 6525850, 4065534)
|
||||
void AwtFrame::Reshape(int x, int y, int width, int height)
|
||||
@@ -1250,22 +1282,6 @@ MsgRouting AwtFrame::WmSysCommand(UINT uCmdType, int xPos, int yPos)
|
||||
return AwtWindow::WmSysCommand(uCmdType, xPos, yPos);
|
||||
}
|
||||
|
||||
MsgRouting AwtFrame::WmDPIChanged(UINT xDPI, UINT yDPI, RECT* bounds) {
|
||||
if (isZoomed() && !m_maxBoundsSet) {
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()));
|
||||
if (device) {
|
||||
float factorX = xDPI / 96.0f / device->GetScaleX();
|
||||
float factorY = yDPI / 96.0f / device->GetScaleY();
|
||||
|
||||
// adjust rcNormalPosition for the zoomed frame
|
||||
AwtFrame::__SetState(this, AwtFrame::__GetState(this), factorX, factorY);
|
||||
return mrConsume;
|
||||
}
|
||||
}
|
||||
return AwtWindow::WmDPIChanged(xDPI, yDPI, bounds);
|
||||
}
|
||||
|
||||
LRESULT AwtFrame::WinThreadExecProc(ExecuteArgs * args)
|
||||
{
|
||||
switch( args->cmdId ) {
|
||||
@@ -1376,15 +1392,6 @@ void AwtFrame::_SetState(void *param)
|
||||
PDATA pData;
|
||||
JNI_CHECK_PEER_GOTO(self, ret);
|
||||
f = (AwtFrame *)pData;
|
||||
AwtFrame::__SetState(f, state);
|
||||
ret:
|
||||
env->DeleteGlobalRef(self);
|
||||
|
||||
delete sss;
|
||||
}
|
||||
|
||||
void AwtFrame::__SetState(AwtFrame* f, int state, float factorX, float factorY)
|
||||
{
|
||||
HWND hwnd = f->GetHWnd();
|
||||
if (::IsWindow(hwnd))
|
||||
{
|
||||
@@ -1408,11 +1415,6 @@ void AwtFrame::__SetState(AwtFrame* f, int state, float factorX, float factorY)
|
||||
wp.length = sizeof(wp);
|
||||
::GetWindowPlacement(hwnd, &wp);
|
||||
|
||||
wp.rcNormalPosition.left *= factorX;
|
||||
wp.rcNormalPosition.right *= factorX;
|
||||
wp.rcNormalPosition.top *= factorY;
|
||||
wp.rcNormalPosition.bottom *= factorY;
|
||||
|
||||
// Iconify first.
|
||||
// If both iconify & zoom are TRUE, handle this case
|
||||
// with wp.flags field below.
|
||||
@@ -1446,6 +1448,10 @@ void AwtFrame::__SetState(AwtFrame* f, int state, float factorX, float factorY)
|
||||
f->setZoomed(zoom);
|
||||
}
|
||||
}
|
||||
ret:
|
||||
env->DeleteGlobalRef(self);
|
||||
|
||||
delete sss;
|
||||
}
|
||||
|
||||
jint AwtFrame::_GetState(void *param)
|
||||
@@ -1454,21 +1460,12 @@ jint AwtFrame::_GetState(void *param)
|
||||
|
||||
jobject self = (jobject)param;
|
||||
|
||||
jint result = java_awt_Frame_NORMAL;
|
||||
AwtFrame *f = NULL;
|
||||
|
||||
PDATA pData;
|
||||
JNI_CHECK_PEER_GOTO(self, ret);
|
||||
f = (AwtFrame *)pData;
|
||||
jint result = AwtFrame::__GetState(f);
|
||||
ret:
|
||||
env->DeleteGlobalRef(self);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
jint AwtFrame::__GetState(AwtFrame* f)
|
||||
{
|
||||
jint result = java_awt_Frame_NORMAL;
|
||||
if (::IsWindow(f->GetHWnd()))
|
||||
{
|
||||
DASSERT(!::IsBadReadPtr(f, sizeof(AwtFrame)));
|
||||
@@ -1483,6 +1480,9 @@ jint AwtFrame::__GetState(AwtFrame* f)
|
||||
f->isIconic() ? " iconic" : "",
|
||||
f->isZoomed() ? " zoomed" : "");
|
||||
}
|
||||
ret:
|
||||
env->DeleteGlobalRef(self);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1692,7 +1692,7 @@ BOOL AwtFrame::HasCustomDecoration()
|
||||
if (!m_pHasCustomDecoration) {
|
||||
m_pHasCustomDecoration = new BOOL;
|
||||
JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
*m_pHasCustomDecoration = JNU_CallMethodByName(env, NULL, GetTarget(env), "hasCustomDecoration", "()Z").z;
|
||||
*m_pHasCustomDecoration = JNU_GetFieldByName(env, NULL, GetTarget(env), "hasCustomDecoration", "Z").z;
|
||||
}
|
||||
return *m_pHasCustomDecoration;
|
||||
}
|
||||
@@ -1734,10 +1734,8 @@ LRESULT HitTestNCA(AwtFrame* frame, int x, int y) {
|
||||
AdjustWindowRectEx(&rcFrame, WS_OVERLAPPEDWINDOW & ~WS_CAPTION, FALSE, NULL);
|
||||
|
||||
JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
int titleHeight = (int)JNU_CallMethodByName(env, NULL, frame->GetPeer(env),
|
||||
"getCustomDecorationTitleBarHeight", "()I",
|
||||
frame->ScaleDownX(x - rcWindow.left),
|
||||
frame->ScaleDownY(y - rcWindow.top)).i;
|
||||
int titleHeight = (int)JNU_GetFieldByName(env, NULL, frame->GetTarget(env),
|
||||
"customDecorTitleBarHeight", "I").i;
|
||||
if (titleHeight >= 0) {
|
||||
titleHeight = frame->ScaleUpY(titleHeight);
|
||||
insets.top = titleHeight; // otherwise leave default
|
||||
@@ -1750,12 +1748,23 @@ LRESULT HitTestNCA(AwtFrame* frame, int x, int y) {
|
||||
if (y >= rcWindow.top &&
|
||||
y < rcWindow.top + insets.top)
|
||||
{
|
||||
if (JNU_CallMethodByName(env, NULL, frame->GetPeer(env),
|
||||
"hitTestCustomDecoration", "(II)Z",
|
||||
frame->ScaleDownX(x - rcWindow.left),
|
||||
frame->ScaleDownY(y - rcWindow.top)).z)
|
||||
{
|
||||
return HTNOWHERE;
|
||||
jint customSpot = JNU_CallMethodByName(env, NULL, frame->GetTarget(env),
|
||||
"hitTestCustomDecoration", "(II)I",
|
||||
frame->ScaleDownX(x - rcWindow.left),
|
||||
frame->ScaleDownY(y - rcWindow.top)).i;
|
||||
switch (customSpot) {
|
||||
case java_awt_Window_CustomWindowDecoration_NO_HIT_SPOT:
|
||||
break; // Nothing
|
||||
case java_awt_Window_CustomWindowDecoration_MINIMIZE_BUTTON:
|
||||
return HTMINBUTTON;
|
||||
case java_awt_Window_CustomWindowDecoration_MAXIMIZE_BUTTON:
|
||||
return HTMAXBUTTON;
|
||||
case java_awt_Window_CustomWindowDecoration_CLOSE_BUTTON:
|
||||
return HTCLOSE;
|
||||
case java_awt_Window_CustomWindowDecoration_MENU_BAR:
|
||||
return HTMENU;
|
||||
default:
|
||||
return HTNOWHERE;
|
||||
}
|
||||
fOnResizeBorder = (y < (rcWindow.top - rcFrame.top));
|
||||
uRow = 0;
|
||||
|
||||
@@ -111,9 +111,9 @@ public:
|
||||
MsgRouting WmMouseMove(UINT flags, int x, int y);
|
||||
MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
|
||||
MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
|
||||
MsgRouting WmNcMouseMove(WPARAM hitTest, int x, int y);
|
||||
MsgRouting WmGetIcon(WPARAM iconType, LRESULT& retVal);
|
||||
MsgRouting WmShowWindow(BOOL show, UINT status);
|
||||
MsgRouting WmDPIChanged(UINT xDPI, UINT yDPI, RECT* bounds);
|
||||
MsgRouting WmNcCalcSize(BOOL fCalcValidRects, LPNCCALCSIZE_PARAMS lpncsp, LRESULT& retVal);
|
||||
MsgRouting WmNcHitTest(int x, int y, LRESULT& retVal);
|
||||
MsgRouting WmWindowPosChanging(LPARAM windowPos);
|
||||
@@ -141,9 +141,7 @@ public:
|
||||
|
||||
// some methods called on Toolkit thread
|
||||
static void _SetState(void *param);
|
||||
static void __SetState(AwtFrame* f, int state, float factorX = 1, float factorY = 1);
|
||||
static jint _GetState(void *param);
|
||||
static jint __GetState(AwtFrame* f);
|
||||
static void _SetMaximizedBounds(void *param);
|
||||
static void _ClearMaximizedBounds(void *param);
|
||||
static void _SetMenuBar(void *param);
|
||||
|
||||
@@ -288,14 +288,17 @@ void AwtList::SetMultiSelect(BOOL ms) {
|
||||
|
||||
UnsubclassHWND();
|
||||
AwtToolkit::DestroyComponentHWND(m_hwnd);
|
||||
CreateHWnd(env, L"", style, exStyle,
|
||||
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
||||
CreateHWnd(env, L"", style, exStyle, 0, 0, 0, 0,
|
||||
parentHWnd,
|
||||
NULL,
|
||||
::GetSysColor(COLOR_WINDOWTEXT),
|
||||
::GetSysColor(COLOR_WINDOW),
|
||||
peer);
|
||||
|
||||
SetWindowPos(GetHWnd(), 0,
|
||||
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
||||
SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOACTIVATE);
|
||||
|
||||
SendListMessage(WM_SETFONT, (WPARAM)font, (LPARAM)FALSE);
|
||||
SendListMessage(LB_SETITEMHEIGHT, 0, MAKELPARAM(itemHeight, 0));
|
||||
SendListMessage(LB_RESETCONTENT);
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
#include "awt_Util.h"
|
||||
#include "awt_Component.h"
|
||||
#include "awt_Win32GraphicsDevice.h"
|
||||
#include "awt_Win32GraphicsConfig.h"
|
||||
|
||||
AwtWin32GraphicsDevice* UGetDeviceByBounds(const URectBounds& bounds, AwtComponent* comp)
|
||||
{
|
||||
URectBounds _bounds(bounds);
|
||||
if (comp != NULL && !comp->IsTopLevel()) {
|
||||
// use the ancestor window to match the device
|
||||
_bounds = UGetWindowRectBounds(::GetAncestor(comp->GetHWnd(), GA_ROOT));
|
||||
}
|
||||
Devices::InstanceAccess devices;
|
||||
POINT center = {_bounds.x + _bounds.width / 2, _bounds.y + _bounds.height / 2};
|
||||
for (int i = 0; i < devices->GetNumDevices(); i++) {
|
||||
RECT rect = AwtWin32GraphicsConfig::getMonitorBounds(i, _bounds.space);
|
||||
if (::PtInRect(&rect, center)) {
|
||||
return devices->GetDevice(i);
|
||||
}
|
||||
}
|
||||
// default to the hwnd's device
|
||||
return comp != NULL ? devices->GetDevice(AwtWin32GraphicsDevice::DeviceIndexForWindow(comp->GetHWnd())) : NULL;
|
||||
}
|
||||
|
||||
URectBounds UGetWindowRectBounds(HWND hwnd)
|
||||
{
|
||||
RECT r;
|
||||
::GetWindowRect(hwnd, &r);
|
||||
return URectBounds(r.left, r.top, r.right - r.left, r.bottom - r.top, DEVICE_SPACE);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef NATIVE_AWT_UTIL_H
|
||||
#define NATIVE_AWT_UTIL_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef enum {
|
||||
DEVICE_SPACE,
|
||||
USER_SPACE
|
||||
} UCoordSpace;
|
||||
|
||||
typedef enum {
|
||||
RELATIVE_COORD,
|
||||
ABSOLUTE_COORD
|
||||
} UCoordRelativity;
|
||||
|
||||
#define RELATIVITY_FOR_COMP_XY(compPtr) compPtr->IsTopLevel() ? ABSOLUTE_COORD : RELATIVE_COORD
|
||||
|
||||
typedef struct URectBounds {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
UCoordSpace space;
|
||||
|
||||
URectBounds(int _x, int _y, int _w, int _h, const UCoordSpace& _space) : x(_x), y(_y), width(_w), height(_h), space(_space) {}
|
||||
|
||||
URectBounds(const URectBounds& b) : x(b.x), y(b.y), width(b.width), height(b.height), space(b.space) {}
|
||||
|
||||
URectBounds& operator=(const URectBounds& b) {
|
||||
x = b.x;
|
||||
y = b.y;
|
||||
width = b.width;
|
||||
height = b.height;
|
||||
space = b.space;
|
||||
return *this;
|
||||
}
|
||||
} URectBounds;
|
||||
|
||||
class AwtComponent;
|
||||
class AwtWin32GraphicsDevice;
|
||||
|
||||
URectBounds UGetWindowRectBounds(HWND hwnd);
|
||||
AwtWin32GraphicsDevice* UGetDeviceByBounds(const URectBounds& bounds, AwtComponent* comp = NULL);
|
||||
|
||||
#endif //NATIVE_AWT_UTIL_H
|
||||
@@ -77,36 +77,6 @@ inline int shiftToMask(int numBits, int shift) {
|
||||
return mask;
|
||||
}
|
||||
|
||||
RECT AwtWin32GraphicsConfig::getMonitorBounds(int screen, const UCoordSpace& space)
|
||||
{
|
||||
RECT rRW = {0, 0, 0, 0};
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
|
||||
|
||||
if (TRUE == MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW)) {
|
||||
int x = (device == NULL || space == DEVICE_SPACE) ? rRW.left
|
||||
: device->ScaleDownX(rRW.left);
|
||||
int y = (device == NULL || space == DEVICE_SPACE) ? rRW.top
|
||||
: device->ScaleDownY(rRW.top);
|
||||
int w = (device == NULL || space == DEVICE_SPACE) ? rRW.right - rRW.left
|
||||
: device->ScaleDownX(rRW.right - rRW.left);
|
||||
int h = (device == NULL || space == DEVICE_SPACE) ? rRW.bottom - rRW.top
|
||||
: device->ScaleDownY(rRW.bottom - rRW.top);
|
||||
|
||||
::SetRect(&rRW, x, y, x + w, y + h);
|
||||
}
|
||||
else {
|
||||
// 4910760 - don't return a null bounds, return the bounds of the
|
||||
// primary screen
|
||||
int w = ::GetSystemMetrics(SM_CXSCREEN);
|
||||
int h = ::GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
::SetRect(&rRW, 0, 0, device == NULL || space == DEVICE_SPACE ? w : device->ScaleDownX(w),
|
||||
device == NULL || space == DEVICE_SPACE ? h : device->ScaleDownY(h));
|
||||
}
|
||||
return rRW;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_Win32GraphicsConfig
|
||||
* Method: getBounds
|
||||
@@ -124,8 +94,30 @@ JNIEXPORT jobject JNICALL
|
||||
CHECK_NULL_RETURN(clazz, NULL);
|
||||
mid = env->GetMethodID(clazz, "<init>", "(IIII)V");
|
||||
if (mid != 0) {
|
||||
RECT r = AwtWin32GraphicsConfig::getMonitorBounds((int)screen, USER_SPACE);
|
||||
bounds = env->NewObject(clazz, mid, r.left, r.top, r.right - r.left, r.bottom - r.top);
|
||||
RECT rRW = {0, 0, 0, 0};
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
|
||||
|
||||
if (TRUE == MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW)) {
|
||||
int w = (device == NULL) ? rRW.right - rRW.left
|
||||
: device->ScaleDownX(rRW.right - rRW.left);
|
||||
int h = (device == NULL) ? rRW.bottom - rRW.top
|
||||
: device->ScaleDownY(rRW.bottom - rRW.top);
|
||||
|
||||
bounds = env->NewObject(clazz, mid, rRW.left, rRW.top, w, h);
|
||||
|
||||
}
|
||||
else {
|
||||
// 4910760 - don't return a null bounds, return the bounds of the
|
||||
// primary screen
|
||||
int w = ::GetSystemMetrics(SM_CXSCREEN);
|
||||
int h = ::GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
bounds = env->NewObject(clazz, mid,
|
||||
0, 0,
|
||||
device == NULL ? w : device->ScaleDownX(w),
|
||||
device == NULL ? h : device->ScaleDownY(h));
|
||||
}
|
||||
if (safe_ExceptionOccurred(env)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ class AwtWin32GraphicsConfig {
|
||||
public:
|
||||
/* sun.awt.Win32GraphicsConfig fields and method IDs */
|
||||
static jfieldID win32GCVisualID;
|
||||
static RECT getMonitorBounds(int screen, const UCoordSpace& space);
|
||||
};
|
||||
|
||||
#endif /* AWT_WIN32GRAPHICSCONFIG_H */
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <sun_awt_Win32GraphicsDevice.h>
|
||||
#include "awt_Canvas.h"
|
||||
#include "awt_Win32GraphicsDevice.h"
|
||||
#include "awt_Win32GraphicsConfig.h"
|
||||
#include "awt_Window.h"
|
||||
#include "java_awt_Transparency.h"
|
||||
#include "java_awt_color_ColorSpace.h"
|
||||
@@ -78,6 +77,7 @@ AwtWin32GraphicsDevice::AwtWin32GraphicsDevice(int screen,
|
||||
this->devicesArray = arr;
|
||||
this->scaleX = 1;
|
||||
this->scaleY = 1;
|
||||
disableScaleAutoRefresh = FALSE;
|
||||
javaDevice = NULL;
|
||||
colorData = new ImgColorData;
|
||||
colorData->grayscale = GS_NOTGRAY;
|
||||
@@ -629,47 +629,51 @@ void AwtWin32GraphicsDevice::SetScale(float sx, float sy)
|
||||
scaleY = sy;
|
||||
}
|
||||
|
||||
int AwtWin32GraphicsDevice::ScaleUpX(int x, const UCoordRelativity& relativity)
|
||||
int AwtWin32GraphicsDevice::ScaleUpX(int x)
|
||||
{
|
||||
return relativity == RELATIVE_COORD ? ClipRound(x * scaleX) : ScaleUpDX(x);
|
||||
return ClipRound(x * scaleX);
|
||||
}
|
||||
|
||||
// scale up the delta [x - device.x]
|
||||
int AwtWin32GraphicsDevice::ScaleUpDX(int x)
|
||||
int AwtWin32GraphicsDevice::ScaleUpAbsX(int x)
|
||||
{
|
||||
RECT devBounds = AwtWin32GraphicsConfig::getMonitorBounds(screen, DEVICE_SPACE);
|
||||
return devBounds.left + ClipRound((x - devBounds.left) * scaleX);
|
||||
LONG screen = pMonitorInfo->rcMonitor.left;
|
||||
return screen + ClipRound((x - screen) * scaleX);
|
||||
}
|
||||
|
||||
int AwtWin32GraphicsDevice::ScaleUpY(int y, const UCoordRelativity& relativity)
|
||||
int AwtWin32GraphicsDevice::ScaleUpY(int y)
|
||||
{
|
||||
return relativity == RELATIVE_COORD ? ClipRound(y * scaleY) : ScaleUpDY(y);
|
||||
return ClipRound(y * scaleY);
|
||||
}
|
||||
|
||||
// scale up the delta [y - device.y]
|
||||
int AwtWin32GraphicsDevice::ScaleUpDY(int y)
|
||||
int AwtWin32GraphicsDevice::ScaleUpAbsY(int y)
|
||||
{
|
||||
RECT devBounds = AwtWin32GraphicsConfig::getMonitorBounds(screen, DEVICE_SPACE);
|
||||
return devBounds.top + ClipRound((y - devBounds.top) * scaleY);
|
||||
LONG screen = pMonitorInfo->rcMonitor.top;
|
||||
return screen + ClipRound((y - screen) * scaleY);
|
||||
}
|
||||
|
||||
int AwtWin32GraphicsDevice::ScaleDownX(int x, const UCoordRelativity& relativity)
|
||||
int AwtWin32GraphicsDevice::ScaleDownX(int x)
|
||||
{
|
||||
return relativity == RELATIVE_COORD ? ClipRound(x / scaleX) : ScaleDownDX(x);
|
||||
return ClipRound(x / scaleX);
|
||||
}
|
||||
|
||||
// scale down the delta [x - device.x]
|
||||
int AwtWin32GraphicsDevice::ScaleDownDX(int x)
|
||||
int AwtWin32GraphicsDevice::ScaleDownAbsX(int x)
|
||||
{
|
||||
RECT devBounds = AwtWin32GraphicsConfig::getMonitorBounds(screen, USER_SPACE);
|
||||
return devBounds.left + ClipRound((x - devBounds.left) / scaleX);
|
||||
LONG screen = pMonitorInfo->rcMonitor.left;
|
||||
return screen + ClipRound((x - screen) / scaleX);
|
||||
}
|
||||
|
||||
int AwtWin32GraphicsDevice::ScaleDownY(int y, const UCoordRelativity& relativity)
|
||||
int AwtWin32GraphicsDevice::ScaleDownY(int y)
|
||||
{
|
||||
return relativity == RELATIVE_COORD ? ClipRound(y / scaleY) : ScaleDownDY(y);
|
||||
return ClipRound(y / scaleY);
|
||||
}
|
||||
|
||||
int AwtWin32GraphicsDevice::ScaleDownAbsY(int y)
|
||||
{
|
||||
LONG screen = pMonitorInfo->rcMonitor.top;
|
||||
return screen + ClipRound((y - screen) / scaleY);
|
||||
}
|
||||
|
||||
|
||||
int AwtWin32GraphicsDevice::ClipRound(double value)
|
||||
{
|
||||
value -= 0.5;
|
||||
@@ -686,13 +690,6 @@ int AwtWin32GraphicsDevice::ClipRound(double value)
|
||||
return (int)ceil(value);
|
||||
}
|
||||
|
||||
// scale down the delta [y - device.y]
|
||||
int AwtWin32GraphicsDevice::ScaleDownDY(int y)
|
||||
{
|
||||
RECT devBounds = AwtWin32GraphicsConfig::getMonitorBounds(screen, USER_SPACE);
|
||||
return devBounds.top + ClipRound((y - devBounds.top) / scaleY);
|
||||
}
|
||||
|
||||
// scale down the delta [pt.xy - device.xy]
|
||||
void AwtWin32GraphicsDevice::ScaleDownDPoint(POINT *pt)
|
||||
{
|
||||
@@ -709,11 +706,13 @@ void AwtWin32GraphicsDevice::ScaleDownDPoint(POINT *pt)
|
||||
|
||||
void AwtWin32GraphicsDevice::InitDesktopScales()
|
||||
{
|
||||
float dpiX = -1.0f;
|
||||
float dpiY = -1.0f;
|
||||
GetScreenDpi(GetMonitor(), &dpiX, &dpiY);
|
||||
if (dpiX > 0 && dpiY > 0) {
|
||||
SetScale(dpiX / 96, dpiY / 96);
|
||||
if (!disableScaleAutoRefresh) {
|
||||
float dpiX = -1.0f;
|
||||
float dpiY = -1.0f;
|
||||
GetScreenDpi(GetMonitor(), &dpiX, &dpiY);
|
||||
if (dpiX > 0 && dpiY > 0) {
|
||||
SetScale(dpiX / 96, dpiY / 96);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,6 +736,12 @@ void AwtWin32GraphicsDevice::DisableOffscreenAcceleration()
|
||||
// REMIND: noop for now
|
||||
}
|
||||
|
||||
void AwtWin32GraphicsDevice::DisableScaleAutoRefresh()
|
||||
{
|
||||
disableScaleAutoRefresh = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invalidates the GraphicsDevice object associated with this
|
||||
* device by disabling offscreen acceleration and calling
|
||||
@@ -797,6 +802,22 @@ void AwtWin32GraphicsDevice::ResetAllMonitorInfo()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function updates the scale factor for all monitors on the system.
|
||||
*/
|
||||
void AwtWin32GraphicsDevice::ResetAllDesktopScales()
|
||||
{
|
||||
if (!Devices::GetInstance()){
|
||||
return;
|
||||
}
|
||||
Devices::InstanceAccess devices;
|
||||
int devicesNum = devices->GetNumDevices();
|
||||
for (int deviceIndex = 0; deviceIndex < devicesNum; deviceIndex++) {
|
||||
devices->GetDevice(deviceIndex)->InitDesktopScales();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AwtWin32GraphicsDevice::DisableOffscreenAccelerationForDevice(
|
||||
HMONITOR hMonitor)
|
||||
{
|
||||
@@ -1444,6 +1465,7 @@ JNIEXPORT void JNICALL
|
||||
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
|
||||
|
||||
if (device != NULL ) {
|
||||
device->DisableScaleAutoRefresh();
|
||||
device->SetScale(scaleX, scaleY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ extern "C" {
|
||||
#include "colordata.h"
|
||||
#include "awt_Palette.h"
|
||||
#include "Devices.h"
|
||||
#include "awt_Util.h"
|
||||
|
||||
class AwtPalette;
|
||||
class Devices;
|
||||
@@ -66,19 +65,20 @@ public:
|
||||
int GetDeviceIndex() { return screen; }
|
||||
void Release();
|
||||
void DisableOffscreenAcceleration();
|
||||
void DisableScaleAutoRefresh();
|
||||
void Invalidate(JNIEnv *env);
|
||||
void InitDesktopScales();
|
||||
void SetScale(float scaleX, float scaleY);
|
||||
float GetScaleX();
|
||||
float GetScaleY();
|
||||
int ScaleUpX(int x, const UCoordRelativity& relativity = RELATIVE_COORD);
|
||||
int ScaleUpY(int y, const UCoordRelativity& relativity = RELATIVE_COORD);
|
||||
int ScaleDownX(int x, const UCoordRelativity& relativity = RELATIVE_COORD);
|
||||
int ScaleDownY(int y, const UCoordRelativity& relativity = RELATIVE_COORD);
|
||||
int ScaleUpDX(int x);
|
||||
int ScaleUpDY(int y);
|
||||
int ScaleDownDX(int x);
|
||||
int ScaleDownDY(int y);
|
||||
int ScaleUpX(int x);
|
||||
int ScaleUpAbsX(int x);
|
||||
int ScaleUpY(int y);
|
||||
int ScaleUpAbsY(int y);
|
||||
int ScaleDownX(int x);
|
||||
int ScaleDownAbsX(int x);
|
||||
int ScaleDownY(int y);
|
||||
int ScaleDownAbsY(int y);
|
||||
|
||||
static void ScaleDownDPoint(POINT *pt);
|
||||
static int DeviceIndexForWindow(HWND hWnd);
|
||||
@@ -94,6 +94,7 @@ public:
|
||||
static HMONITOR GetMonitor(int deviceIndex);
|
||||
static LPMONITORINFO GetMonitorInfo(int deviceIndex);
|
||||
static void ResetAllMonitorInfo();
|
||||
static void ResetAllDesktopScales();
|
||||
static BOOL IsPrimaryPalettized() { return primaryPalettized; }
|
||||
static int GetDefaultDeviceIndex() { return primaryIndex; }
|
||||
static void DisableOffscreenAccelerationForDevice(HMONITOR hMonitor);
|
||||
@@ -124,6 +125,7 @@ private:
|
||||
Devices *devicesArray;
|
||||
float scaleX;
|
||||
float scaleY;
|
||||
BOOL disableScaleAutoRefresh;
|
||||
|
||||
static HDC MakeDCFromMonitor(HMONITOR);
|
||||
static int ClipRound(double value);
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include "awt_IconCursor.h"
|
||||
#include "ComCtl32Util.h"
|
||||
#include "math.h"
|
||||
#include "awt_Util.h"
|
||||
|
||||
#include "java_awt_Insets.h"
|
||||
#include <java_awt_Container.h>
|
||||
@@ -155,17 +154,6 @@ struct SetFullScreenExclusiveModeStateStruct {
|
||||
jboolean isFSEMState;
|
||||
};
|
||||
|
||||
/* // struct for _WindowDPIChange() method
|
||||
struct ScaleStruct {
|
||||
jobject window;
|
||||
jint prevScreen;
|
||||
jfloat prevScaleX;
|
||||
jfloat prevScaleY;
|
||||
jint screen;
|
||||
jfloat scaleX;
|
||||
jfloat scaleY;
|
||||
}; */
|
||||
|
||||
struct OverrideHandle {
|
||||
jobject frame;
|
||||
HWND handle;
|
||||
@@ -181,10 +169,6 @@ jfieldID AwtWindow::autoRequestFocusID;
|
||||
jfieldID AwtWindow::securityWarningWidthID;
|
||||
jfieldID AwtWindow::securityWarningHeightID;
|
||||
|
||||
jfieldID AwtWindow::sysXID;
|
||||
jfieldID AwtWindow::sysYID;
|
||||
jfieldID AwtWindow::sysWID;
|
||||
jfieldID AwtWindow::sysHID;
|
||||
jfieldID AwtWindow::windowTypeID;
|
||||
jfieldID AwtWindow::sysInsetsID;
|
||||
jmethodID AwtWindow::notifyWindowStateChangedMID;
|
||||
@@ -248,13 +232,11 @@ AwtWindow::AwtWindow() {
|
||||
m_alwaysOnTop = false;
|
||||
|
||||
fullScreenExclusiveModeState = FALSE;
|
||||
/*m_winSizeMove = FALSE;
|
||||
m_winSizeMove = FALSE;
|
||||
prevScaleRec.screen = -1;
|
||||
prevScaleRec.scaleX = -1.0f;
|
||||
prevScaleRec.scaleY = -1.0f;*/
|
||||
prevScaleRec.scaleY = -1.0f;
|
||||
m_overriddenHwnd = NULL;
|
||||
|
||||
::SetRect(&m_boundsOnDPIChange, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
AwtWindow::~AwtWindow()
|
||||
@@ -983,51 +965,6 @@ MsgRouting AwtWindow::WmTimer(UINT_PTR timerID)
|
||||
return mrConsume;
|
||||
}
|
||||
|
||||
MsgRouting AwtWindow::WmDPIChanged(UINT xDPI, UINT yDPI, RECT* bounds) {
|
||||
if (!::IsWindowVisible(GetHWnd())) {
|
||||
// may diverge with Component::Reshape in this state
|
||||
return mrDoDefault;
|
||||
}
|
||||
if (IsInMoveResizeLoop()) {
|
||||
// Dragged with mouse to new screen. In this case the new bounds must be set immediately
|
||||
// or otherwise OS will reset it back to the previous values.
|
||||
::SetWindowPos(GetHWnd(), NULL,
|
||||
bounds->left, bounds->top,
|
||||
bounds->right - bounds->left, bounds->bottom - bounds->top,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
} else {
|
||||
// Either DPI of this screen changed, or the window moved to a new screen by a shortcut (shift+meta+arrow).
|
||||
// Store the new bounds for async update.
|
||||
::CopyRect(&m_boundsOnDPIChange, bounds);
|
||||
}
|
||||
return mrConsume;
|
||||
}
|
||||
|
||||
void AwtWindow::_AdjustBoundsOnDPIChange(void* param)
|
||||
{
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
|
||||
jobject jwnd = (jobject)param;
|
||||
PDATA pData;
|
||||
JNI_CHECK_PEER_GOTO(jwnd, done);
|
||||
AwtWindow *window = (AwtWindow *)pData;
|
||||
|
||||
int x = window->m_boundsOnDPIChange.left;
|
||||
int y = window->m_boundsOnDPIChange.top;
|
||||
int width = window->m_boundsOnDPIChange.right - window->m_boundsOnDPIChange.left;
|
||||
int height = window->m_boundsOnDPIChange.bottom - window->m_boundsOnDPIChange.top;
|
||||
|
||||
if (width > 0 && height > 0) {
|
||||
::SetRect(&window->m_boundsOnDPIChange, 0, 0, 0, 0); // drop it
|
||||
|
||||
::SetWindowPos(window->GetHWnd(), NULL,
|
||||
x, y, width, height,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
done:
|
||||
env->DeleteGlobalRef(jwnd);
|
||||
}
|
||||
|
||||
// The security warning is visible if:
|
||||
// 1. The window has the keyboard window focus, OR
|
||||
// 2. The mouse pointer is located within the window bounds,
|
||||
@@ -1197,20 +1134,20 @@ AwtWindow* AwtWindow::Create(jobject self, jobject parent)
|
||||
// specify WS_EX_TOOLWINDOW to remove parentless windows from taskbar
|
||||
exStyle |= WS_EX_TOOLWINDOW;
|
||||
}
|
||||
jint x = env->GetIntField(target, AwtComponent::xID);
|
||||
jint y = env->GetIntField(target, AwtComponent::yID);
|
||||
jint width = env->GetIntField(target, AwtComponent::widthID);
|
||||
jint height = env->GetIntField(target, AwtComponent::heightID);
|
||||
|
||||
window->CreateHWnd(env, L"",
|
||||
style, exStyle,
|
||||
0, 0, 0, 0,
|
||||
x, y, width, height,
|
||||
(awtParent != NULL) ? awtParent->GetHWnd() : NULL,
|
||||
NULL,
|
||||
::GetSysColor(COLOR_WINDOWTEXT),
|
||||
::GetSysColor(COLOR_WINDOW),
|
||||
self);
|
||||
|
||||
jint x = env->GetIntField(target, AwtComponent::xID);
|
||||
jint y = env->GetIntField(target, AwtComponent::yID);
|
||||
jint width = env->GetIntField(target, AwtComponent::widthID);
|
||||
jint height = env->GetIntField(target, AwtComponent::heightID);
|
||||
|
||||
/*
|
||||
* Initialize icon as inherited from parent if it exists
|
||||
*/
|
||||
@@ -1220,13 +1157,7 @@ AwtWindow* AwtWindow::Create(jobject self, jobject parent)
|
||||
window->m_iconInherited = TRUE;
|
||||
}
|
||||
window->DoUpdateIcon();
|
||||
|
||||
|
||||
/*
|
||||
* Reshape here instead of during create, so that a WM_NCCALCSIZE
|
||||
* is sent.
|
||||
*/
|
||||
window->Reshape(x, y, width, height);
|
||||
window->RecalcNonClient();
|
||||
}
|
||||
} catch (...) {
|
||||
env->DeleteLocalRef(target);
|
||||
@@ -1284,6 +1215,48 @@ void AwtWindow::moveToDefaultLocation() {
|
||||
VERIFY(::SetWindowPos(GetHWnd(), NULL, defLoc.left, defLoc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Override AwtComponent::Reshape() to handle absolute screen coordinates used
|
||||
* by the top-level windows.
|
||||
*/
|
||||
void AwtWindow::Reshape(int x, int y, int w, int h) {
|
||||
if (IsEmbeddedFrame()) {
|
||||
// Not the "real" top level window
|
||||
return AwtComponent::Reshape(x, y, w, h);
|
||||
}
|
||||
// Yes, use x,y in user's space to find the nearest monitor in device space.
|
||||
POINT pt = {x + w / 2, y + h / 2};
|
||||
Devices::InstanceAccess devices;
|
||||
HMONITOR monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
|
||||
int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
|
||||
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
|
||||
// Try to set the correct size and jump to the correct location, even if it is
|
||||
// on the different monitor. Note that for the "size" we use the current
|
||||
// monitor, so the WM_DPICHANGED will adjust it for the "target" monitor.
|
||||
int scaleUpAbsX = device == NULL ? x : device->ScaleUpAbsX(x);
|
||||
int scaleUpAbsY = device == NULL ? y : device->ScaleUpAbsY(y);
|
||||
ReshapeNoScale(scaleUpAbsX, scaleUpAbsY, ScaleUpX(w), ScaleUpY(h));
|
||||
// The window manager may tweak the size for different reasons, so try
|
||||
// to make sure our window has the correct size in the user's space.
|
||||
// NOOP if the size was changed already or changing is in progress.
|
||||
RECT rc;
|
||||
::GetWindowRect(GetHWnd(), &rc);
|
||||
ReshapeNoScale(rc.left, rc.top, ScaleUpX(w), ScaleUpY(h));
|
||||
// the window manager may ignore our "SetWindowPos" request, in this,
|
||||
// case the WmMove/WmSize will not come and we need to manually resync
|
||||
// the "java.awt.Window" locations, because "java.awt.Window" already
|
||||
// uses location ignored by the window manager.
|
||||
::GetWindowRect(GetHWnd(), &rc);
|
||||
if (x != ScaleDownAbsX(rc.left) || y != ScaleDownAbsY(rc.top)) {
|
||||
WmMove(rc.left, rc.top);
|
||||
}
|
||||
int userW = ScaleDownX(rc.right - rc.left);
|
||||
int userH = ScaleDownY(rc.bottom - rc.top);
|
||||
if (w != userW || h != userH) {
|
||||
WmSize(SIZENORMAL, rc.right - rc.left, rc.bottom - rc.top);
|
||||
}
|
||||
}
|
||||
|
||||
void AwtWindow::Show()
|
||||
{
|
||||
m_visible = true;
|
||||
@@ -1870,6 +1843,16 @@ MsgRouting AwtWindow::WmShowWindow(BOOL show, UINT status)
|
||||
return AwtCanvas::WmShowWindow(show, status);
|
||||
}
|
||||
|
||||
void AwtWindow::WmDPIChanged(const LPARAM &lParam) {
|
||||
// need to update the scales now, otherwise the ReshapeNoScale() will
|
||||
// calculate the bounds wrongly
|
||||
AwtWin32GraphicsDevice::ResetAllDesktopScales();
|
||||
RECT *r = (RECT *) lParam;
|
||||
ReshapeNoScale(r->left, r->top, r->right - r->left, r->bottom - r->top);
|
||||
CheckIfOnNewScreen(true);
|
||||
}
|
||||
|
||||
|
||||
MsgRouting AwtWindow::WmEraseBkgnd(HDC hDC, BOOL& didErase)
|
||||
{
|
||||
if (!IsUndecorated()) {
|
||||
@@ -1900,61 +1883,21 @@ MsgRouting AwtWindow::WmMove(int x, int y)
|
||||
return mrDoDefault;
|
||||
}
|
||||
|
||||
if (m_screenNum == -1) {
|
||||
// Set initial value
|
||||
m_screenNum = GetScreenImOn();
|
||||
}
|
||||
else if (CheckIfOnNewScreen()) {
|
||||
DoUpdateIcon();
|
||||
}
|
||||
// Check for the new screen and update the java peer
|
||||
CheckIfOnNewScreen(false); // postpone if different DPI
|
||||
|
||||
/* Update the java AWT target component's fields directly */
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
if (env->EnsureLocalCapacity(1) < 0) {
|
||||
return mrConsume;
|
||||
}
|
||||
jobject peer = GetPeer(env);
|
||||
jobject target = env->GetObjectField(peer, AwtObject::targetID);
|
||||
jobject target = GetTarget(env);
|
||||
|
||||
URectBounds rect = UGetWindowRectBounds(GetHWnd());
|
||||
AwtWin32GraphicsDevice* device = UGetDeviceByBounds(rect, this);
|
||||
RECT rect;
|
||||
::GetWindowRect(GetHWnd(), &rect);
|
||||
|
||||
int usrX = device->ScaleDownX(rect.x);
|
||||
int usrY = device->ScaleDownY(rect.y);
|
||||
|
||||
// [tav] Convert x/y to user space, asymmetrically to AwtComponent::Reshape.
|
||||
AwtComponent* parent = GetParent();
|
||||
if (parent != NULL && (device->GetScaleX() > 1 || device->GetScaleY() > 1)) {
|
||||
|
||||
RECT parentInsets;
|
||||
parent->GetInsets(&parentInsets);
|
||||
// Convert the owner's client area origin to user space
|
||||
int parentInsetsUsrX = device->ScaleDownX(parentInsets.left);
|
||||
int parentInsetsUsrY = device->ScaleDownY(parentInsets.top);
|
||||
|
||||
RECT parentRect;
|
||||
VERIFY(::GetWindowRect(parent->GetHWnd(), &parentRect));
|
||||
// Convert the owner's origin to user space
|
||||
int parentUsrX = device->ScaleDownX(parentRect.left);
|
||||
int parentUsrY = device->ScaleDownY(parentRect.top);
|
||||
|
||||
// Calc the offset from the owner's client area in device space
|
||||
int offsetDevX = rect.x - parentRect.left - parentInsets.left;
|
||||
int offsetDevY = rect.y - parentRect.top - parentInsets.top;
|
||||
|
||||
// Convert the offset to user space
|
||||
int offsetUsrX = device->ScaleDownX(offsetDevX);
|
||||
int offsetUsrY = device->ScaleDownY(offsetDevY);
|
||||
|
||||
// Finally calc the window's location based on the frame's and its insets user space values.
|
||||
usrX = parentUsrX + parentInsetsUsrX + offsetUsrX;
|
||||
usrY = parentUsrY + parentInsetsUsrY + offsetUsrY;
|
||||
}
|
||||
|
||||
(env)->SetIntField(target, AwtComponent::xID, usrX);
|
||||
(env)->SetIntField(target, AwtComponent::yID, usrY);
|
||||
(env)->SetIntField(peer, AwtWindow::sysXID, rect.x);
|
||||
(env)->SetIntField(peer, AwtWindow::sysYID, rect.y);
|
||||
(env)->SetIntField(target, AwtComponent::xID, ScaleDownAbsX(rect.left));
|
||||
(env)->SetIntField(target, AwtComponent::yID, ScaleDownAbsY(rect.top));
|
||||
SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED);
|
||||
|
||||
env->DeleteLocalRef(target);
|
||||
@@ -1996,18 +1939,27 @@ MsgRouting AwtWindow::WmSizing()
|
||||
return mrDoDefault;
|
||||
}
|
||||
|
||||
/*MsgRouting AwtWindow::WmEnterSizeMove()
|
||||
MsgRouting AwtWindow::WmEnterSizeMove()
|
||||
{
|
||||
m_winSizeMove = TRUE;
|
||||
// Below is a workaround, see CheckWindowDPIChange
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(m_screenNum);
|
||||
if (device) {
|
||||
prevScaleRec.screen = m_screenNum;
|
||||
prevScaleRec.scaleX = device->GetScaleX();
|
||||
prevScaleRec.scaleY = device->GetScaleY();
|
||||
}
|
||||
// Above is a workaround
|
||||
return mrDoDefault;
|
||||
}
|
||||
|
||||
MsgRouting AwtWindow::WmExitSizeMove()
|
||||
{
|
||||
m_winSizeMove = FALSE;
|
||||
CheckWindowDPIChange();
|
||||
CheckWindowDPIChange(); // workaround
|
||||
return mrDoDefault;
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Override AwtComponent's size handling to first update the
|
||||
@@ -2022,6 +1974,8 @@ MsgRouting AwtWindow::WmSize(UINT type, int w, int h)
|
||||
UpdateSecurityWarningVisibility();
|
||||
return mrDoDefault;
|
||||
}
|
||||
// Check for the new screen and update the java peer
|
||||
CheckIfOnNewScreen(false); // postpone if different DPI
|
||||
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
if (env->EnsureLocalCapacity(1) < 0)
|
||||
@@ -2029,16 +1983,8 @@ MsgRouting AwtWindow::WmSize(UINT type, int w, int h)
|
||||
jobject target = GetTarget(env);
|
||||
// fix 4167248 : ensure the insets are up-to-date before using
|
||||
BOOL insetsChanged = UpdateInsets(NULL);
|
||||
int newWidth = w + m_insets.left + m_insets.right;
|
||||
int newHeight = h + m_insets.top + m_insets.bottom;
|
||||
URectBounds rect = UGetWindowRectBounds(GetHWnd());
|
||||
AwtWin32GraphicsDevice* device = UGetDeviceByBounds(rect, this);
|
||||
(env)->SetIntField(target, AwtComponent::widthID, device->ScaleDownX(newWidth));
|
||||
(env)->SetIntField(target, AwtComponent::heightID, device->ScaleDownY(newHeight));
|
||||
|
||||
jobject peer = GetPeer(env);
|
||||
(env)->SetIntField(peer, AwtWindow::sysWID, newWidth);
|
||||
(env)->SetIntField(peer, AwtWindow::sysHID, newHeight);
|
||||
(env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(w));
|
||||
(env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(h));
|
||||
|
||||
if (!AwtWindow::IsResizing()) {
|
||||
WindowResized();
|
||||
@@ -2120,6 +2066,11 @@ LRESULT AwtWindow::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
LRESULT retValue = 0L;
|
||||
|
||||
switch(message) {
|
||||
case WM_DPICHANGED: {
|
||||
WmDPIChanged(lParam);
|
||||
mr = mrConsume;
|
||||
break;
|
||||
}
|
||||
case WM_GETICON:
|
||||
mr = WmGetIcon(wParam, retValue);
|
||||
break;
|
||||
@@ -2272,98 +2223,81 @@ int AwtWindow::GetScreenImOn() {
|
||||
return scrnNum;
|
||||
}
|
||||
|
||||
/* Check to see if we've been moved onto another screen.
|
||||
/*
|
||||
* Check to see if we've been moved onto another screen.
|
||||
* If so, update internal data, surfaces, etc.
|
||||
*/
|
||||
|
||||
BOOL AwtWindow::CheckIfOnNewScreen() {
|
||||
void AwtWindow::CheckIfOnNewScreen(BOOL force) {
|
||||
int curScrn = GetScreenImOn();
|
||||
|
||||
if (curScrn != m_screenNum) { // we've been moved
|
||||
// if moved from one monitor to another with different DPI, we should
|
||||
// update the m_screenNum only if the size was updated as well in the
|
||||
// WM_DPICHANGED.
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* oldDevice = devices->GetDevice(m_screenNum);
|
||||
AwtWin32GraphicsDevice* newDevice = devices->GetDevice(curScrn);
|
||||
if (!force && m_winSizeMove && oldDevice && newDevice) {
|
||||
if (oldDevice->GetScaleX() != newDevice->GetScaleX()
|
||||
|| oldDevice->GetScaleY() != newDevice->GetScaleY()) {
|
||||
// scales are different, wait for WM_DPICHANGED
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
|
||||
jclass peerCls = env->GetObjectClass(m_peerObject);
|
||||
DASSERT(peerCls);
|
||||
CHECK_NULL_RETURN(peerCls, TRUE);
|
||||
CHECK_NULL(peerCls);
|
||||
|
||||
jmethodID draggedID = env->GetMethodID(peerCls, "draggedToNewScreen",
|
||||
"()V");
|
||||
DASSERT(draggedID);
|
||||
if (draggedID == NULL) {
|
||||
env->DeleteLocalRef(peerCls);
|
||||
return TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
env->CallVoidMethod(m_peerObject, draggedID);
|
||||
m_screenNum = curScrn;
|
||||
|
||||
env->DeleteLocalRef(peerCls);
|
||||
return TRUE;
|
||||
|
||||
DoUpdateIcon();
|
||||
}
|
||||
return FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* void AwtWindow::CheckWindowDPIChange() {
|
||||
|
||||
if (prevScaleRec.screen != -1 ) {
|
||||
float prevScaleX = prevScaleRec.scaleX;
|
||||
float prevScaleY = prevScaleRec.scaleY;
|
||||
|
||||
if (prevScaleX >= 1 && prevScaleY >= 1) {
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(m_screenNum);
|
||||
if (device) {
|
||||
float scaleX = device->GetScaleX();
|
||||
float scaleY = device->GetScaleY();
|
||||
if (prevScaleX != scaleX || prevScaleY != scaleY) {
|
||||
WindowDPIChange(prevScaleRec.screen, prevScaleX, prevScaleY,
|
||||
m_screenNum, scaleX, scaleY);
|
||||
void AwtWindow::CheckWindowDPIChange() {
|
||||
if (prevScaleRec.screen != -1 && prevScaleRec.screen != m_screenNum) {
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice *device = devices->GetDevice(m_screenNum);
|
||||
if (device) {
|
||||
if (prevScaleRec.scaleX != device->GetScaleX()
|
||||
|| prevScaleRec.scaleY != device->GetScaleY()) {
|
||||
RECT rect;
|
||||
::GetWindowRect(GetHWnd(), &rect);
|
||||
int x = rect.left;
|
||||
int y = rect.top;
|
||||
int w = rect.right - rect.left;
|
||||
int h = rect.bottom - rect.top;
|
||||
RECT bounds;
|
||||
if (MonitorBounds(device->GetMonitor(), &bounds)) {
|
||||
x = x < bounds.left ? bounds.left : x;
|
||||
y = y < bounds.top ? bounds.top : y;
|
||||
x = (x + w > bounds.right) ? bounds.right - w : x;
|
||||
y = (y + h > bounds.bottom) ? bounds.bottom - h : y;
|
||||
}
|
||||
ReshapeNoScale(x, y, w, h);
|
||||
}
|
||||
}
|
||||
prevScaleRec.screen = -1;
|
||||
prevScaleRec.scaleX = -1.0f;
|
||||
prevScaleRec.scaleY = -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void AwtWindow::WindowDPIChange(int prevScreen,
|
||||
float prevScaleX, float prevScaleY,
|
||||
int screen, float scaleX,
|
||||
float scaleY)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
RECT rect;
|
||||
|
||||
if (prevScaleX == scaleX && prevScaleY == scaleY) {
|
||||
return;
|
||||
}
|
||||
|
||||
::GetWindowRect(GetHWnd(), &rect);
|
||||
x = rect.left;
|
||||
y = rect.top;
|
||||
w = (rect.right - rect.left) * scaleX / prevScaleX;
|
||||
h = (rect.bottom - rect.top) * scaleY / prevScaleY;
|
||||
|
||||
if (prevScreen != screen) {
|
||||
Devices::InstanceAccess devices;
|
||||
AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
|
||||
if (device) {
|
||||
RECT bounds;
|
||||
if (MonitorBounds(device->GetMonitor(), &bounds)) {
|
||||
x = x < bounds.left ? bounds.left : x;
|
||||
y = y < bounds.top ? bounds.top : y;
|
||||
|
||||
x = (x + w > bounds.right) ? bounds.right - w : x;
|
||||
y = (y + h > bounds.bottom) ? bounds.bottom - h : y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReshapeNoScale(x, y, w, h);
|
||||
} */
|
||||
|
||||
BOOL AwtWindow::IsFocusableWindow() {
|
||||
/*
|
||||
* For Window/Frame/Dialog to accept focus it should:
|
||||
@@ -2750,15 +2684,11 @@ void AwtWindow::_ReshapeFrame(void *param)
|
||||
{
|
||||
env->SetIntField(target, AwtComponent::widthID,
|
||||
w = minWidth);
|
||||
env->SetIntField(peer, AwtWindow::sysWID,
|
||||
w);
|
||||
}
|
||||
if (h < minHeight)
|
||||
{
|
||||
env->SetIntField(target, AwtComponent::heightID,
|
||||
h = minHeight);
|
||||
env->SetIntField(peer, AwtWindow::sysHID,
|
||||
h);
|
||||
}
|
||||
}
|
||||
env->DeleteLocalRef(target);
|
||||
@@ -3425,40 +3355,6 @@ void AwtWindow::_GetNativeWindowSize(void* param) {
|
||||
env->DeleteGlobalRef(self);
|
||||
}
|
||||
|
||||
/*void AwtWindow::_WindowDPIChange(void* param)
|
||||
{
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
|
||||
ScaleStruct *ss = (ScaleStruct *)param;
|
||||
jobject self = ss->window;
|
||||
jint prevScreen = ss->prevScreen;
|
||||
jfloat prevScaleX = ss->prevScaleX;
|
||||
jfloat prevScaleY = ss->prevScaleY;
|
||||
jint screen = ss->screen;
|
||||
jfloat scaleX = ss->scaleX;
|
||||
jfloat scaleY = ss->scaleY;
|
||||
|
||||
PDATA pData;
|
||||
JNI_CHECK_PEER_GOTO(self, ret);
|
||||
AwtWindow *window = (AwtWindow *)pData;
|
||||
|
||||
if (window->m_winSizeMove) {
|
||||
if (window->prevScaleRec.screen == -1) {
|
||||
window->prevScaleRec.screen = prevScreen;
|
||||
window->prevScaleRec.scaleX = prevScaleX;
|
||||
window->prevScaleRec.scaleY = prevScaleY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
window->WindowDPIChange(prevScreen, prevScaleX, prevScaleY,
|
||||
screen, scaleX, scaleY);
|
||||
}
|
||||
|
||||
ret:
|
||||
env->DeleteGlobalRef(self);
|
||||
delete ss;
|
||||
}*/
|
||||
|
||||
extern "C" int getSystemMetricValue(int msgType);
|
||||
extern "C" {
|
||||
|
||||
@@ -3515,11 +3411,6 @@ Java_sun_awt_windows_WWindowPeer_initIDs(JNIEnv *env, jclass cls)
|
||||
{
|
||||
TRY;
|
||||
|
||||
CHECK_NULL(AwtWindow::sysXID = env->GetFieldID(cls, "sysX", "I"));
|
||||
CHECK_NULL(AwtWindow::sysYID = env->GetFieldID(cls, "sysY", "I"));
|
||||
CHECK_NULL(AwtWindow::sysWID = env->GetFieldID(cls, "sysW", "I"));
|
||||
CHECK_NULL(AwtWindow::sysHID = env->GetFieldID(cls, "sysH", "I"));
|
||||
|
||||
CHECK_NULL(AwtWindow::sysInsetsID = env->GetFieldID(cls, "sysInsets", "Ljava/awt/Insets;"));
|
||||
|
||||
AwtWindow::windowTypeID = env->GetFieldID(cls, "windowType",
|
||||
@@ -4161,49 +4052,6 @@ Java_sun_awt_windows_WWindowPeer_repositionSecurityWarning(JNIEnv *env,
|
||||
CATCH_BAD_ALLOC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_windows_WWindowPeer
|
||||
* Method: _AdjustBoundsOnDPIChange
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_awt_windows_WWindowPeer_adjustBoundsOnDPIChange(JNIEnv *env, jobject self)
|
||||
{
|
||||
TRY;
|
||||
|
||||
AwtToolkit::GetInstance().InvokeFunction(AwtWindow::_AdjustBoundsOnDPIChange, (void*)env->NewGlobalRef(self));
|
||||
// global refs deleted in _AdjustBoundsOnDisplayChange
|
||||
|
||||
CATCH_BAD_ALLOC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_windows_WWindowPeer
|
||||
* Method: windowDPIChange
|
||||
* Signature: (IFFIFF)V
|
||||
*/
|
||||
/*JNIEXPORT void JNICALL
|
||||
Java_sun_awt_windows_WWindowPeer_windowDPIChange(JNIEnv *env, jobject self,
|
||||
jint prevScreen, jfloat prevScaleX, jfloat prevScaleY,
|
||||
jint screen, jfloat scaleX, jfloat scaleY)
|
||||
{
|
||||
TRY;
|
||||
|
||||
ScaleStruct *ss = new ScaleStruct;
|
||||
ss->window = env->NewGlobalRef(self);
|
||||
ss->prevScreen = prevScreen;
|
||||
ss->prevScaleX = prevScaleX;
|
||||
ss->prevScaleY = prevScaleY;
|
||||
ss->screen = screen;
|
||||
ss->scaleX = scaleX;
|
||||
ss->scaleY = scaleY;
|
||||
|
||||
AwtToolkit::GetInstance().InvokeFunction(AwtWindow::_WindowDPIChange, ss);
|
||||
// global refs and ss are deleted in _WindowDPIChange
|
||||
|
||||
CATCH_BAD_ALLOC;
|
||||
}*/
|
||||
|
||||
/*
|
||||
* Class: sun_awt_windows_WLightweightFramePeer
|
||||
* Method: overrideNativeHandle
|
||||
|
||||
@@ -58,12 +58,6 @@ public:
|
||||
static jfieldID securityWarningHeightID;
|
||||
|
||||
/* sun.awt.windows.WWindowPeer field and method IDs */
|
||||
// The coordinates at the peer.
|
||||
static jfieldID sysXID;
|
||||
static jfieldID sysYID;
|
||||
static jfieldID sysWID;
|
||||
static jfieldID sysHID;
|
||||
|
||||
static jfieldID sysInsetsID;
|
||||
|
||||
static jfieldID windowTypeID;
|
||||
@@ -131,6 +125,7 @@ public:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
virtual void Reshape(int x, int y, int w, int h);
|
||||
virtual void Invalidate(RECT* r);
|
||||
virtual void Show();
|
||||
virtual void SetResizable(BOOL isResizable);
|
||||
@@ -138,7 +133,7 @@ public:
|
||||
virtual void RecalcNonClient();
|
||||
virtual void RedrawNonClient();
|
||||
virtual int GetScreenImOn();
|
||||
virtual BOOL CheckIfOnNewScreen();
|
||||
virtual void CheckIfOnNewScreen(BOOL force);
|
||||
virtual void Grab();
|
||||
virtual void Ungrab();
|
||||
virtual void Ungrab(BOOL doPost);
|
||||
@@ -180,8 +175,8 @@ public:
|
||||
virtual MsgRouting WmMove(int x, int y);
|
||||
virtual MsgRouting WmSize(UINT type, int w, int h);
|
||||
virtual MsgRouting WmSizing();
|
||||
/*virtual MsgRouting WmEnterSizeMove();
|
||||
virtual MsgRouting WmExitSizeMove();*/
|
||||
virtual MsgRouting WmEnterSizeMove();
|
||||
virtual MsgRouting WmExitSizeMove();
|
||||
virtual MsgRouting WmPaint(HDC hDC);
|
||||
virtual MsgRouting WmSettingChange(UINT wFlag, LPCTSTR pszSection);
|
||||
virtual MsgRouting WmNcCalcSize(BOOL fCalcValidRects,
|
||||
@@ -197,8 +192,6 @@ public:
|
||||
virtual MsgRouting HandleEvent(MSG *msg, BOOL synthetic);
|
||||
virtual void WindowResized();
|
||||
|
||||
MsgRouting WmDPIChanged(UINT xDPI, UINT yDPI, RECT* bounds);
|
||||
|
||||
static jboolean _RequestWindowFocus(void *param);
|
||||
|
||||
virtual BOOL AwtSetActiveWindow(BOOL isMouseEventCause = FALSE, UINT hittest = HTCLIENT);
|
||||
@@ -255,8 +248,6 @@ public:
|
||||
static void _RepositionSecurityWarning(void* param);
|
||||
static void _SetFullScreenExclusiveModeState(void* param);
|
||||
static void _GetNativeWindowSize(void* param);
|
||||
// static void _WindowDPIChange(void* param);
|
||||
static void _AdjustBoundsOnDPIChange(void* param);
|
||||
static void _OverrideHandle(void *param);
|
||||
|
||||
inline static BOOL IsResizing() {
|
||||
@@ -296,7 +287,6 @@ private:
|
||||
// from its hierarchy when shown. Currently applied to instances of
|
||||
// javax/swing/Popup$HeavyWeightWindow class.
|
||||
BOOL m_isIgnoringMouseEvents; // Make window transparent for mouse events (used for JCEF)
|
||||
RECT m_boundsOnDPIChange; /* bounds to asynchronously adjust on DPI change */
|
||||
|
||||
// SetTranslucency() is the setter for the following two fields
|
||||
BYTE m_opacity; // The opacity level. == 0xff by default (when opacity mode is disabled)
|
||||
@@ -412,19 +402,18 @@ protected:
|
||||
private:
|
||||
int m_screenNum;
|
||||
|
||||
/*typedef struct {
|
||||
typedef struct {
|
||||
jint screen;
|
||||
jfloat scaleX;
|
||||
jfloat scaleY;
|
||||
} ScaleRec;
|
||||
|
||||
BOOL m_winSizeMove;
|
||||
ScaleRec prevScaleRec;*/
|
||||
ScaleRec prevScaleRec;
|
||||
|
||||
void InitOwner(AwtWindow *owner);
|
||||
/*void CheckWindowDPIChange();
|
||||
void WindowDPIChange(int prevScreen, float prevScaleX, float prevScaleY,
|
||||
int newScreen, float scaleX, float scaleY); */
|
||||
void CheckWindowDPIChange();
|
||||
void WmDPIChanged(const LPARAM &lParam);
|
||||
|
||||
Type m_windowType;
|
||||
void InitType(JNIEnv *env, jobject peer);
|
||||
|
||||
@@ -41,6 +41,10 @@ extern const UINT SYSCOMMAND_IMM;
|
||||
* See winuser.h for details.
|
||||
*/
|
||||
|
||||
#ifndef WM_DPICHANGED
|
||||
#define WM_DPICHANGED 0x02E0
|
||||
#endif //WM_DPICHANGED
|
||||
|
||||
#ifndef WM_MOUSEWHEEL
|
||||
#define WM_MOUSEWHEEL 0x020A
|
||||
#endif //WM_MOUSEWHEEL
|
||||
|
||||
@@ -614,10 +614,6 @@ class Stream<T> extends ExchangeImpl<T> {
|
||||
if (contentLength > 0) {
|
||||
h.setHeader("content-length", Long.toString(contentLength));
|
||||
}
|
||||
URI uri = request.uri();
|
||||
if (uri != null) {
|
||||
h.setHeader("host", Utils.hostString(request));
|
||||
}
|
||||
HttpHeaders sysh = filterHeaders(h.build());
|
||||
HttpHeaders userh = filterHeaders(request.getUserHeaders());
|
||||
// Filter context restricted from userHeaders
|
||||
|
||||
118
src/jetbrains.api/src/com/jetbrains/CustomWindowDecoration.java
Normal file
118
src/jetbrains.api/src/com/jetbrains/CustomWindowDecoration.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2000-2021 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.jetbrains;
|
||||
|
||||
import java.awt.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public interface CustomWindowDecoration {
|
||||
|
||||
/*CONST java.awt.Window.*_HIT_SPOT*/
|
||||
/*CONST java.awt.Window.*_BUTTON*/
|
||||
/*CONST java.awt.Window.MENU_BAR*/
|
||||
|
||||
void setCustomDecorationEnabled(Window window, boolean enabled);
|
||||
boolean isCustomDecorationEnabled(Window window);
|
||||
|
||||
void setCustomDecorationHitTestSpots(Window window, List<Map.Entry<Shape, Integer>> spots);
|
||||
List<Map.Entry<Shape, Integer>> getCustomDecorationHitTestSpots(Window window);
|
||||
|
||||
void setCustomDecorationTitleBarHeight(Window window, int height);
|
||||
int getCustomDecorationTitleBarHeight(Window window);
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
class __Fallback implements CustomWindowDecoration {
|
||||
|
||||
private final Method
|
||||
hasCustomDecoration,
|
||||
setHasCustomDecoration,
|
||||
setCustomDecorationHitTestSpots,
|
||||
setCustomDecorationTitleBarHeight;
|
||||
private final Field peer;
|
||||
private final Class<?> wpeer;
|
||||
|
||||
__Fallback() throws Exception {
|
||||
hasCustomDecoration = Window.class.getDeclaredMethod("hasCustomDecoration");
|
||||
hasCustomDecoration.setAccessible(true);
|
||||
setHasCustomDecoration = Window.class.getDeclaredMethod("setHasCustomDecoration");
|
||||
setHasCustomDecoration.setAccessible(true);
|
||||
wpeer = Class.forName("sun.awt.windows.WWindowPeer");
|
||||
setCustomDecorationHitTestSpots = wpeer.getDeclaredMethod("setCustomDecorationHitTestSpots", List.class);
|
||||
setCustomDecorationHitTestSpots.setAccessible(true);
|
||||
setCustomDecorationTitleBarHeight = wpeer.getDeclaredMethod("setCustomDecorationTitleBarHeight", int.class);
|
||||
setCustomDecorationTitleBarHeight.setAccessible(true);
|
||||
peer = Component.class.getDeclaredField("peer");
|
||||
peer.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomDecorationEnabled(Window window, boolean enabled) {
|
||||
if (enabled) {
|
||||
try {
|
||||
setHasCustomDecoration.invoke(window);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCustomDecorationEnabled(Window window) {
|
||||
try {
|
||||
return (boolean) hasCustomDecoration.invoke(window);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomDecorationHitTestSpots(Window window, List<Map.Entry<Shape, Integer>> spots) {
|
||||
List<Rectangle> hitTestSpots = spots.stream().map(e -> e.getKey().getBounds()).collect(Collectors.toList());
|
||||
try {
|
||||
setCustomDecorationHitTestSpots.invoke(wpeer.cast(peer.get(window)), hitTestSpots);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch(ClassCastException | NullPointerException ignore) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<Shape, Integer>> getCustomDecorationHitTestSpots(Window window) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomDecorationTitleBarHeight(Window window, int height) {
|
||||
try {
|
||||
setCustomDecorationTitleBarHeight.invoke(wpeer.cast(peer.get(window)), height);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch(ClassCastException | NullPointerException ignore) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCustomDecorationTitleBarHeight(Window window) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,15 @@ public class JBR {
|
||||
|
||||
private JBR() {}
|
||||
|
||||
private static <T> T getService(Class<T> interFace, FallbackSupplier<T> fallback) {
|
||||
T service = getService(interFace);
|
||||
try {
|
||||
return service != null ? service : fallback != null ? fallback.get() : null;
|
||||
} catch (Throwable ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static <T> T getService(Class<T> interFace) {
|
||||
return api == null ? null : api.getService(interFace);
|
||||
}
|
||||
@@ -94,6 +103,11 @@ public class JBR {
|
||||
<T> T getService(Class<T> interFace);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface FallbackSupplier<T> {
|
||||
T get() throws Throwable;
|
||||
}
|
||||
|
||||
// ========================== Generated metadata ==========================
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,22 +104,30 @@ public class Gensrc {
|
||||
for (Path module : modules.paths) {
|
||||
Path f = module.resolve("share/classes").resolve(file);
|
||||
if (Files.exists(f)) {
|
||||
Pattern namePattern = compile(name.replaceAll("\\*", "[a-zA-Z0-9_]+") + "\\s*=");
|
||||
Pattern statementPattern = compile("((?:(?:public|protected|private|static|final)\\s+){2,3})([a-zA-Z0-9]+)\\s+([^;]+);");
|
||||
Pattern namePattern = compile(name.replaceAll("\\*", "\\\\w+"));
|
||||
Pattern statementPattern = compile(
|
||||
"((?:(?:MODS) ){2,3})([a-zA-Z0-9]+) (FIELD(?:, FIELD)*);"
|
||||
.replaceAll("MODS", "public|protected|private|static|final")
|
||||
.replaceAll("FIELD", "\\\\w+ = [\\\\w\"']+ ")
|
||||
.replaceAll(" ", "\\\\s+")
|
||||
.replaceAll(" ", "\\\\s*")
|
||||
);
|
||||
Matcher statementMatcher = statementPattern.matcher(Files.readString(f));
|
||||
while (statementMatcher.find()) {
|
||||
String mods = statementMatcher.group(1);
|
||||
if (!mods.contains("static") || !mods.contains("final")) continue;
|
||||
for (String s : statementMatcher.group(3).split(",")) {
|
||||
if (!namePattern.matcher(s).find()) continue;
|
||||
statements.add("public static final " + statementMatcher.group(2) + " " + s.strip() + ";");
|
||||
s = s.strip();
|
||||
String nm = s.substring(0, s.indexOf('=')).strip();
|
||||
if (!namePattern.matcher(nm).matches()) continue;
|
||||
statements.add("public static final " + statementMatcher.group(2) + " " + s + ";");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (statements.isEmpty()) throw new RuntimeException("Constant not found: " + placeholder);
|
||||
content = replaceTemplate(content, placeholder, statements, true);
|
||||
content = replaceTemplate(content, placeholder, statements);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +137,7 @@ public class Gensrc {
|
||||
return matcher.group(1);
|
||||
}
|
||||
|
||||
private static String replaceTemplate(String src, String placeholder, Iterable<String> statements, boolean compact) {
|
||||
private static String replaceTemplate(String src, String placeholder, Iterable<String> statements) {
|
||||
int placeholderIndex = src.indexOf(placeholder);
|
||||
int indent = 0;
|
||||
while (placeholderIndex - indent >= 1 && src.charAt(placeholderIndex - indent - 1) == ' ') indent++;
|
||||
@@ -137,11 +145,8 @@ public class Gensrc {
|
||||
if (nextLineIndex == 0) nextLineIndex = placeholderIndex + placeholder.length();
|
||||
String before = src.substring(0, placeholderIndex - indent), after = src.substring(nextLineIndex);
|
||||
StringBuilder sb = new StringBuilder(before);
|
||||
boolean firstStatement = true;
|
||||
for (String s : statements) {
|
||||
if (!firstStatement && !compact) sb.append('\n');
|
||||
sb.append(s);
|
||||
firstStatement = false;
|
||||
sb.append(s).append('\n');
|
||||
}
|
||||
sb.append(after);
|
||||
return sb.toString();
|
||||
@@ -156,7 +161,7 @@ public class Gensrc {
|
||||
Service[] interfaces = findPublicServiceInterfaces();
|
||||
List<String> statements = new ArrayList<>();
|
||||
for (Service i : interfaces) statements.add(generateMethodsForService(i));
|
||||
content = replaceTemplate(content, "/*GENERATED_METHODS*/", statements, false);
|
||||
content = replaceTemplate(content, "/*GENERATED_METHODS*/", statements);
|
||||
content = content.replace("/*KNOWN_SERVICES*/",
|
||||
modules.services.stream().map(s -> "\"" + s + "\"").collect(Collectors.joining(", ")));
|
||||
content = content.replace("/*KNOWN_PROXIES*/",
|
||||
@@ -188,7 +193,8 @@ public class Gensrc {
|
||||
javadocEnd = 0;
|
||||
}
|
||||
return new Service(name, javadoc,
|
||||
content.substring(javadocEnd, indexOfDeclaration).contains("@Deprecated"));
|
||||
content.substring(javadocEnd, indexOfDeclaration).contains("@Deprecated"),
|
||||
content.contains("__Fallback"));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
@@ -198,7 +204,7 @@ public class Gensrc {
|
||||
|
||||
private static String generateMethodsForService(Service service) {
|
||||
return ("private static class $__Holder {<DEPRECATED>\n" +
|
||||
" private static final $ INSTANCE = api != null ? api.getService($.class) : null;\n" +
|
||||
" private static final $ INSTANCE = getService($.class, <FALLBACK>);\n" +
|
||||
"}\n" +
|
||||
"/**\n" +
|
||||
" * @return true if current runtime has implementation for all methods in {@link $}\n" +
|
||||
@@ -214,6 +220,7 @@ public class Gensrc {
|
||||
"public static $ get$() {\n" +
|
||||
" return $__Holder.INSTANCE;\n" +
|
||||
"}")
|
||||
.replace("<FALLBACK>", service.hasFallback ? "$.__Fallback::new" : "null")
|
||||
.replaceAll("\\$", service.name)
|
||||
.replace("<JAVADOC>", service.javadoc)
|
||||
.replaceAll("<DEPRECATED>", service.deprecated ? "\n@Deprecated" : "");
|
||||
@@ -223,11 +230,13 @@ public class Gensrc {
|
||||
private final String name;
|
||||
private final String javadoc;
|
||||
private final boolean deprecated;
|
||||
private final boolean hasFallback;
|
||||
|
||||
private Service(String name, String javadoc, boolean deprecated) {
|
||||
private Service(String name, String javadoc, boolean deprecated, boolean hasFallback) {
|
||||
this.name = name;
|
||||
this.javadoc = javadoc;
|
||||
this.deprecated = deprecated;
|
||||
this.hasFallback = hasFallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
# 2. When only new API is added, or some existing API was @Deprecated - increment MINOR, reset PATCH to 0
|
||||
# 3. For major backwards incompatible API changes - increment MAJOR, reset MINOR and PATCH to 0
|
||||
|
||||
VERSION = 1.0.1
|
||||
VERSION = 1.1.2
|
||||
|
||||
# Hash is used to track changes to jetbrains.api, so you would not forget to update version when needed.
|
||||
# When you make any changes, "make jbr-api" will fail and ask you to update hash and version number here.
|
||||
|
||||
HASH = B5362229733433BFF4CE11BB91E9DA3F
|
||||
HASH = C6871CD21E54119BBB76A1E8D3BD1BBA
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.Button;
|
||||
import java.awt.Canvas;
|
||||
import java.awt.Checkbox;
|
||||
import java.awt.Choice;
|
||||
import java.awt.Component;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Label;
|
||||
import java.awt.List;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
import java.awt.ScrollPane;
|
||||
import java.awt.Scrollbar;
|
||||
import java.awt.TextArea;
|
||||
import java.awt.TextField;
|
||||
import java.awt.Window;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 8211999
|
||||
* @run main/othervm SetComponentsBounds
|
||||
* @run main/othervm -Dsun.java2d.uiScale=1 SetComponentsBounds
|
||||
* @run main/othervm -Dsun.java2d.uiScale=2.25 SetComponentsBounds
|
||||
*/
|
||||
public final class SetComponentsBounds {
|
||||
|
||||
private static final int X = 111;
|
||||
private static final int Y = 222;
|
||||
private static final int WIDTH = 321;
|
||||
private static final int HEIGHT = 123;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
for (GraphicsDevice gd : ge.getScreenDevices()) {
|
||||
test(gd.getDefaultConfiguration(), true);
|
||||
test(gd.getDefaultConfiguration(), false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void test(GraphicsConfiguration gc, boolean visible) throws Exception {
|
||||
Rectangle screen = gc.getBounds();
|
||||
Window frame = new Frame();
|
||||
try {
|
||||
frame.setLayout(null); // trigger use the minimum size of
|
||||
// the peer
|
||||
frame.setBounds(screen.x + 100, screen.y + 100, 500, 500);
|
||||
frame.add(new Button());
|
||||
frame.add(new Canvas());
|
||||
frame.add(new Checkbox());
|
||||
frame.add(new Choice());
|
||||
frame.add(new Label());
|
||||
frame.add(new List());
|
||||
frame.add(new Scrollbar());
|
||||
frame.add(new ScrollPane());
|
||||
frame.add(new TextArea());
|
||||
frame.add(new TextField());
|
||||
for (Component comp : frame.getComponents()) {
|
||||
comp.setBounds(X, Y, WIDTH, HEIGHT);
|
||||
}
|
||||
if (visible) {
|
||||
frame.setVisible(true);
|
||||
} else {
|
||||
frame.pack();
|
||||
}
|
||||
Robot robot = new Robot();
|
||||
robot.waitForIdle();
|
||||
checkGC(gc, frame);
|
||||
for (Component comp : frame.getComponents()) {
|
||||
Rectangle bounds = comp.getBounds();
|
||||
if (bounds.x != X || bounds.y != Y || bounds.width != WIDTH) {
|
||||
System.err.println("Screen bounds:" + screen);
|
||||
System.err.println("Component:" + comp);
|
||||
throw new RuntimeException("Wrong bounds:" + bounds);
|
||||
}
|
||||
if (bounds.height > HEIGHT) {
|
||||
// different check for HEIGHT, it depends on the font
|
||||
throw new RuntimeException("Wrong height:" + bounds.height);
|
||||
}
|
||||
checkGC(gc, comp);
|
||||
}
|
||||
} finally {
|
||||
frame.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkGC(GraphicsConfiguration gc, Component comp) {
|
||||
GraphicsConfiguration compGC = comp.getGraphicsConfiguration();
|
||||
if (compGC != gc) {
|
||||
System.err.println("Expected GC:" + gc);
|
||||
System.err.println("Actual GC:" + compGC);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 6345003 8171363
|
||||
* @bug 6345003 8171363 8211999
|
||||
* @summary grab problems with EmbeddedFrame
|
||||
* @requires (os.family == "windows")
|
||||
* @modules java.desktop/java.awt.peer
|
||||
@@ -67,6 +67,7 @@ public class EmbeddedFrameGrabTest {
|
||||
final Frame frame = new Frame("AWT Frame");
|
||||
frame.pack();
|
||||
frame.setSize(200, 200);
|
||||
frame.setLocationRelativeTo(null);
|
||||
FramePeer frame_peer = AWTAccessor.getComponentAccessor()
|
||||
.getPeer(frame);
|
||||
Class comp_peer_class
|
||||
@@ -88,6 +89,7 @@ public class EmbeddedFrameGrabTest {
|
||||
final Panel p = new Panel();
|
||||
p.setLayout(new BorderLayout());
|
||||
embedded_frame.add(p, BorderLayout.CENTER);
|
||||
embedded_frame.setBounds(0, 0, 150, 150);
|
||||
embedded_frame.validate();
|
||||
p.add(combo);
|
||||
p.validate();
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
@@ -30,7 +31,7 @@ import java.awt.Toolkit;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8176359 8231564
|
||||
* @bug 8176359 8231564 8211999
|
||||
* @key headful
|
||||
* @requires (os.family == "windows" | os.family == "mac")
|
||||
* @summary setMaximizedBounds() should work if set to the screen other than
|
||||
@@ -58,15 +59,23 @@ public final class MaximizedToOppositeScreenSmall {
|
||||
Rectangle framAt = gd1.getDefaultConfiguration().getBounds();
|
||||
framAt.grow(-framAt.width / 2 + 100, -framAt.height / 2 + 100);
|
||||
for (GraphicsDevice gd2 : gds) {
|
||||
Rectangle maxTo = gd2.getDefaultConfiguration().getBounds();
|
||||
maxTo.grow(-maxTo.width / 2 + 120, -maxTo.height / 2 + 120);
|
||||
Frame frame = new Frame(gd1.getDefaultConfiguration());
|
||||
try {
|
||||
frame.setLayout(null); // trigger use the minimum size of
|
||||
// the peer
|
||||
frame.setBounds(framAt);
|
||||
|
||||
frame.setVisible(true);
|
||||
robot.waitForIdle();
|
||||
robot.delay(1000);
|
||||
|
||||
Dimension minimumSize = frame.getMinimumSize();
|
||||
minimumSize.width = Math.max(minimumSize.width, 120);
|
||||
minimumSize.height = Math.max(minimumSize.height, 120);
|
||||
Rectangle maxTo = gd2.getDefaultConfiguration().getBounds();
|
||||
maxTo.grow(-maxTo.width / 2 + minimumSize.width,
|
||||
-maxTo.height / 2 + minimumSize.height);
|
||||
|
||||
frame.setMaximizedBounds(maxTo);
|
||||
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
|
||||
robot.waitForIdle();
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.DisplayMode;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8211999
|
||||
* @key headful
|
||||
* @summary verifies the full-screen window bounds and graphics configuration
|
||||
*/
|
||||
public final class FullscreenWindowProps {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
GraphicsDevice gd = ge.getDefaultScreenDevice();
|
||||
|
||||
if (!gd.isFullScreenSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Frame frame = new Frame() {
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
super.paint(g);
|
||||
g.setColor(Color.GREEN);
|
||||
g.fillRect(0, 0, getWidth(), getHeight());
|
||||
}
|
||||
};
|
||||
try {
|
||||
frame.setBackground(Color.MAGENTA);
|
||||
frame.setVisible(true);
|
||||
gd.setFullScreenWindow(frame);
|
||||
Thread.sleep(4000);
|
||||
|
||||
for (DisplayMode dm : gd.getDisplayModes()) {
|
||||
if (dm.getWidth() == 1024 && dm.getHeight() == 768) {
|
||||
gd.setDisplayMode(dm);
|
||||
Thread.sleep(4000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsConfiguration frameGC = frame.getGraphicsConfiguration();
|
||||
Rectangle frameBounds = frame.getBounds();
|
||||
|
||||
GraphicsConfiguration screenGC = gd.getDefaultConfiguration();
|
||||
Rectangle screenBounds = screenGC.getBounds();
|
||||
|
||||
if (frameGC != screenGC) {
|
||||
System.err.println("Expected: " + screenGC);
|
||||
System.err.println("Actual: " + frameGC);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
checkSize(frameBounds.x, screenBounds.x, "x");
|
||||
checkSize(frameBounds.y, screenBounds.y, "Y");
|
||||
checkSize(frameBounds.width, screenBounds.width, "width");
|
||||
checkSize(frameBounds.height, screenBounds.height, "height");
|
||||
} finally {
|
||||
gd.setFullScreenWindow(null);
|
||||
frame.dispose();
|
||||
Thread.sleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkSize(int actual, int expected, String prop) {
|
||||
if (Math.abs(actual - expected) > 30) { // let's allow size variation,
|
||||
// the bug is reproduced anyway
|
||||
System.err.println("Expected: " + expected);
|
||||
System.err.println("Actual: " + actual);
|
||||
throw new RuntimeException(prop + " is wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Frame;
|
||||
import java.awt.List;
|
||||
import java.awt.Panel;
|
||||
import java.awt.Point;
|
||||
import java.awt.Robot;
|
||||
import java.awt.event.InputEvent;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 4909485 8211999
|
||||
* @key headful
|
||||
*/
|
||||
public final class ListMultipleSelectTest {
|
||||
|
||||
private static List aList;
|
||||
private static Panel panel;
|
||||
private static Point p;
|
||||
private static Robot robot;
|
||||
private static int[] selected;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Frame frame = new Frame();
|
||||
try {
|
||||
panel = new Panel();
|
||||
aList = new List();
|
||||
aList.add("Test item1");
|
||||
aList.add("Test item2");
|
||||
aList.add("Test item3");
|
||||
aList.add("Test item4");
|
||||
|
||||
frame.setLayout(new FlowLayout()); //list should fill whole frame's space
|
||||
panel.add(aList);
|
||||
frame.setSize(200, 200);
|
||||
frame.setLocationRelativeTo(null);
|
||||
panel.setVisible(true);
|
||||
frame.add(panel);
|
||||
frame.setVisible(true);
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(" InterruptedException. Test failed. ");
|
||||
}
|
||||
|
||||
Dimension listSize = aList.getSize();
|
||||
p = aList.getLocationOnScreen();
|
||||
int stepY = listSize.height / aList.getItemCount();
|
||||
|
||||
// System.out.println("itemCount = "+aList.getItemCount());
|
||||
// System.out.println("Size Of aList="+ listSize);
|
||||
// System.out.println("stepY = "+stepY);
|
||||
// System.out.println("Point:" +p);
|
||||
System.out.println("Multiple mode is ON");
|
||||
aList.setMultipleMode(true);
|
||||
//=================================================
|
||||
robot = new Robot();
|
||||
robot.setAutoDelay(0);
|
||||
robot.setAutoWaitForIdle(false);
|
||||
robot.delay(10);
|
||||
robot.waitForIdle();
|
||||
|
||||
//=================================================
|
||||
|
||||
for (int i = 0; i < aList.getItemCount(); i++) {
|
||||
//select all items in the List
|
||||
mousePress(p.x + listSize.width / 2, p.y + stepY / 2 + stepY * i);
|
||||
}
|
||||
|
||||
selected = aList.getSelectedIndexes();
|
||||
System.out.println("Multiple mode is ON");
|
||||
aList.setMultipleMode(true);
|
||||
int[] newSelected = aList.getSelectedIndexes();
|
||||
if (!java.util.Arrays.equals(newSelected, selected)) {
|
||||
throw new RuntimeException(" Incorrect item remains selected " +
|
||||
"after setMultipleMode(true). ");
|
||||
}
|
||||
|
||||
aList.setMultipleMode(false);
|
||||
System.out.println("Multiple mode is OFF");
|
||||
selected = aList.getSelectedIndexes();
|
||||
if (selected[0] != 3 || selected.length != 1) {
|
||||
throw new RuntimeException(" Incorrect item remains selected " +
|
||||
"after setMultipleMode(false) or it is more then one " +
|
||||
"item remaining.Forward. ");
|
||||
}
|
||||
|
||||
System.out.println("Multiple mode is ON");
|
||||
aList.setMultipleMode(true);
|
||||
|
||||
if (selected[0] != 3 || selected.length != 1) {
|
||||
throw new RuntimeException(" Incorrect item remains selected " +
|
||||
"after setMultipleMode(true) or it is more then one " +
|
||||
"item remaining. ");
|
||||
}
|
||||
|
||||
deselectAll();
|
||||
for (int i = aList.getItemCount() - 1; i >= 0; i--) {
|
||||
mousePress(p.x + listSize.width / 2, p.y + stepY / 2 + stepY * i);
|
||||
}
|
||||
|
||||
System.out.println("Multiple mode is OFF");
|
||||
aList.setMultipleMode(false);
|
||||
|
||||
selected = aList.getSelectedIndexes();
|
||||
if (selected[0] != 0 || selected.length != 1) {
|
||||
throw new RuntimeException(" Incorrect item remains selected " +
|
||||
"after setMultipleMode(false) or it is more then one " +
|
||||
"item remaining.Backward. ");
|
||||
}
|
||||
System.out.println("Test succeeded.");
|
||||
} finally {
|
||||
frame.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void mousePress(int x, int y) {
|
||||
robot.mouseMove(x, y);
|
||||
robot.mousePress(InputEvent.BUTTON1_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_MASK);
|
||||
robot.delay(1000);
|
||||
}
|
||||
|
||||
private static void deselectAll() {
|
||||
for (int i = 0; i < selected.length; i++) {
|
||||
aList.deselect(selected[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
/*
|
||||
@test
|
||||
@key headful
|
||||
@bug 8017472
|
||||
@bug 8017472 8211999
|
||||
@summary MouseEvent has wrong coordinates when using multiple monitors
|
||||
@run main MouseEventTest
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
@@ -38,7 +40,7 @@ import javax.imageio.ImageIO;
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 8215105
|
||||
* @bug 8215105 8211999
|
||||
* @summary tests that Robot can capture the common colors without artifacts
|
||||
*/
|
||||
public final class CheckCommonColors {
|
||||
@@ -48,16 +50,20 @@ public final class CheckCommonColors {
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
robot = new Robot();
|
||||
try {
|
||||
test();
|
||||
} finally {
|
||||
frame.dispose();
|
||||
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
for (GraphicsDevice gd : ge.getScreenDevices()) {
|
||||
try {
|
||||
test(gd.getDefaultConfiguration().getBounds());
|
||||
} finally {
|
||||
frame.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void test() {
|
||||
private static void test(Rectangle screen) {
|
||||
frame.setSize(400, 400);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.setLocation((int)screen.getCenterX() - 200,
|
||||
(int)screen.getCenterY() - 200);
|
||||
frame.setUndecorated(true);
|
||||
for (final Color color : List.of(Color.WHITE, Color.LIGHT_GRAY,
|
||||
Color.GRAY, Color.DARK_GRAY,
|
||||
@@ -69,16 +75,24 @@ public final class CheckCommonColors {
|
||||
robot.waitForIdle();
|
||||
frame.setBackground(color);
|
||||
frame.setVisible(true);
|
||||
checkPixels(color);
|
||||
checkPixels(color, true);
|
||||
checkPixels(color, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkPixels(final Color color) {
|
||||
private static void checkPixels(final Color color, boolean useRect) {
|
||||
System.out.println("color = " + color + ", useRect = " + useRect);
|
||||
int attempt = 0;
|
||||
while (true) {
|
||||
Point p = frame.getLocationOnScreen();
|
||||
p.translate(frame.getWidth() / 2, frame.getHeight() / 2);
|
||||
Color pixel = robot.getPixelColor(p.x, p.y);
|
||||
Color pixel;
|
||||
Rectangle rect = new Rectangle(p.x, p.y, 1, 1);
|
||||
if (useRect) {
|
||||
BufferedImage bi = robot.createScreenCapture(rect);
|
||||
pixel = new Color(bi.getRGB(0, 0));
|
||||
} else {
|
||||
pixel = robot.getPixelColor(rect.x, rect.y);
|
||||
}
|
||||
if (color.equals(pixel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.awt.Robot;
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 8201364 8232433
|
||||
* @bug 8201364 8232433 8211999
|
||||
* @summary Component.getLocation() should returns correct location if
|
||||
* Component.setBounds() was ignored by the OS
|
||||
*/
|
||||
@@ -64,8 +64,11 @@ public final class LocationAtScreenCorner {
|
||||
Rectangle bounds = device.getDefaultConfiguration().getBounds();
|
||||
test(robot, frame, bounds.x, bounds.y);
|
||||
test(robot, frame, bounds.width, bounds.y);
|
||||
test(robot, frame, bounds.x + bounds.width, bounds.y);
|
||||
test(robot, frame, bounds.x, bounds.height);
|
||||
test(robot, frame, bounds.x, bounds.y + bounds.height);
|
||||
test(robot, frame, bounds.width, bounds.height);
|
||||
test(robot, frame, bounds.x + bounds.width, bounds.y + bounds.height);
|
||||
}
|
||||
frame.dispose();
|
||||
}
|
||||
|
||||
95
test/jdk/java/awt/Window/SlowMotion/SlowMotion.java
Normal file
95
test/jdk/java/awt/Window/SlowMotion/SlowMotion.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 8211999
|
||||
* @run main/timeout=300 SlowMotion
|
||||
* @summary places the window on the screen outside of any insets, and waits to
|
||||
* catch any strange window moving
|
||||
*/
|
||||
public final class SlowMotion {
|
||||
|
||||
// some additional space, if getScreenInsets() does not work, say on Linux
|
||||
private static final int SAFE = 100;
|
||||
private static final int HEIGHT = 350;
|
||||
private static final int WIDTH = 279;
|
||||
private static Robot robot;
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
robot = new Robot();
|
||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
GraphicsDevice[] sds = ge.getScreenDevices();
|
||||
|
||||
for (GraphicsDevice sd : sds) {
|
||||
GraphicsConfiguration gc = sd.getDefaultConfiguration();
|
||||
Rectangle bounds = gc.getBounds();
|
||||
bounds.translate(SAFE, SAFE);
|
||||
Point point = new Point(bounds.x, bounds.y);
|
||||
Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
|
||||
while (point.y < bounds.y + bounds.height - insets.bottom - HEIGHT - SAFE * 2) {
|
||||
while (point.x < bounds.x + bounds.width - insets.right - WIDTH - SAFE * 2) {
|
||||
test(point, new Frame());
|
||||
test(point, new Window(null));
|
||||
test(point, new Dialog((Dialog) null));
|
||||
point.translate(bounds.width / 6, 0);
|
||||
}
|
||||
point.setLocation(bounds.x, point.y + bounds.height / 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void test(final Point loc, Window window) {
|
||||
try {
|
||||
window.setBounds(loc.x, loc.y, WIDTH, HEIGHT);
|
||||
window.setVisible(true);
|
||||
robot.delay(1000); // intentionally very slow, we try to catch
|
||||
// very very last suspicion event
|
||||
Rectangle bounds = window.getBounds();
|
||||
if (loc.x != bounds.x || loc.y != bounds.y
|
||||
|| bounds.width != WIDTH || bounds.height != HEIGHT) {
|
||||
System.err.println("Component = " + window);
|
||||
System.err.println("Actual bounds = " + bounds);
|
||||
System.err.println("Expected location = " + loc);
|
||||
System.err.println("Expected width = " + WIDTH);
|
||||
System.err.println("Expected height = " + HEIGHT);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} finally {
|
||||
window.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Window;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 8211999
|
||||
* @summary The test creates the packed/unpacked top level components on the
|
||||
* different screens and compares their bounds
|
||||
* @run main/othervm WindowSizeDifferentScreens
|
||||
* @run main/othervm -Dsun.java2d.uiScale=1 WindowSizeDifferentScreens
|
||||
* @run main/othervm -Dsun.java2d.uiScale=1.25 WindowSizeDifferentScreens
|
||||
*/
|
||||
public final class WindowSizeDifferentScreens {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
test("window");
|
||||
test("dialog");
|
||||
test("frame");
|
||||
}
|
||||
|
||||
private static void test(String top) throws Exception {
|
||||
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
Robot robot = new Robot();
|
||||
Window main = getTopLevel(top);
|
||||
try {
|
||||
main.setVisible(true);
|
||||
robot.waitForIdle();
|
||||
main.setSize(500, 500);
|
||||
robot.waitForIdle();
|
||||
for (GraphicsDevice gd : ge.getScreenDevices()) {
|
||||
Rectangle bounds = gd.getDefaultConfiguration().getBounds();
|
||||
Point point = bounds.getLocation();
|
||||
point.translate(100, 100);
|
||||
main.setLocation(point);
|
||||
main.setBackground(Color.RED);
|
||||
robot.waitForIdle();
|
||||
|
||||
Window packed = getTopLevel(top);
|
||||
Window unpacked = getTopLevel(top);
|
||||
try {
|
||||
packed.pack();
|
||||
robot.waitForIdle();
|
||||
packed.setBackground(Color.GREEN);
|
||||
unpacked.setBackground(Color.BLUE);
|
||||
packed.setSize(500, 500);
|
||||
unpacked.setSize(500, 500);
|
||||
packed.setLocation(point);
|
||||
unpacked.setLocation(point);
|
||||
robot.waitForIdle();
|
||||
packed.setVisible(true);
|
||||
unpacked.setVisible(true);
|
||||
robot.waitForIdle();
|
||||
Rectangle mBounds = main.getBounds();
|
||||
Rectangle pBounds = packed.getBounds();
|
||||
Rectangle uBounds = unpacked.getBounds();
|
||||
|
||||
if (!mBounds.equals(uBounds) ||
|
||||
!mBounds.equals(pBounds)) {
|
||||
System.err.println("Expected bounds: " + mBounds);
|
||||
System.err.println("Actual unpacked: " + uBounds);
|
||||
System.err.println("Actual packed: " + pBounds);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} finally {
|
||||
packed.dispose();
|
||||
unpacked.dispose();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
main.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static Window getTopLevel(String top) {
|
||||
switch (top) {
|
||||
case "window": return new Window(null);
|
||||
case "dialog": return new Dialog((Dialog) null);
|
||||
case "frame" : return new Frame();
|
||||
default: throw new IllegalArgumentException("Unexpected: " + top);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,10 @@
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.dnd.DnDConstants;
|
||||
@@ -47,7 +47,7 @@ import test.java.awt.regtesthelpers.Util;
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 4955110 8238575
|
||||
* @bug 4955110 8238575 8211999
|
||||
* @summary tests that DragSourceDragEvent.getDropAction() accords to its new
|
||||
* spec (does not depend on the user drop action)
|
||||
* @library ../../regtesthelpers
|
||||
@@ -57,6 +57,7 @@ import test.java.awt.regtesthelpers.Util;
|
||||
*/
|
||||
public final class Button2DragTest {
|
||||
|
||||
private static final int SIZE = 200;
|
||||
private volatile boolean dropSuccess;
|
||||
private volatile boolean locationValid = true;
|
||||
|
||||
@@ -79,8 +80,8 @@ public final class Button2DragTest {
|
||||
final DragSourceListener dragSourceListener = new DragSourceListener() {
|
||||
private void checkLocation(DragSourceEvent dsde) {
|
||||
if (!frame.getBounds().contains(dsde.getLocation())) {
|
||||
System.err.println("Expected in" + frame.getBounds());
|
||||
System.err.println("Actual" + dsde.getLocation());
|
||||
System.err.println("Expected in: " + frame.getBounds());
|
||||
System.err.println("Actual: " + dsde.getLocation());
|
||||
locationValid = false;
|
||||
}
|
||||
}
|
||||
@@ -130,8 +131,10 @@ public final class Button2DragTest {
|
||||
|
||||
frame.setBackground(Color.GREEN);
|
||||
frame.setUndecorated(true);
|
||||
frame.setSize(200, 200);
|
||||
frame.setLocationRelativeTo(null);
|
||||
Rectangle screen = frame.getGraphicsConfiguration().getBounds();
|
||||
int x = (int) (screen.getCenterX() - SIZE / 2);
|
||||
int y = (int) (screen.getCenterY() - SIZE / 2);
|
||||
frame.setBounds(x, y, SIZE, SIZE);
|
||||
frame.setVisible(true);
|
||||
|
||||
Robot robot = Util.createRobot();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@@ -25,7 +25,7 @@
|
||||
* @test
|
||||
* @summary Verify that some special headers - such as User-Agent
|
||||
* can be specified by the caller.
|
||||
* @bug 8203771
|
||||
* @bug 8203771 8218546
|
||||
* @modules java.base/sun.net.www.http
|
||||
* java.net.http/jdk.internal.net.http.common
|
||||
* java.net.http/jdk.internal.net.http.frame
|
||||
@@ -64,8 +64,6 @@ import java.net.http.HttpHeaders;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -74,13 +72,13 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.lang.System.err;
|
||||
import static java.lang.System.out;
|
||||
import static java.net.http.HttpClient.Builder.NO_PROXY;
|
||||
import static java.net.http.HttpClient.Version.HTTP_2;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import org.testng.Assert;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
public class SpecialHeadersTest implements HttpServerAdapters {
|
||||
|
||||
@@ -151,7 +149,11 @@ public class SpecialHeadersTest implements HttpServerAdapters {
|
||||
"USER-AGENT", u -> userAgent(), "HOST", u -> u.getRawAuthority());
|
||||
|
||||
@Test(dataProvider = "variants")
|
||||
void test(String uriString, String headerNameAndValue, boolean sameClient) throws Exception {
|
||||
void test(String uriString,
|
||||
String headerNameAndValue,
|
||||
boolean sameClient)
|
||||
throws Exception
|
||||
{
|
||||
out.println("\n--- Starting ");
|
||||
|
||||
int index = headerNameAndValue.indexOf(":");
|
||||
@@ -183,21 +185,41 @@ public class SpecialHeadersTest implements HttpServerAdapters {
|
||||
assertEquals(resp.statusCode(), 200,
|
||||
"Expected 200, got:" + resp.statusCode());
|
||||
|
||||
String receivedHeaderString = value == null ? null
|
||||
: resp.headers().firstValue("X-"+key).get();
|
||||
out.println("Got X-" + key + ": " + resp.headers().allValues("X-"+key));
|
||||
if (value != null) {
|
||||
assertEquals(receivedHeaderString, value);
|
||||
assertEquals(resp.headers().allValues("X-"+key), List.of(value));
|
||||
} else {
|
||||
assertEquals(resp.headers().allValues("X-"+key).size(), 0);
|
||||
}
|
||||
boolean isInitialRequest = i == 0;
|
||||
boolean isSecure = uri.getScheme().equalsIgnoreCase("https");
|
||||
boolean isHTTP2 = resp.version() == HTTP_2;
|
||||
boolean isNotH2CUpgrade = isSecure || (sameClient == true && !isInitialRequest);
|
||||
boolean isDefaultHostHeader = name.equalsIgnoreCase("host") && useDefault;
|
||||
|
||||
// By default, HTTP/2 sets the `:authority:` pseudo-header, instead
|
||||
// of the `Host` header. Therefore, there should be no "X-Host"
|
||||
// header in the response, except the response to the h2c Upgrade
|
||||
// request which will have been sent through HTTP/1.1.
|
||||
|
||||
if (isDefaultHostHeader && isHTTP2 && isNotH2CUpgrade) {
|
||||
assertTrue(resp.headers().firstValue("X-" + key).isEmpty());
|
||||
assertTrue(resp.headers().allValues("X-" + key).isEmpty());
|
||||
out.println("No X-" + key + " header received, as expected");
|
||||
} else {
|
||||
String receivedHeaderString = value == null ? null
|
||||
: resp.headers().firstValue("X-"+key).get();
|
||||
out.println("Got X-" + key + ": " + resp.headers().allValues("X-"+key));
|
||||
if (value != null) {
|
||||
assertEquals(receivedHeaderString, value);
|
||||
assertEquals(resp.headers().allValues("X-"+key), List.of(value));
|
||||
} else {
|
||||
assertEquals(resp.headers().allValues("X-"+key).size(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "variants")
|
||||
void testHomeMadeIllegalHeader(String uriString, String headerNameAndValue, boolean sameClient) throws Exception {
|
||||
void testHomeMadeIllegalHeader(String uriString,
|
||||
String headerNameAndValue,
|
||||
boolean sameClient)
|
||||
throws Exception
|
||||
{
|
||||
out.println("\n--- Starting ");
|
||||
final URI uri = URI.create(uriString);
|
||||
|
||||
@@ -266,6 +288,11 @@ public class SpecialHeadersTest implements HttpServerAdapters {
|
||||
}
|
||||
HttpRequest request = requestBuilder.build();
|
||||
|
||||
boolean isInitialRequest = i == 0;
|
||||
boolean isSecure = uri.getScheme().equalsIgnoreCase("https");
|
||||
boolean isNotH2CUpgrade = isSecure || (sameClient == true && !isInitialRequest);
|
||||
boolean isDefaultHostHeader = name.equalsIgnoreCase("host") && useDefault;
|
||||
|
||||
client.sendAsync(request, BodyHandlers.ofString())
|
||||
.thenApply(response -> {
|
||||
out.println("Got response: " + response);
|
||||
@@ -273,15 +300,27 @@ public class SpecialHeadersTest implements HttpServerAdapters {
|
||||
assertEquals(response.statusCode(), 200);
|
||||
return response;})
|
||||
.thenAccept(resp -> {
|
||||
String receivedHeaderString = value == null ? null
|
||||
: resp.headers().firstValue("X-"+key).get();
|
||||
out.println("Got X-" + key + ": " + resp.headers().allValues("X-"+key));
|
||||
if (value != null) {
|
||||
assertEquals(receivedHeaderString, value);
|
||||
assertEquals(resp.headers().allValues("X-" + key), List.of(value));
|
||||
// By default, HTTP/2 sets the `:authority:` pseudo-header, instead
|
||||
// of the `Host` header. Therefore, there should be no "X-Host"
|
||||
// header in the response, except the response to the h2c Upgrade
|
||||
// request which will have been sent through HTTP/1.1.
|
||||
|
||||
if (isDefaultHostHeader && resp.version() == HTTP_2 && isNotH2CUpgrade) {
|
||||
assertTrue(resp.headers().firstValue("X-" + key).isEmpty());
|
||||
assertTrue(resp.headers().allValues("X-" + key).isEmpty());
|
||||
out.println("No X-" + key + " header received, as expected");
|
||||
} else {
|
||||
assertEquals(resp.headers().allValues("X-" + key).size(), 1);
|
||||
} })
|
||||
String receivedHeaderString = value == null ? null
|
||||
: resp.headers().firstValue("X-"+key).get();
|
||||
out.println("Got X-" + key + ": " + resp.headers().allValues("X-"+key));
|
||||
if (value != null) {
|
||||
assertEquals(receivedHeaderString, value);
|
||||
assertEquals(resp.headers().allValues("X-" + key), List.of(value));
|
||||
} else {
|
||||
assertEquals(resp.headers().allValues("X-" + key).size(), 1);
|
||||
}
|
||||
}
|
||||
})
|
||||
.join();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Robot;
|
||||
import java.awt.event.InputEvent;
|
||||
import javax.swing.JFrame;
|
||||
@@ -35,13 +38,15 @@ import javax.swing.SwingUtilities;
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 8149849
|
||||
* @bug 8149849 8211999
|
||||
* @summary [hidpi] DnD issues (cannot DnD from JFileChooser to JEditorPane or
|
||||
* other text component) when scale > 1
|
||||
* @run main/othervm DNDTextToScaledArea
|
||||
* @run main/othervm -Dsun.java2d.uiScale=2 DNDTextToScaledArea
|
||||
*/
|
||||
public class DNDTextToScaledArea {
|
||||
|
||||
private static final int SIZE = 300;
|
||||
private static final String TEXT = "ABCDEFGH";
|
||||
private static JFrame frame;
|
||||
private static JTextArea srcTextArea;
|
||||
@@ -51,10 +56,17 @@ public class DNDTextToScaledArea {
|
||||
private static volatile boolean passed = false;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Robot robot = new Robot();
|
||||
robot.setAutoDelay(50);
|
||||
var lge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
for (GraphicsDevice device : lge.getScreenDevices()) {
|
||||
test(device);
|
||||
}
|
||||
}
|
||||
|
||||
SwingUtilities.invokeAndWait(DNDTextToScaledArea::createAndShowGUI);
|
||||
private static void test(GraphicsDevice device) throws Exception {
|
||||
Robot robot = new Robot();
|
||||
robot.setAutoDelay(150);
|
||||
|
||||
SwingUtilities.invokeAndWait(() -> createAndShowGUI(device));
|
||||
robot.waitForIdle();
|
||||
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
@@ -62,6 +74,11 @@ public class DNDTextToScaledArea {
|
||||
dstPoint = getPoint(dstTextArea, 0.75);
|
||||
});
|
||||
robot.waitForIdle();
|
||||
// check the destination
|
||||
robot.mouseMove(dstPoint.x, dstPoint.y);
|
||||
robot.mousePress(InputEvent.BUTTON1_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_MASK);
|
||||
robot.waitForIdle();
|
||||
|
||||
dragAndDrop(robot, srcPoint, dstPoint);
|
||||
robot.waitForIdle();
|
||||
@@ -77,11 +94,12 @@ public class DNDTextToScaledArea {
|
||||
}
|
||||
}
|
||||
|
||||
private static void createAndShowGUI() {
|
||||
|
||||
frame = new JFrame();
|
||||
frame.setSize(300, 300);
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
private static void createAndShowGUI(GraphicsDevice device) {
|
||||
frame = new JFrame(device.getDefaultConfiguration());
|
||||
Rectangle screen = device.getDefaultConfiguration().getBounds();
|
||||
int x = (int) (screen.getCenterX() - SIZE / 2);
|
||||
int y = (int) (screen.getCenterY() - SIZE / 2);
|
||||
frame.setBounds(x, y, SIZE, SIZE);
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
|
||||
|
||||
120
test/jdk/jb/build/CheckJBRModules.java
Normal file
120
test/jdk/jb/build/CheckJBRModules.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2022 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @requires !vm.graal.enabled
|
||||
* @summary Verifies the list of available modules
|
||||
* @library /test/lib
|
||||
* @run main CheckJBRModules
|
||||
*/
|
||||
public class CheckJBRModules {
|
||||
static final String moduleNames[] = {
|
||||
"java.base",
|
||||
"java.compiler",
|
||||
"java.datatransfer",
|
||||
"java.desktop",
|
||||
"java.instrument",
|
||||
"java.logging",
|
||||
"java.management",
|
||||
"java.management.rmi",
|
||||
"java.naming",
|
||||
"java.net.http",
|
||||
"java.prefs",
|
||||
"java.rmi",
|
||||
"java.scripting",
|
||||
"java.se",
|
||||
"java.security.jgss",
|
||||
"java.security.sasl",
|
||||
"java.smartcardio",
|
||||
"java.sql",
|
||||
"java.sql.rowset",
|
||||
"java.transaction.xa",
|
||||
"java.xml",
|
||||
"java.xml.crypto",
|
||||
"jdk.accessibility",
|
||||
"jdk.attach",
|
||||
"jdk.charsets",
|
||||
"jdk.compiler",
|
||||
"jdk.crypto.cryptoki",
|
||||
"jdk.crypto.ec",
|
||||
"jdk.dynalink",
|
||||
"jdk.httpserver",
|
||||
"jdk.internal.ed",
|
||||
"jdk.internal.le",
|
||||
"jdk.internal.vm.ci",
|
||||
"jdk.jdi",
|
||||
"jdk.jdwp.agent",
|
||||
"jdk.jfr",
|
||||
"jdk.jsobject",
|
||||
"jdk.localedata",
|
||||
"jdk.management",
|
||||
"jdk.management.agent",
|
||||
"jdk.management.jfr",
|
||||
"jdk.naming.dns",
|
||||
"jdk.naming.rmi",
|
||||
"jdk.net",
|
||||
"jdk.pack",
|
||||
"jdk.scripting.nashorn",
|
||||
"jdk.scripting.nashorn.shell",
|
||||
"jdk.sctp",
|
||||
"jdk.security.auth",
|
||||
"jdk.security.jgss",
|
||||
"jdk.unsupported",
|
||||
"jdk.unsupported.desktop",
|
||||
"jdk.xml.dom",
|
||||
"jdk.zipfs",
|
||||
"jdk.hotspot.agent",
|
||||
"jdk.jcmd" };
|
||||
|
||||
static final String moduleNames_x64[] = {
|
||||
"jdk.aot",
|
||||
"jdk.internal.vm.compiler",
|
||||
"jdk.internal.vm.compiler.management" };
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
final OutputAnalyzer oa = exec("--list-modules").shouldHaveExitValue(0);
|
||||
for(String moduleName : moduleNames) {
|
||||
oa.shouldContain(moduleName);
|
||||
}
|
||||
|
||||
final boolean isArch_x64 = "x86_64".equals(System.getProperty("os.arch"));
|
||||
if (isArch_x64) {
|
||||
for(String moduleName : moduleNames_x64) {
|
||||
oa.shouldContain(moduleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* java args... returning the OutputAnalyzer to analyzer the output
|
||||
*/
|
||||
private static OutputAnalyzer exec(String... args) throws Exception {
|
||||
return ProcessTools.executeTestJava(args)
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
}
|
||||
}
|
||||
53
test/jdk/jb/build/CheckJBRModulesWindows.java
Normal file
53
test/jdk/jb/build/CheckJBRModulesWindows.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2022 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @requires !vm.graal.enabled
|
||||
* @requires (os.family == "windows")
|
||||
* @summary Verifies the list of available modules specific to Windows
|
||||
* @library /test/lib
|
||||
* @run main CheckJBRModulesWindows
|
||||
*/
|
||||
public class CheckJBRModulesWindows {
|
||||
static final String moduleNames[] = { "jdk.crypto.mscapi" };
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
final OutputAnalyzer oa = exec("--list-modules").shouldHaveExitValue(0);
|
||||
for(String moduleName : moduleNames) {
|
||||
oa.shouldContain(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* java args... returning the OutputAnalyzer to analyzer the output
|
||||
*/
|
||||
private static OutputAnalyzer exec(String... args) throws Exception {
|
||||
return ProcessTools.executeTestJava(args)
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
}
|
||||
}
|
||||
@@ -35,13 +35,13 @@ public class ProxyInfoResolvingTest {
|
||||
JBRApi.ModuleRegistry r = init();
|
||||
// No mapping defined -> null
|
||||
requireNull(getProxy(ProxyInfoResolvingTest.class));
|
||||
// Invalid JBR-side target class -> error
|
||||
// Invalid JBR-side target class -> null
|
||||
r.proxy(InterfaceWithoutImplementation.class.getName(), "absentImpl");
|
||||
mustFail(() -> getProxy(InterfaceWithoutImplementation.class), RuntimeException.class, ClassNotFoundException.class);
|
||||
// Invalid JBR-side target static method mapping -> error
|
||||
requireNull(getProxy(InterfaceWithoutImplementation.class));
|
||||
// Invalid JBR-side target static method mapping -> null
|
||||
r.service(ServiceWithoutImplementation.class.getName(), null)
|
||||
.withStatic("someMethod", "NoClass");
|
||||
mustFail(() -> getProxy(ServiceWithoutImplementation.class), RuntimeException.class, ClassNotFoundException.class);
|
||||
requireNull(getProxy(ServiceWithoutImplementation.class));
|
||||
// Service without target class or static method mapping -> null
|
||||
r.service(EmptyService.class.getName(), null);
|
||||
requireNull(getProxy(EmptyService.class));
|
||||
|
||||
85
test/jdk/jb/java/awt/Focus/MacSpecialFocusLostCase.java
Normal file
85
test/jdk/jb/java/awt/Focus/MacSpecialFocusLostCase.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2022 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for JBR-4281 Window losing focus isn't detected in some cases on macOS
|
||||
* @key headful
|
||||
* @requires (os.family == "mac")
|
||||
*/
|
||||
|
||||
public class MacSpecialFocusLostCase {
|
||||
private static Robot robot;
|
||||
private static JFrame frame;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
robot = new Robot();
|
||||
robot.setAutoDelay(50);
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(MacSpecialFocusLostCase::initUI);
|
||||
checkFocusedStatus(true);
|
||||
pressCmdSpace(); // open Spotlight popup
|
||||
checkFocusedStatus(false);
|
||||
pressEsc(); // close Spotlight popup
|
||||
checkFocusedStatus(true);
|
||||
} finally {
|
||||
pressEsc(); // make sure popup is closed in any case
|
||||
SwingUtilities.invokeAndWait(MacSpecialFocusLostCase::disposeUI);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initUI() {
|
||||
frame = new JFrame("MacSpecialFocusLostCase");
|
||||
frame.setBounds(200, 200, 300, 200);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
private static void disposeUI() {
|
||||
if (frame != null) frame.dispose();
|
||||
}
|
||||
|
||||
private static void checkFocusedStatus(boolean expected) throws Exception {
|
||||
robot.delay(1000);
|
||||
boolean[] result = new boolean[1];
|
||||
SwingUtilities.invokeAndWait(() -> result[0] = frame.isFocused());
|
||||
if (result[0] != expected) {
|
||||
throw new RuntimeException(expected ? "Frame isn't focused" : "Frame is still focused");
|
||||
}
|
||||
}
|
||||
|
||||
private static void pressCmdSpace() {
|
||||
robot.keyPress(KeyEvent.VK_META);
|
||||
robot.keyPress(KeyEvent.VK_SPACE);
|
||||
robot.keyRelease(KeyEvent.VK_SPACE);
|
||||
robot.keyRelease(KeyEvent.VK_META);
|
||||
}
|
||||
|
||||
private static void pressEsc() {
|
||||
robot.keyPress(KeyEvent.VK_ESCAPE);
|
||||
robot.keyRelease(KeyEvent.VK_ESCAPE);
|
||||
}
|
||||
}
|
||||
@@ -1,140 +1,137 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import sun.awt.InvokeOnToolkitHelper;
|
||||
import sun.lwawt.macosx.CThreading;
|
||||
import sun.lwawt.macosx.LWCToolkit;
|
||||
import sun.awt.AWTThreading;
|
||||
|
||||
import javax.swing.*;
|
||||
import static helper.ToolkitTestHelper.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary tests that AWTThreading can manage a stream of cross EDT/AppKit invocation requests
|
||||
* @summary tests that AWTThreading can manage cross EDT/AppKit blocking invocation requests
|
||||
* @requires (os.family == "mac")
|
||||
* @compile --add-exports=java.desktop/sun.lwawt.macosx=ALL-UNNAMED --add-exports=java.desktop/sun.awt=ALL-UNNAMED AWTThreadingTest.java
|
||||
* @run main/othervm --add-exports=java.desktop/sun.lwawt.macosx=ALL-UNNAMED --add-exports=java.desktop/sun.awt=ALL-UNNAMED AWTThreadingTest
|
||||
* @modules java.desktop/sun.lwawt.macosx java.desktop/sun.awt
|
||||
* @run main AWTThreadingTest
|
||||
* @author Anton Tarasov
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public class AWTThreadingTest {
|
||||
static final ReentrantLock LOCK = new ReentrantLock();
|
||||
static final Condition COND = LOCK.newCondition();
|
||||
static final CountDownLatch LATCH = new CountDownLatch(1);
|
||||
static final int TIMEOUT_SECONDS = 1;
|
||||
|
||||
static JFrame frame;
|
||||
static Thread thread;
|
||||
static final AtomicInteger ITER_COUNTER = new AtomicInteger();
|
||||
static final AtomicBoolean DUMP_STACK = new AtomicBoolean(false);
|
||||
|
||||
final static AtomicBoolean passed = new AtomicBoolean(true);
|
||||
final static AtomicInteger counter = new AtomicInteger(0);
|
||||
static volatile Thread THREAD;
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
EventQueue.invokeLater(AWTThreadingTest::runGui);
|
||||
public static void main(String[] args) {
|
||||
DUMP_STACK.set(args.length > 0 && "dumpStack".equals(args[0]));
|
||||
|
||||
LATCH.await(5, TimeUnit.SECONDS);
|
||||
initTest(AWTThreadingTest.class);
|
||||
|
||||
frame.dispose();
|
||||
thread.interrupt();
|
||||
testCase("certain threads superposition", AWTThreadingTest::test);
|
||||
|
||||
testCase("random threads superposition", AWTThreadingTest::test);
|
||||
|
||||
if (!passed.get()) {
|
||||
throw new RuntimeException("Test FAILED!");
|
||||
}
|
||||
System.out.println("Test PASSED");
|
||||
}
|
||||
|
||||
static void runGui() {
|
||||
frame = new JFrame("frame");
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.setSize(200, 200);
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowOpened(WindowEvent e) {
|
||||
startThread();
|
||||
static void test() {
|
||||
ITER_COUNTER.set(0);
|
||||
|
||||
var timer = new TestTimer(TIMEOUT_SECONDS * 3, TimeUnit.SECONDS);
|
||||
EventQueue.invokeLater(() -> startThread(() ->
|
||||
FUTURE.isDone() ||
|
||||
timer.hasFinished()));
|
||||
|
||||
tryRun(() -> {
|
||||
if (!FUTURE.get(TIMEOUT_SECONDS * 4, TimeUnit.SECONDS)) {
|
||||
throw new RuntimeException("Test FAILED! (negative result)");
|
||||
}
|
||||
});
|
||||
frame.setVisible(true);
|
||||
|
||||
tryRun(THREAD::join);
|
||||
|
||||
System.out.println(ITER_COUNTER + " iterations passed");
|
||||
}
|
||||
|
||||
static void startThread() {
|
||||
thread = new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
static void startThread(Supplier<Boolean> shouldExitLoop) {
|
||||
THREAD = new Thread(() -> {
|
||||
|
||||
while (!shouldExitLoop.get()) {
|
||||
ITER_COUNTER.incrementAndGet();
|
||||
|
||||
var point_1 = new CountDownLatch(1);
|
||||
var point_2 = new CountDownLatch(1);
|
||||
var point_3 = new CountDownLatch(1);
|
||||
var invocations = new CountDownLatch(2);
|
||||
|
||||
//
|
||||
// 1. Execute invokeAndWait() from AppKit to EDT
|
||||
// 1. Blocking invocation from AppKit to EDT
|
||||
//
|
||||
CThreading.executeOnAppKit(() -> {
|
||||
try {
|
||||
LWCToolkit.invokeAndWait(counter::incrementAndGet, Window.getWindows()[0]);
|
||||
} catch (Exception e) {
|
||||
fail(e);
|
||||
}
|
||||
// We're on AppKit, wait for the 2nd invocation to be on the AWTThreading-pool thread.
|
||||
if (TEST_CASE == 1) await(point_1, TIMEOUT_SECONDS);
|
||||
|
||||
tryRun(() -> LWCToolkit.invokeAndWait(() -> {
|
||||
// We're being dispatched on EDT.
|
||||
if (TEST_CASE == 1) point_2.countDown();
|
||||
|
||||
// Wait for the 2nd invocation to be executed on AppKit.
|
||||
if (TEST_CASE == 1) await(point_3, TIMEOUT_SECONDS);
|
||||
}, FRAME));
|
||||
|
||||
invocations.countDown();
|
||||
});
|
||||
|
||||
//
|
||||
// 2. Execute invokeAndBlock() from EDT to AppKit
|
||||
// 2. Blocking invocation from EDT to AppKit
|
||||
//
|
||||
EventQueue.invokeLater(() -> {
|
||||
passed.set(false);
|
||||
EventQueue.invokeLater(() -> AWTThreading.executeWaitToolkit(() -> {
|
||||
// We're on the AWTThreading-pool thread.
|
||||
if (TEST_CASE == 1) point_1.countDown();
|
||||
|
||||
Boolean success = InvokeOnToolkitHelper.invokeAndBlock(() -> {
|
||||
try {
|
||||
return CThreading.executeOnAppKit(() -> Boolean.TRUE);
|
||||
} catch (Throwable e) {
|
||||
fail(e);
|
||||
// Wait for the 1st invocation to start NSRunLoop and be dispatched
|
||||
if (TEST_CASE == 1) await(point_2, TIMEOUT_SECONDS);
|
||||
|
||||
// Perform in JavaRunLoopMode to be accepted by NSRunLoop started by LWCToolkit.invokeAndWait.
|
||||
LWCToolkit.performOnMainThreadAndWait(() -> {
|
||||
if (DUMP_STACK.get()) {
|
||||
dumpAllThreads();
|
||||
}
|
||||
return null;
|
||||
// We're being executed on AppKit.
|
||||
if (TEST_CASE == 1) point_3.countDown();
|
||||
});
|
||||
System.out.println("Success: " + counter.get() + ": " + success);
|
||||
|
||||
passed.set(Boolean.TRUE.equals(success));
|
||||
invocations.countDown();
|
||||
}));
|
||||
|
||||
if (passed.get()) {
|
||||
lock(COND::signal);
|
||||
}
|
||||
else {
|
||||
fail(null);
|
||||
}
|
||||
});
|
||||
await(invocations, TIMEOUT_SECONDS * 2);
|
||||
} // while
|
||||
|
||||
lock(COND::await);
|
||||
}
|
||||
FUTURE.complete(true);
|
||||
});
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
THREAD.setDaemon(true);
|
||||
THREAD.start();
|
||||
}
|
||||
|
||||
static void lock(MyRunnable runnable) {
|
||||
LOCK.lock();
|
||||
try {
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
LOCK.unlock();
|
||||
static void await(CountDownLatch latch, int seconds) {
|
||||
if (!tryCall(() -> latch.await(seconds, TimeUnit.SECONDS), false)) {
|
||||
FUTURE.completeExceptionally(new Throwable("Awaiting has timed out"));
|
||||
}
|
||||
}
|
||||
|
||||
interface MyRunnable {
|
||||
void run() throws Exception;
|
||||
}
|
||||
|
||||
static void fail(Throwable e) {
|
||||
if (e != null) e.printStackTrace();
|
||||
passed.set(false);
|
||||
LATCH.countDown();
|
||||
static void dumpAllThreads() {
|
||||
Thread.getAllStackTraces().keySet().forEach(t -> {
|
||||
System.out.printf("%s\t%s\t%d\t%s\n", t.getName(), t.getState(), t.getPriority(), t.isDaemon() ? "Daemon" : "Normal");
|
||||
Arrays.asList(t.getStackTrace()).forEach(frame -> System.out.println("\tat " + frame));
|
||||
});
|
||||
System.out.println("\n\n");
|
||||
}
|
||||
}
|
||||
220
test/jdk/jb/java/awt/Toolkit/LWCToolkitInvokeAndWaitTest.java
Normal file
220
test/jdk/jb/java/awt/Toolkit/LWCToolkitInvokeAndWaitTest.java
Normal file
@@ -0,0 +1,220 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.*;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.AWTThreading;
|
||||
import sun.lwawt.macosx.CThreading;
|
||||
import sun.lwawt.macosx.LWCToolkit;
|
||||
|
||||
import static helper.ToolkitTestHelper.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests different scenarios for LWCToolkit.invokeAndWait().
|
||||
* @requires (os.family == "mac")
|
||||
* @modules java.desktop/sun.lwawt.macosx java.desktop/sun.awt
|
||||
* @run main LWCToolkitInvokeAndWaitTest
|
||||
* @run main/othervm -Dlog.level.FINER=true LWCToolkitInvokeAndWaitTest
|
||||
* @author Anton Tarasov
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public class LWCToolkitInvokeAndWaitTest {
|
||||
// This property is used in {CAccessibility}
|
||||
static final int INVOKE_TIMEOUT_SECONDS = Integer.getInteger("sun.lwawt.macosx.CAccessibility.invokeTimeoutSeconds", 1);
|
||||
|
||||
static final Runnable CONSUME_DISPATCHING = () -> FUTURE.completeExceptionally(new Throwable("Unexpected dispatching!"));
|
||||
static final TestLogHandler LOG_HANDLER = new TestLogHandler();
|
||||
|
||||
static volatile CountDownLatch EDT_FAST_FREE_LATCH;
|
||||
|
||||
static {
|
||||
AWTThreading.setAWTThreadingFactory(edt -> new AWTThreading(edt) {
|
||||
@Override
|
||||
public CompletableFuture<Void> onEventDispatchThreadFree(Runnable runnable) {
|
||||
if (EDT_FAST_FREE_LATCH != null) {
|
||||
// 1. wait for the invocation event to be dispatched
|
||||
// 2. wait for EDT to become free
|
||||
tryRun(EDT_FAST_FREE_LATCH::await);
|
||||
|
||||
EDT_FAST_FREE_LATCH = null;
|
||||
}
|
||||
// if EDT is free the runnable should be called immediately
|
||||
return super.onEventDispatchThreadFree(runnable);
|
||||
}
|
||||
@Override
|
||||
public void notifyEventDispatchThreadFree() {
|
||||
if (EDT_FAST_FREE_LATCH != null &&
|
||||
// if the invocation event is dispatched by now
|
||||
EDT_FAST_FREE_LATCH.getCount() == 1)
|
||||
{
|
||||
EDT_FAST_FREE_LATCH.countDown();
|
||||
}
|
||||
super.notifyEventDispatchThreadFree();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
loop(); // init the event threads
|
||||
|
||||
tryRun(() -> {
|
||||
Consumer<Class<?>> setLog = cls -> {
|
||||
Logger log = LogManager.getLogManager().getLogger(cls.getName());
|
||||
log.setUseParentHandlers(false);
|
||||
log.addHandler(LOG_HANDLER);
|
||||
if (Boolean.getBoolean("log.level.FINER")) {
|
||||
log.setLevel(Level.FINER);
|
||||
}
|
||||
};
|
||||
setLog.accept(AWTThreading.class);
|
||||
setLog.accept(LWCToolkit.class);
|
||||
});
|
||||
|
||||
Consumer<InvocationEvent> noop = e -> {};
|
||||
|
||||
initTest(LWCToolkitInvokeAndWaitTest.class);
|
||||
|
||||
testCase("InvocationEvent is normally dispatched", () -> test1(
|
||||
"",
|
||||
noop,
|
||||
() -> System.out.println("I'm dispatched")));
|
||||
|
||||
testCase("InvocationEvent is lost", () -> test1(
|
||||
"lost",
|
||||
noop,
|
||||
CONSUME_DISPATCHING));
|
||||
|
||||
EDT_FAST_FREE_LATCH = new CountDownLatch(2);
|
||||
testCase("InvocationEvent is lost (EDT becomes fast free)", () -> test1(
|
||||
"lost",
|
||||
// notify the invocationEvent has been dispatched
|
||||
invocationEvent -> EDT_FAST_FREE_LATCH.countDown(),
|
||||
CONSUME_DISPATCHING));
|
||||
|
||||
testCase("InvocationEvent is disposed", () -> test1(
|
||||
"disposed",
|
||||
invocationEvent -> AWTAccessor.getInvocationEventAccessor().dispose(invocationEvent),
|
||||
CONSUME_DISPATCHING));
|
||||
|
||||
testCase("InvocationEvent is timed out (delayed before dispatching)", () -> test1(
|
||||
"timed out",
|
||||
invocationEvent -> sleep(INVOKE_TIMEOUT_SECONDS * 4),
|
||||
CONSUME_DISPATCHING));
|
||||
|
||||
testCase("InvocationEvent is timed out (delayed during dispatching)", () -> test1(
|
||||
"timed out",
|
||||
noop,
|
||||
() -> sleep(INVOKE_TIMEOUT_SECONDS * 4)));
|
||||
|
||||
testCase("invokeAndWait is discarded", () -> test2(
|
||||
"discarded"));
|
||||
|
||||
System.out.println("Test PASSED");
|
||||
}
|
||||
|
||||
static void test1(String expectedInLog,
|
||||
Consumer<InvocationEvent> onBeforeDispatching,
|
||||
Runnable onDispatching)
|
||||
{
|
||||
EventQueue.invokeLater(() -> subTest1(onBeforeDispatching, onDispatching));
|
||||
|
||||
check(expectedInLog);
|
||||
}
|
||||
|
||||
static void subTest1(Consumer<InvocationEvent> onBeforeDispatching, Runnable onDispatching) {
|
||||
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueue() {
|
||||
@Override
|
||||
protected void dispatchEvent(AWTEvent event) {
|
||||
//
|
||||
// Intercept the invocation posted from Appkit.
|
||||
//
|
||||
if (event instanceof AWTThreading.TrackedInvocationEvent) {
|
||||
System.out.println("Before dispatching: " + event);
|
||||
onBeforeDispatching.accept((InvocationEvent)event);
|
||||
|
||||
if (onDispatching == CONSUME_DISPATCHING) {
|
||||
System.out.println("Consuming: " + event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.dispatchEvent(event);
|
||||
}
|
||||
});
|
||||
CThreading.executeOnAppKit(() -> tryRun(() -> {
|
||||
//
|
||||
// Post an invocation from AppKit.
|
||||
//
|
||||
LWCToolkit.invokeAndWait(onDispatching, FRAME, false, INVOKE_TIMEOUT_SECONDS);
|
||||
FUTURE.complete(true);
|
||||
}));
|
||||
}
|
||||
|
||||
static void test2(String expectedInLog) {
|
||||
EventQueue.invokeLater(() ->
|
||||
//
|
||||
// Blocking EDT.
|
||||
//
|
||||
LWCToolkit.performOnMainThreadAndWait(() -> {
|
||||
//
|
||||
// The invocation from AppKit should be discarded.
|
||||
//
|
||||
tryRun(() -> LWCToolkit.invokeAndWait(EMPTY_RUNNABLE, FRAME, false, INVOKE_TIMEOUT_SECONDS * 4));
|
||||
FUTURE.complete(true);
|
||||
}));
|
||||
|
||||
check(expectedInLog);
|
||||
}
|
||||
|
||||
static void check(String expectedInLog) {
|
||||
tryRun(() -> {
|
||||
if (!FUTURE.get(INVOKE_TIMEOUT_SECONDS * 2L, TimeUnit.SECONDS)) {
|
||||
throw new RuntimeException("Test FAILED! (negative result)");
|
||||
}
|
||||
});
|
||||
|
||||
loop(); // wait for the logging to be printed
|
||||
|
||||
if (!LOG_HANDLER.testContains(expectedInLog)) {
|
||||
throw new RuntimeException("Test FAILED! (not found in the log: \"" + expectedInLog + "\")");
|
||||
}
|
||||
}
|
||||
|
||||
static void loop() {
|
||||
tryRun(() -> EventQueue.invokeAndWait(EMPTY_RUNNABLE));
|
||||
var latch = new CountDownLatch(1);
|
||||
CThreading.executeOnAppKit(latch::countDown);
|
||||
tryRun(latch::await);
|
||||
}
|
||||
|
||||
static void sleep(int seconds) {
|
||||
tryRun(() -> Thread.sleep(seconds * 1000L));
|
||||
}
|
||||
|
||||
static class TestLogHandler extends StreamHandler {
|
||||
public StringBuilder buffer = new StringBuilder();
|
||||
|
||||
public TestLogHandler() {
|
||||
// Use System.out to merge with the test printing.
|
||||
super(System.out, new SimpleFormatter());
|
||||
setLevel(Level.ALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(LogRecord record) {
|
||||
buffer.append(record.getMessage());
|
||||
super.publish(record);
|
||||
flush();
|
||||
}
|
||||
|
||||
public boolean testContains(String str) {
|
||||
boolean contains = buffer.toString().contains(str);
|
||||
buffer.setLength(0);
|
||||
return contains;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
test/jdk/jb/java/awt/Toolkit/helper/ToolkitTestHelper.java
Normal file
120
test/jdk/jb/java/awt/Toolkit/helper/ToolkitTestHelper.java
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package helper;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public class ToolkitTestHelper {
|
||||
public static final Runnable EMPTY_RUNNABLE = () -> {};
|
||||
|
||||
public static volatile CompletableFuture<Boolean> FUTURE;
|
||||
public static volatile int TEST_CASE;
|
||||
public static volatile JFrame FRAME;
|
||||
|
||||
private static volatile JLabel LABEL;
|
||||
private static volatile Thread MAIN_THREAD;
|
||||
|
||||
private static final Runnable UPDATE_LABEL = new Runnable() {
|
||||
final Random rand = new Random();
|
||||
@Override
|
||||
public void run() {
|
||||
LABEL.setForeground(new Color(rand.nextFloat(), 0, rand.nextFloat()));
|
||||
LABEL.setText("(" + TEST_CASE + ")");
|
||||
}
|
||||
};
|
||||
|
||||
public static void initTest(Class<?> testClass) {
|
||||
MAIN_THREAD = Thread.currentThread();
|
||||
|
||||
assert MAIN_THREAD.getName().toLowerCase().contains("main");
|
||||
|
||||
Thread.UncaughtExceptionHandler handler = MAIN_THREAD.getUncaughtExceptionHandler();
|
||||
MAIN_THREAD.setUncaughtExceptionHandler((t, e) -> {
|
||||
if (FRAME != null) FRAME.dispose();
|
||||
handler.uncaughtException(t, e);
|
||||
});
|
||||
|
||||
tryRun(() -> EventQueue.invokeAndWait(() -> {
|
||||
FRAME = new JFrame(testClass.getSimpleName());
|
||||
LABEL = new JLabel("0");
|
||||
LABEL.setFont(LABEL.getFont().deriveFont((float)30));
|
||||
LABEL.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
FRAME.add(LABEL, BorderLayout.CENTER);
|
||||
FRAME.getContentPane().setBackground(Color.green);
|
||||
FRAME.setLocationRelativeTo(null);
|
||||
FRAME.setSize(200, 200);
|
||||
FRAME.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||
FRAME.setVisible(true);
|
||||
}));
|
||||
|
||||
Timer timer = new Timer(100, e -> UPDATE_LABEL.run());
|
||||
timer.setRepeats(true);
|
||||
timer.start();
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
MAIN_THREAD.join();
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
if (FRAME != null) FRAME.dispose();
|
||||
timer.stop();
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void testCase(String caseCaption, Runnable test) {
|
||||
FUTURE = new CompletableFuture<>();
|
||||
FUTURE.whenComplete((r, e) -> Optional.of(e).ifPresent(Throwable::printStackTrace));
|
||||
|
||||
//noinspection NonAtomicOperationOnVolatileField
|
||||
String prefix = "(" + (++TEST_CASE) + ")";
|
||||
|
||||
System.out.println("\n" + prefix + " TEST: " + caseCaption);
|
||||
UPDATE_LABEL.run();
|
||||
|
||||
test.run();
|
||||
|
||||
System.out.println(prefix + " SUCCEEDED\n");
|
||||
}
|
||||
|
||||
public static void tryRun(ThrowableRunnable runnable) {
|
||||
tryCall(() -> {
|
||||
runnable.run();
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
|
||||
public static <T> T tryCall(Callable<T> callable, T defValue) {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
if (Thread.currentThread() == MAIN_THREAD) {
|
||||
throw new RuntimeException("Test FAILED!", e);
|
||||
} else {
|
||||
FUTURE.completeExceptionally(e);
|
||||
}
|
||||
}
|
||||
return defValue;
|
||||
}
|
||||
|
||||
public interface ThrowableRunnable {
|
||||
void run() throws Exception;
|
||||
}
|
||||
|
||||
public static class TestTimer {
|
||||
private final long finishTime;
|
||||
|
||||
public TestTimer(long timeFromNow, TimeUnit unit) {
|
||||
finishTime = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(timeFromNow, unit);
|
||||
}
|
||||
|
||||
public boolean hasFinished() {
|
||||
return System.currentTimeMillis() >= finishTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +120,7 @@ java/awt/Choice/ItemStateChangeTest/ItemStateChangeTest.java
|
||||
java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java 7100044 macosx-all,windows-all,linux-all
|
||||
java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java 8202931 macosx-all,linux-all,windows-all
|
||||
java/awt/Choice/GrabLockTest/GrabLockTest.java JRE-839 windows-all,macosx-all,linux-all
|
||||
java/awt/Choice/PopdownGeneratesMouseEvents/PopdownGeneratesMouseEvents.java 8194045б generic-all
|
||||
java/awt/Choice/PopupPosTest/PopupPosTest.java 8192930 windows-all
|
||||
java/awt/Choice/RemoveAllShrinkTest/RemoveAllShrinkTest.java 8047703 generic-all
|
||||
java/awt/Choice/SelectCurrentItemTest/SelectCurrentItemTest.html 8014503,8192929 windows-all,macosx-all,linux-all
|
||||
@@ -231,6 +232,7 @@ java/awt/LightweightComponent/LightweightEventTest/LightweightEventTest.java
|
||||
java/awt/List/FirstItemRemoveTest/FirstItemRemoveTest.java 8169461 windows-all
|
||||
java/awt/List/KeyEventsTest/KeyEventsTest.java 8047703 windows-all
|
||||
java/awt/List/SingleModeDeselect/SingleModeDeselect.java 8196367 windows-all
|
||||
java/awt/MenuBar/8007006/bug8007006.java 8202886 macosx-all
|
||||
java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java 8049405 macosx-all,windows-all,linux-all
|
||||
java/awt/Mixing/AWT_Mixing/JButtonInGlassPaneOverlapping.java 8158801 windows-all,macosx-all,linux-all
|
||||
java/awt/Mixing/AWT_Mixing/JButtonOverlapping.java 8158801 windows-all,macosx-all,linux-all
|
||||
|
||||
Reference in New Issue
Block a user