Merge tag jb8u212-b1586.4
Change-Id: Iae9396a77c6bbf1eeb78d3970aa21087c26f22c3
diff --git a/build.txt b/build.txt
new file mode 100644
index 0000000..e17dfaa
--- /dev/null
+++ b/build.txt
@@ -0,0 +1 @@
+8u202-b1483.49
diff --git a/make/lib/Awt2dLibraries.gmk b/make/lib/Awt2dLibraries.gmk
index 9c9f56f..15d5237 100644
--- a/make/lib/Awt2dLibraries.gmk
+++ b/make/lib/Awt2dLibraries.gmk
@@ -625,6 +625,12 @@
LIBAWT_XAWT_LDFLAGS += -lpthread
endif
+ ifeq ($(BUILD_XAWT_XWAYLAND), true)
+ LIBAWT_XAWT_FILES += xwayland.c
+ LIBAWT_XAWT_CFLAGS += -DBUILD_XAWT_XWAYLAND=true
+ LIBAWT_XAWT_LDFLAGS_SUFFIX += -lpthread -lxcb -lxcb-composite -lwayland-server -lwayland-client
+ endif
+
$(eval $(call SetupNativeCompilation,BUILD_LIBAWT_XAWT, \
LIBRARY := awt_xawt, \
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
diff --git a/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java b/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java
index 83973ef..6235e4e 100644
--- a/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java
+++ b/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java
@@ -693,7 +693,7 @@
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(theOutputFileName)));
out.println(commentStart +
" This file was generated AUTOMATICALLY from a template file " +
- new java.util.Date() + commentEnd);
+ commentEnd);
int marklen = commandMarker.length();
LOOP: while(true) {
try {
@@ -1808,6 +1808,7 @@
commentStart = (Csyntax ? "/*" : "//");
commentEnd = (Csyntax ? " */" : "");
commandLineDescription = desc.toString();
+ commandLineDescription = "java GenerateCharacter"; // Android Studio: make build deterministic.
}
private static void searchBins(long[] map, int binsOccupied) throws Exception {
diff --git a/src/lang/annotation/TestConstructorParameterAnnotations.java b/src/lang/annotation/TestConstructorParameterAnnotations.java
new file mode 100644
index 0000000..66c270f
--- /dev/null
+++ b/src/lang/annotation/TestConstructorParameterAnnotations.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8074977
+ * @summary Test consistency of annotations on constructor parameters
+ * @compile TestConstructorParameterAnnotations.java
+ * @run main TestConstructorParameterAnnotations
+ * @compile -parameters TestConstructorParameterAnnotations.java
+ * @run main TestConstructorParameterAnnotations
+ */
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+/*
+ * Some constructor parameters are <em>mandated</em>; that is, they
+ * are not explicitly present in the source code, but required to be
+ * present by the Java Language Specification. In other cases, some
+ * constructor parameters are not present in the source, but are
+ * synthesized by the compiler as an implementation artifact. There is
+ * not a reliable mechanism to consistently determine whether or not
+ * a parameter is implicit or not.
+ *
+ * (Using the "-parameters" option to javac does emit the information
+ * needed to make a reliably determination, but the information is not
+ * present by default.)
+ *
+ * The lack of such a mechanism causes complications reading parameter
+ * annotations in some cases since annotations for parameters are
+ * written out for the parameters in the source code, but when reading
+ * annotations at runtime all the parameters, including implicit ones,
+ * are present.
+ */
+public class TestConstructorParameterAnnotations {
+ public static void main(String... args) {
+ int errors = 0;
+ Class<?>[] classes = {NestedClass0.class,
+ NestedClass1.class,
+ NestedClass2.class,
+ NestedClass3.class,
+ NestedClass4.class,
+ StaticNestedClass0.class,
+ StaticNestedClass1.class,
+ StaticNestedClass2.class,
+ StaticNestedClass3.class,
+ StaticNestedClass4.class};
+
+ for (Class<?> clazz : classes) {
+ for (Constructor<?> ctor : clazz.getConstructors()) {
+ System.out.println(ctor);
+ errors += checkGetParameterAnnotations(clazz, ctor);
+ errors += checkGetParametersGetAnnotation(clazz, ctor);
+ }
+ }
+
+ if (errors > 0)
+ throw new RuntimeException(errors + " errors.");
+ return;
+ }
+
+ private static int checkGetParameterAnnotations(Class<?> clazz,
+ Constructor<?> ctor) {
+ String annotationString =
+ Arrays.deepToString(ctor.getParameterAnnotations());
+ String expectedString =
+ clazz.getAnnotation(ExpectedGetParameterAnnotations.class).value();
+
+ if (!Objects.equals(annotationString, expectedString)) {
+ System.err.println("Annotation mismatch on " + ctor +
+ "\n\tExpected:" + expectedString +
+ "\n\tActual: " + annotationString);
+ return 1;
+ }
+ return 0;
+ }
+
+ private static int checkGetParametersGetAnnotation(Class<?> clazz,
+ Constructor<?> ctor) {
+ int errors = 0;
+ int i = 0;
+ ExpectedParameterAnnotations epa =
+ clazz.getAnnotation(ExpectedParameterAnnotations.class);
+
+ for (Parameter param : ctor.getParameters() ) {
+ String annotationString =
+ Objects.toString(param.getAnnotation(MarkerAnnotation.class));
+ String expectedString = epa.value()[i];
+
+ if (!Objects.equals(annotationString, expectedString)) {
+ System.err.println("Annotation mismatch on " + ctor +
+ " on param " + param +
+ "\n\tExpected:" + expectedString +
+ "\n\tActual: " + annotationString);
+ errors++;
+ }
+ i++;
+ }
+ return errors;
+ }
+
+ @ExpectedGetParameterAnnotations("[[]]")
+ @ExpectedParameterAnnotations({"null"})
+ public class NestedClass0 {
+ public NestedClass0() {}
+ }
+
+ @ExpectedGetParameterAnnotations(
+ "[[], " +
+ "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)]]")
+ @ExpectedParameterAnnotations({
+ "null",
+ "@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)"})
+ public class NestedClass1 {
+ public NestedClass1(@MarkerAnnotation(1) int parameter) {}
+ }
+
+ @ExpectedGetParameterAnnotations(
+ "[[], " +
+ "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)], " +
+ "[]]")
+ @ExpectedParameterAnnotations({
+ "null",
+ "@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)",
+ "null"})
+ public class NestedClass2 {
+ public NestedClass2(@MarkerAnnotation(2) int parameter1,
+ int parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations(
+ "[[], " +
+ "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)], " +
+ "[]]")
+ @ExpectedParameterAnnotations({
+ "null",
+ "@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)",
+ "null"})
+ public class NestedClass3 {
+ public <P> NestedClass3(@MarkerAnnotation(3) P parameter1,
+ int parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations(
+ "[[], " +
+ "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)], " +
+ "[]]")
+ @ExpectedParameterAnnotations({
+ "null",
+ "@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)",
+ "null"})
+ public class NestedClass4 {
+ public <P, Q> NestedClass4(@MarkerAnnotation(4) P parameter1,
+ Q parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations("[]")
+ @ExpectedParameterAnnotations({"null"})
+ public static class StaticNestedClass0 {
+ public StaticNestedClass0() {}
+ }
+
+ @ExpectedGetParameterAnnotations(
+ "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)]]")
+ @ExpectedParameterAnnotations({
+ "@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)"})
+ public static class StaticNestedClass1 {
+ public StaticNestedClass1(@MarkerAnnotation(1) int parameter) {}
+ }
+
+ @ExpectedGetParameterAnnotations(
+ "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)], " +
+ "[]]")
+ @ExpectedParameterAnnotations({
+ "@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)",
+ "null"})
+ public static class StaticNestedClass2 {
+ public StaticNestedClass2(@MarkerAnnotation(2) int parameter1,
+ int parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations(
+ "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)], " +
+ "[]]")
+ @ExpectedParameterAnnotations({
+ "@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)",
+ "null"})
+ public static class StaticNestedClass3 {
+ public <P> StaticNestedClass3(@MarkerAnnotation(3) P parameter1,
+ int parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations(
+ "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)], " +
+ "[]]")
+ @ExpectedParameterAnnotations({
+ "@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)",
+ "null"})
+ public static class StaticNestedClass4 {
+ public <P, Q> StaticNestedClass4(@MarkerAnnotation(4) P parameter1,
+ Q parameter2) {}
+ }
+
+ @Target(ElementType.PARAMETER)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface MarkerAnnotation {
+ int value();
+ }
+
+ /**
+ * String form of expected value of calling
+ * getParameterAnnotations on a constructor.
+ */
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ExpectedGetParameterAnnotations {
+ String value();
+ }
+
+ /**
+ * String form of expected value of calling
+ * getAnnotation(MarkerAnnotation.class) on each element of the
+ * result of getParameters() on a constructor.
+ */
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ExpectedParameterAnnotations {
+ String[] value();
+ }
+}
diff --git a/src/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java b/src/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java
new file mode 100644
index 0000000..ee36976
--- /dev/null
+++ b/src/lang/annotation/typeAnnotations/TestConstructorParameterTypeAnnotations.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8074977
+ * @summary Test consistency of annotations on constructor parameters
+ * @compile TestConstructorParameterTypeAnnotations.java
+ * @run main TestConstructorParameterTypeAnnotations
+ * @compile -parameters TestConstructorParameterTypeAnnotations.java
+ * @run main TestConstructorParameterTypeAnnotations
+ */
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+/*
+ * Some constructor parameters are <em>mandated</em>; that is, they
+ * are not explicitly present in the source code, but required to be
+ * present by the Java Language Specification. In other cases, some
+ * constructor parameters are not present in the source, but are
+ * synthesized by the compiler as an implementation artifact. There is
+ * not a reliable mechanism to consistently determine whether or not
+ * a parameter is implicit or not.
+ *
+ * (Using the "-parameters" option to javac does emit the information
+ * needed to make a reliably determination, but the information is not
+ * present by default.)
+ *
+ * The lack of such a mechanism causes complications reading parameter
+ * annotations in some cases since annotations for parameters are
+ * written out for the parameters in the source code, but when reading
+ * annotations at runtime all the parameters, including implicit ones,
+ * are present.
+ */
+public class TestConstructorParameterTypeAnnotations {
+ public static void main(String... args) {
+ int errors = 0;
+ Class<?>[] classes = {NestedClass0.class,
+ NestedClass1.class,
+ NestedClass2.class,
+ NestedClass3.class,
+ NestedClass4.class,
+ StaticNestedClass0.class,
+ StaticNestedClass1.class,
+ StaticNestedClass2.class };
+
+ for (Class<?> clazz : classes) {
+ for (Constructor<?> ctor : clazz.getConstructors()) {
+ System.out.println(ctor);
+ errors += checkGetParameterAnnotations(clazz, ctor);
+ errors += checkGetAnnotatedParametersGetAnnotation(clazz, ctor);
+ }
+ }
+
+ if (errors > 0)
+ throw new RuntimeException(errors + " errors.");
+ return;
+ }
+
+ private static int checkGetParameterAnnotations(Class<?> clazz,
+ Constructor<?> ctor) {
+ String annotationString =
+ Arrays.deepToString(ctor.getParameterAnnotations());
+ String expectedString =
+ clazz.getAnnotation(ExpectedGetParameterAnnotations.class).value();
+
+ if (!Objects.equals(annotationString, expectedString)) {
+ System.err.println("Annotation mismatch on " + ctor +
+ "\n\tExpected:" + expectedString +
+ "\n\tActual: " + annotationString);
+ return 1;
+ }
+ return 0;
+ }
+
+ private static int checkGetAnnotatedParametersGetAnnotation(Class<?> clazz,
+ Constructor<?> ctor) {
+ int errors = 0;
+ int i = 0;
+ ExpectedParameterTypeAnnotations epa =
+ clazz.getAnnotation(ExpectedParameterTypeAnnotations.class);
+
+ for (AnnotatedType param : ctor.getAnnotatedParameterTypes() ) {
+ String annotationString =
+ Objects.toString(param.getAnnotation(MarkerTypeAnnotation.class));
+ String expectedString = epa.value()[i];
+
+ if (!Objects.equals(annotationString, expectedString)) {
+ System.err.println("Annotation mismatch on " + ctor +
+ " on param " + param +
+ "\n\tExpected:" + expectedString +
+ "\n\tActual: " + annotationString);
+ errors++;
+ }
+ i++;
+ }
+ return errors;
+ }
+
+ @ExpectedGetParameterAnnotations("[[]]")
+ @ExpectedParameterTypeAnnotations({"null"})
+ public class NestedClass0 {
+ public NestedClass0() {}
+ }
+
+ @ExpectedGetParameterAnnotations("[[], []]")
+ @ExpectedParameterTypeAnnotations({
+ "null",
+ "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=1)"})
+ public class NestedClass1 {
+ public NestedClass1(@MarkerTypeAnnotation(1) int parameter) {}
+ }
+
+ @ExpectedGetParameterAnnotations("[[], [], []]")
+ @ExpectedParameterTypeAnnotations({
+ "null",
+ "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=2)",
+ "null"})
+ public class NestedClass2 {
+ public NestedClass2(@MarkerTypeAnnotation(2) int parameter1,
+ int parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations("[[], [], []]")
+ @ExpectedParameterTypeAnnotations({
+ "null",
+ "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=3)",
+ "null"})
+ public class NestedClass3 {
+ public <P> NestedClass3(@MarkerTypeAnnotation(3) P parameter1,
+ int parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations("[[], [], []]")
+ @ExpectedParameterTypeAnnotations({
+ "null",
+ "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=4)",
+ "null"})
+ public class NestedClass4 {
+ public <P, Q> NestedClass4(@MarkerTypeAnnotation(4) P parameter1,
+ Q parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations("[]")
+ @ExpectedParameterTypeAnnotations({"null"})
+ public static class StaticNestedClass0 {
+ public StaticNestedClass0() {}
+ }
+
+ @ExpectedGetParameterAnnotations("[[]]")
+ @ExpectedParameterTypeAnnotations({
+ "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=1)"})
+ public static class StaticNestedClass1 {
+ public StaticNestedClass1(@MarkerTypeAnnotation(1) int parameter) {}
+ }
+
+ @ExpectedGetParameterAnnotations("[[], []]")
+ @ExpectedParameterTypeAnnotations({
+ "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=2)",
+ "null"})
+ public static class StaticNestedClass2 {
+ public StaticNestedClass2(@MarkerTypeAnnotation(2) int parameter1,
+ int parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations("[[], []]")
+ @ExpectedParameterTypeAnnotations({
+ "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=3)",
+ "null"})
+ public static class StaticNestedClass3 {
+ public <P> StaticNestedClass3(@MarkerTypeAnnotation(3) P parameter1,
+ int parameter2) {}
+ }
+
+ @ExpectedGetParameterAnnotations("[[], []]")
+ @ExpectedParameterTypeAnnotations({
+ "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=4)",
+ "null"})
+ public static class StaticNestedClass4 {
+ public <P, Q> StaticNestedClass4(@MarkerTypeAnnotation(4) P parameter1,
+ Q parameter2) {}
+ }
+
+ @Target(ElementType.TYPE_USE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface MarkerTypeAnnotation {
+ int value();
+ }
+
+ /**
+ * String form of expected value of calling
+ * getParameterAnnotations on a constructor.
+ */
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ExpectedGetParameterAnnotations {
+ String value();
+ }
+
+ /**
+ * String form of expected value of calling
+ * getAnnotation(MarkerTypeAnnotation.class) on each element of the
+ * result of getParameters() on a constructor.
+ */
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ExpectedParameterTypeAnnotations {
+ String[] value();
+ }
+}
diff --git a/src/macosx/native/sun/awt/AWTWindow.m b/src/macosx/native/sun/awt/AWTWindow.m
index 82d7b24..b1bcd97 100644
--- a/src/macosx/native/sun/awt/AWTWindow.m
+++ b/src/macosx/native/sun/awt/AWTWindow.m
@@ -323,6 +323,9 @@
if (self.nsWindow == nil) return nil; // no hope either
[self.nsWindow release]; // the property retains the object already
+ // Tell the system we have an sRGB backing store
+ [self.nsWindow setColorSpace: [NSColorSpace sRGBColorSpace]];
+
self.isEnabled = YES;
self.isMinimizing = NO;
self.javaPlatformWindow = platformWindow;
diff --git a/src/share/classes/java/lang/reflect/Constructor.java b/src/share/classes/java/lang/reflect/Constructor.java
index bf17091..e5b9436 100644
--- a/src/share/classes/java/lang/reflect/Constructor.java
+++ b/src/share/classes/java/lang/reflect/Constructor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -524,19 +524,18 @@
}
@Override
- void handleParameterNumberMismatch(int resultLength, int numParameters) {
+ boolean handleParameterNumberMismatch(int resultLength, int numParameters) {
Class<?> declaringClass = getDeclaringClass();
if (declaringClass.isEnum() ||
declaringClass.isAnonymousClass() ||
declaringClass.isLocalClass() )
- return ; // Can't do reliable parameter counting
+ return false; // Can't do reliable parameter counting
else {
- if (!declaringClass.isMemberClass() || // top-level
- // Check for the enclosing instance parameter for
- // non-static member classes
- (declaringClass.isMemberClass() &&
- ((declaringClass.getModifiers() & Modifier.STATIC) == 0) &&
- resultLength + 1 != numParameters) ) {
+ if (declaringClass.isMemberClass() &&
+ ((declaringClass.getModifiers() & Modifier.STATIC) == 0) &&
+ resultLength + 1 == numParameters) {
+ return true;
+ } else {
throw new AnnotationFormatError(
"Parameter annotations don't match number of parameters");
}
diff --git a/src/share/classes/java/lang/reflect/Executable.java b/src/share/classes/java/lang/reflect/Executable.java
index 3e82d99..832b5cd 100644
--- a/src/share/classes/java/lang/reflect/Executable.java
+++ b/src/share/classes/java/lang/reflect/Executable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, 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
@@ -554,12 +554,18 @@
Annotation[][] result = parseParameterAnnotations(parameterAnnotations);
- if (result.length != numParameters)
- handleParameterNumberMismatch(result.length, numParameters);
+ if (result.length != numParameters &&
+ handleParameterNumberMismatch(result.length, numParameters)) {
+ Annotation[][] tmp = new Annotation[result.length+1][];
+ // Shift annotations down one to account for an implicit leading parameter
+ System.arraycopy(result, 0, tmp, 1, result.length);
+ tmp[0] = new Annotation[0];
+ result = tmp;
+ }
return result;
}
- abstract void handleParameterNumberMismatch(int resultLength, int numParameters);
+ abstract boolean handleParameterNumberMismatch(int resultLength, int numParameters);
/**
* {@inheritDoc}
diff --git a/src/share/classes/java/lang/reflect/Method.java b/src/share/classes/java/lang/reflect/Method.java
index ddf0f38..02efc80 100644
--- a/src/share/classes/java/lang/reflect/Method.java
+++ b/src/share/classes/java/lang/reflect/Method.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -649,7 +649,7 @@
}
@Override
- void handleParameterNumberMismatch(int resultLength, int numParameters) {
+ boolean handleParameterNumberMismatch(int resultLength, int numParameters) {
throw new AnnotationFormatError("Parameter annotations don't match number of parameters");
}
}
diff --git a/src/share/classes/java/nio/file/FileTreeWalker.java b/src/share/classes/java/nio/file/FileTreeWalker.java
index b0cf0d3..eae821c 100644
--- a/src/share/classes/java/nio/file/FileTreeWalker.java
+++ b/src/share/classes/java/nio/file/FileTreeWalker.java
@@ -25,6 +25,8 @@
package java.nio.file;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicWithKeyFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.io.Closeable;
import java.io.IOException;
@@ -216,7 +218,11 @@
// links then a link target might not exist so get attributes of link
BasicFileAttributes attrs;
try {
- attrs = Files.readAttributes(file, BasicFileAttributes.class, linkOptions);
+ BasicFileAttributeView view = Files.getFileAttributeView(file, BasicWithKeyFileAttributeView.class, linkOptions);
+ if (view == null) {
+ view = Files.getFileAttributeView(file, BasicFileAttributeView.class, linkOptions);
+ }
+ attrs = view.readAttributes();
} catch (IOException ioe) {
if (!followLinks)
throw ioe;
diff --git a/src/share/classes/java/nio/file/attribute/BasicWithKeyFileAttributeView.java b/src/share/classes/java/nio/file/attribute/BasicWithKeyFileAttributeView.java
new file mode 100644
index 0000000..917284a
--- /dev/null
+++ b/src/share/classes/java/nio/file/attribute/BasicWithKeyFileAttributeView.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * Similar to {@link BasicFileAttributeView} with a hint to implementors
+ * to retrieve a valid {@link BasicFileAttributes#fileKey()} if possible, even
+ * at a performance cost.
+ */
+
+public interface BasicWithKeyFileAttributeView
+ extends BasicFileAttributeView {
+}
diff --git a/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java b/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java
index 8eab556..4c94ddf 100644
--- a/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java
+++ b/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -125,9 +125,30 @@
tmp.add(t);
}
}
+ // If a constructor has a mandated outer this, that parameter
+ // has no annotations and the annotations to parameter mapping
+ // should be offset by 1.
+ boolean offset = false;
+ if (decl instanceof Constructor) {
+ Constructor<?> ctor = (Constructor<?>) decl;
+ Class<?> declaringClass = ctor.getDeclaringClass();
+ if (!declaringClass.isEnum() &&
+ (declaringClass.isMemberClass() &&
+ (declaringClass.getModifiers() & Modifier.STATIC) == 0) ) {
+ offset = true;
+ }
+ }
for (int i = 0; i < size; i++) {
- @SuppressWarnings("unchecked")
- ArrayList<TypeAnnotation> list = l[i];
+ ArrayList<TypeAnnotation> list;
+ if (offset) {
+ @SuppressWarnings("unchecked")
+ ArrayList<TypeAnnotation> tmp = (i == 0) ? null : l[i - 1];
+ list = tmp;
+ } else {
+ @SuppressWarnings("unchecked")
+ ArrayList<TypeAnnotation> tmp = l[i];
+ list = tmp;
+ }
TypeAnnotation[] typeAnnotations;
if (list != null) {
typeAnnotations = list.toArray(new TypeAnnotation[list.size()]);
diff --git a/src/share/native/com/sun/java/util/jar/pack/jni.cpp b/src/share/native/com/sun/java/util/jar/pack/jni.cpp
index e9109cb..f8ff76e 100644
--- a/src/share/native/com/sun/java/util/jar/pack/jni.cpp
+++ b/src/share/native/com/sun/java/util/jar/pack/jni.cpp
@@ -292,7 +292,7 @@
if (uPtr->aborting()) {
THROW_IOE(uPtr->get_abort_message());
- return false;
+ return null;
}
// We have fetched all the files.
diff --git a/src/share/native/sun/font/layout/LEInsertionList.h b/src/share/native/sun/font/layout/LEInsertionList.h
index 231b5f6..56f9688 100644
--- a/src/share/native/sun/font/layout/LEInsertionList.h
+++ b/src/share/native/sun/font/layout/LEInsertionList.h
@@ -101,7 +101,7 @@
/**
* The destructor.
*/
- ~LEInsertionList();
+ virtual ~LEInsertionList();
/**
* Add an entry to the insertion list.
diff --git a/src/solaris/classes/sun/awt/X11/XBaseWindow.java b/src/solaris/classes/sun/awt/X11/XBaseWindow.java
index 052af80..1cea1ee 100644
--- a/src/solaris/classes/sun/awt/X11/XBaseWindow.java
+++ b/src/solaris/classes/sun/awt/X11/XBaseWindow.java
@@ -1,3 +1,27 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
package sun.awt.X11;
import java.awt.*;
diff --git a/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java b/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java
index 959f241..7fd1ca7 100644
--- a/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java
+++ b/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java
@@ -605,8 +605,7 @@
// its location changes.
Point oldLocation = getLocation();
- Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX(target),
- AWTAccessor.getComponentAccessor().getY(target));
+ Point newLocation = newDimensions.getLocation();
if (!newLocation.equals(oldLocation)) {
handleMoved(newDimensions);
diff --git a/src/solaris/native/sun/awt/awt_GraphicsEnv.c b/src/solaris/native/sun/awt/awt_GraphicsEnv.c
index 1a20b40..d2f989d 100644
--- a/src/solaris/native/sun/awt/awt_GraphicsEnv.c
+++ b/src/solaris/native/sun/awt/awt_GraphicsEnv.c
@@ -32,6 +32,10 @@
#include <sun_awt_X11GraphicsDevice.h>
#include <sun_awt_X11GraphicsConfig.h>
#ifndef HEADLESS
+#ifdef BUILD_XAWT_XWAYLAND
+#include "xwayland.h"
+#include <pthread.h>
+#endif /* BUILD_XAWT_XWAYLAND */
#include <X11/extensions/Xdbe.h>
#include <X11/XKBlib.h>
#include "Xrandr.h"
@@ -178,6 +182,17 @@
#ifndef HEADLESS
+#ifdef BUILD_XAWT_XWAYLAND
+/*
+ * XWayland thread function
+ */
+static void *xwayland_start(void *data)
+{
+ xwayland_run((pthread_barrier_t *) data);
+ return 0;
+}
+#endif /* BUILD_XAWT_XWAYLAND */
+
/*
* XIOErrorHandler
*/
@@ -748,6 +763,26 @@
}
}
+#ifdef BUILD_XAWT_XWAYLAND
+ if (getenv("_AWT_USE_XWAYLAND") != NULL &&
+ strlen(getenv("_AWT_USE_XWAYLAND")) > 0) {
+ pthread_barrier_t barrier;
+ pthread_t thread;
+ pthread_attr_t attr;
+ int rv;
+
+ rv = pthread_barrier_init(&barrier, NULL, 2);
+ assert(!rv);
+ pthread_attr_init(&attr);
+ rv = pthread_create(&thread, &attr, xwayland_start, &barrier);
+ assert(!rv);
+ pthread_barrier_wait(&barrier);
+ pthread_barrier_destroy(&barrier);
+
+ setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1);
+ }
+#endif /* BUILD_XAWT_XWAYLAND */
+
dpy = awt_display = XOpenDisplay(NULL);
#ifdef NETSCAPE
sigprocmask(SIG_SETMASK, &oldset, NULL);
diff --git a/src/solaris/native/sun/awt/xwayland.c b/src/solaris/native/sun/awt/xwayland.c
new file mode 100644
index 0000000..131dc5c
--- /dev/null
+++ b/src/solaris/native/sun/awt/xwayland.c
@@ -0,0 +1,2202 @@
+/*
+ * Copyright 2016 The Chromium Authors. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#define WL_HIDE_DEPRECATED
+#include <wayland-client.h>
+#include <wayland-server.h>
+#include <xcb/composite.h>
+#include <xcb/xcb.h>
+
+struct xwl;
+
+struct xwl_host_callback {
+ struct wl_resource *resource;
+ struct wl_callback *proxy;
+};
+
+struct xwl_compositor {
+ struct xwl *xwl;
+ uint32_t id;
+ uint32_t version;
+ struct wl_global *host_global;
+ struct wl_compositor *internal;
+};
+
+struct xwl_host_surface {
+ struct xwl_compositor *compositor;
+ struct wl_resource *resource;
+ struct wl_surface *proxy;
+ int has_contents;
+};
+
+struct xwl_host_compositor {
+ struct xwl_compositor *compositor;
+ struct wl_resource *resource;
+ struct wl_compositor *proxy;
+};
+
+struct xwl_host_buffer {
+ struct wl_resource *resource;
+ struct wl_buffer *proxy;
+};
+
+struct xwl_host_shm_pool {
+ struct wl_resource *resource;
+ struct wl_shm_pool *proxy;
+};
+
+struct xwl_host_shm {
+ struct xwl_shm *shm;
+ struct wl_resource *resource;
+ struct wl_shm *proxy;
+};
+
+struct xwl_shm {
+ struct xwl *xwl;
+ uint32_t id;
+ struct wl_global *host_global;
+};
+
+struct xwl_host_shell {
+ struct xwl_shell *shell;
+ struct wl_resource *resource;
+ struct wl_shell *proxy;
+};
+
+struct xwl_shell {
+ struct xwl *xwl;
+ uint32_t id;
+ struct wl_global *host_global;
+ struct wl_shell *internal;
+};
+
+struct xwl_host_output {
+ struct xwl_output *output;
+ struct wl_resource *resource;
+ struct wl_output *proxy;
+};
+
+struct xwl_output {
+ struct xwl *xwl;
+ uint32_t id;
+ uint32_t version;
+ struct wl_global *host_global;
+ struct wl_list link;
+};
+
+struct xwl_seat {
+ struct xwl *xwl;
+ uint32_t id;
+ uint32_t version;
+ struct wl_global *host_global;
+ struct wl_list link;
+};
+
+struct xwl_host_pointer {
+ struct xwl_seat *seat;
+ struct wl_resource *resource;
+ struct wl_pointer *proxy;
+};
+
+struct xwl_host_keyboard {
+ struct xwl_seat *seat;
+ struct wl_resource *resource;
+ struct wl_keyboard *proxy;
+};
+
+struct xwl_host_touch {
+ struct xwl_seat *seat;
+ struct wl_resource *resource;
+ struct wl_touch *proxy;
+};
+
+struct xwl_host_seat {
+ struct xwl_seat *seat;
+ struct wl_resource *resource;
+ struct wl_seat *proxy;
+};
+
+struct xwl_window {
+ struct xwl *xwl;
+ xcb_window_t id;
+ uint32_t host_surface_id;
+ int unpaired;
+ int x;
+ int y;
+ int mapped;
+ int override_redirect;
+ struct wl_shell_surface *shell_surface;
+ struct wl_list link;
+};
+
+enum {
+ ATOM_WM_S0,
+ ATOM_WM_PROTOCOLS,
+ ATOM_WM_DELETE_WINDOW,
+ ATOM_WL_SURFACE_ID,
+ ATOM_LAST = ATOM_WL_SURFACE_ID,
+};
+
+struct xwl {
+ pthread_barrier_t *barrier;
+ struct wl_display *display;
+ struct wl_display *host_display;
+ struct wl_client *client;
+ struct xwl_compositor* compositor;
+ struct xwl_shm* shm;
+ struct xwl_shell* shell;
+ struct wl_list outputs;
+ struct wl_list seats;
+ struct wl_event_source *display_event_source;
+ int wm_fd;
+ xcb_connection_t *connection;
+ xcb_screen_t *screen;
+ xcb_window_t window;
+ struct wl_list windows, unpaired_windows;
+ struct xwl_window *host_focus_window;
+ xcb_window_t focus_window;
+ int32_t scale;
+ union {
+ const char *name;
+ xcb_intern_atom_cookie_t cookie;
+ xcb_atom_t value;
+ } atoms[ATOM_LAST + 1];
+};
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static void
+xwl_shell_surface_ping(void *data,
+ struct wl_shell_surface *shell_surface,
+ uint32_t serial)
+{
+ struct xwl_window *window = wl_shell_surface_get_user_data(shell_surface);
+
+ if (getenv("_AWT_XWAYLAND_SEND_DELETE_ON_PING") != NULL) {
+ xcb_client_message_event_t event = {
+ .response_type = XCB_CLIENT_MESSAGE,
+ .format = 32,
+ .window = window->id,
+ .type = window->xwl->atoms[ATOM_WM_PROTOCOLS].value,
+ .data.data32 = {
+ window->xwl->atoms[ATOM_WM_DELETE_WINDOW].value,
+ XCB_CURRENT_TIME,
+ },
+ };
+
+ xcb_send_event(window->xwl->connection,
+ 0,
+ window->id,
+ XCB_EVENT_MASK_NO_EVENT,
+ (const char *) &event);
+ }
+}
+
+static void
+xwl_shell_surface_configure(void *data,
+ struct wl_shell_surface *shell_surface,
+ uint32_t edges,
+ int32_t width,
+ int32_t height)
+{
+ struct xwl_window *window = wl_shell_surface_get_user_data(shell_surface);
+ int32_t scale = window->xwl->scale;
+ uint32_t mask, values[2];
+
+ mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
+ values[0] = width * scale;
+ values[1] = height * scale;
+
+ xcb_configure_window(window->xwl->connection, window->id, mask, values);
+}
+
+static void
+xwl_shell_surface_popup_done(void *data,
+ struct wl_shell_surface *shell_surface)
+{
+}
+
+static const struct wl_shell_surface_listener xwl_shell_surface_listener = {
+ xwl_shell_surface_ping,
+ xwl_shell_surface_configure,
+ xwl_shell_surface_popup_done
+};
+
+static void
+xwl_window_update(struct xwl_window *window)
+{
+ struct wl_resource *host_resource = NULL;
+ struct xwl_host_surface *host_surface;
+ struct wl_surface *surface;
+ struct xwl *xwl = window->xwl;
+ struct xwl_window *parent = NULL;
+ xcb_window_t parent_window = 0;
+ uint32_t flags = 0;
+
+ if (window->host_surface_id) {
+ host_resource = wl_client_get_object(xwl->client,
+ window->host_surface_id);
+ if (host_resource && window->unpaired) {
+ wl_list_remove(&window->link);
+ wl_list_insert(&xwl->windows, &window->link);
+ window->unpaired = 0;
+ }
+ } else if (!window->unpaired) {
+ wl_list_remove(&window->link);
+ wl_list_insert(&xwl->unpaired_windows, &window->link);
+ window->unpaired = 1;
+ }
+
+ if (!window->mapped) {
+ if (window->shell_surface) {
+ wl_shell_surface_destroy(window->shell_surface);
+ window->shell_surface = NULL;
+ }
+ return;
+ }
+
+ if (window->shell_surface)
+ return;
+
+ if (!host_resource)
+ return;
+
+ host_surface = wl_resource_get_user_data(host_resource);
+ assert(host_surface);
+
+ assert(xwl->shell);
+ assert(xwl->shell->internal);
+
+ if (window->override_redirect) {
+ parent_window = xwl->focus_window;
+ flags = WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
+ } else {
+ xcb_get_property_reply_t *reply =
+ xcb_get_property_reply(xwl->connection,
+ xcb_get_property(xwl->connection,
+ 0,
+ window->id,
+ XCB_ATOM_WM_TRANSIENT_FOR,
+ XCB_ATOM_WINDOW,
+ 0,
+ 1),
+ NULL);
+ if (reply)
+ parent_window = *((uint32_t *) xcb_get_property_value(reply));
+ }
+
+ if (parent_window) {
+ struct xwl_window *sibling;
+
+ wl_list_for_each(sibling, &xwl->windows, link) {
+ if (sibling->id == parent_window) {
+ parent = sibling;
+ break;
+ }
+ }
+ }
+
+ window->shell_surface = wl_shell_get_shell_surface(xwl->shell->internal,
+ host_surface->proxy);
+ wl_shell_surface_set_user_data(window->shell_surface, window);
+ wl_shell_surface_add_listener(window->shell_surface,
+ &xwl_shell_surface_listener,
+ window);
+
+ if (parent) {
+ struct wl_resource *parent_resource =
+ wl_client_get_object(xwl->client, parent->host_surface_id);
+ struct xwl_host_surface *parent_host_surface =
+ wl_resource_get_user_data(parent_resource);
+
+ wl_shell_surface_set_transient(window->shell_surface,
+ parent_host_surface->proxy,
+ (window->x - parent->x) / xwl->scale,
+ (window->y - parent->y) / xwl->scale,
+ flags);
+ } else {
+ wl_shell_surface_set_toplevel(window->shell_surface);
+ }
+
+ if (host_surface->has_contents)
+ wl_surface_commit(host_surface->proxy);
+}
+
+static void
+xwl_host_surface_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+xwl_host_surface_attach(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *buffer_resource,
+ int32_t x,
+ int32_t y)
+{
+ struct xwl_host_surface *host = wl_resource_get_user_data(resource);
+ struct xwl_host_buffer *host_buffer = wl_resource_get_user_data(
+ buffer_resource);
+ int32_t scale = host->compositor->xwl->scale;
+
+ wl_surface_attach(host->proxy, host_buffer->proxy, x / scale, y / scale);
+ wl_surface_set_buffer_scale(host->proxy, scale);
+}
+
+static void
+xwl_host_surface_damage(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height)
+{
+ struct xwl_host_surface *host = wl_resource_get_user_data(resource);
+ int32_t scale = host->compositor->xwl->scale;
+ int32_t x1, y1, x2, y2;
+
+ // Round to enclosing rect.
+ x1 = x / scale;
+ y1 = y / scale;
+ x2 = (x + width + scale - 1) / scale;
+ y2 = (y + height + scale - 1) / scale;
+
+ wl_surface_damage(host->proxy, x1, y1, x2 - x1, y2 - y1);
+}
+
+static void
+xwl_frame_callback_done(void *data,
+ struct wl_callback *callback,
+ uint32_t time)
+{
+ struct xwl_host_callback *host = wl_callback_get_user_data(callback);
+
+ wl_callback_send_done(host->resource, time);
+}
+
+static const struct wl_callback_listener xwl_frame_callback_listener = {
+ xwl_frame_callback_done
+};
+
+static void
+xwl_host_callback_destroy(struct wl_resource *resource)
+{
+ struct xwl_host_callback *host = wl_resource_get_user_data(resource);
+
+ wl_callback_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_host_surface_frame(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t callback)
+{
+ struct xwl_host_surface *host = wl_resource_get_user_data(resource);
+ struct xwl_host_callback *host_callback;
+
+ host_callback = malloc(sizeof(*host_callback));
+ assert(host_callback);
+
+ host_callback->resource = wl_resource_create(client,
+ &wl_callback_interface,
+ 1,
+ callback);
+ wl_resource_set_implementation(host_callback->resource,
+ NULL,
+ host_callback,
+ xwl_host_callback_destroy);
+ host_callback->proxy = wl_surface_frame(host->proxy);
+ wl_callback_set_user_data(host_callback->proxy, host_callback);
+ wl_callback_add_listener(host_callback->proxy,
+ &xwl_frame_callback_listener,
+ host_callback);
+}
+
+static void
+xwl_host_surface_set_opaque_region(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *region_resource)
+{
+ /* Not implemented */
+ wl_resource_post_no_memory(resource);
+}
+
+static void
+xwl_host_surface_set_input_region(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *region_resource)
+{
+ /* Not implemented */
+ wl_resource_post_no_memory(resource);
+}
+
+static void
+xwl_host_surface_commit(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct xwl_host_surface *host = wl_resource_get_user_data(resource);
+
+ wl_surface_commit(host->proxy);
+ host->has_contents = 1;
+}
+
+static void
+xwl_host_surface_set_buffer_transform(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t transform)
+{
+ /* Not implemented */
+ wl_resource_post_no_memory(resource);
+}
+
+static void
+xwl_host_surface_set_buffer_scale(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t scale)
+{
+ /* Not implemented */
+ wl_resource_post_no_memory(resource);
+}
+
+#ifdef WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION
+static void
+xwl_host_surface_damage_buffer(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height)
+{
+ /* Not implemented */
+ wl_resource_post_no_memory(resource);
+}
+#endif
+
+static const struct wl_surface_interface xwl_surface_implementation = {
+ xwl_host_surface_destroy,
+ xwl_host_surface_attach,
+ xwl_host_surface_damage,
+ xwl_host_surface_frame,
+ xwl_host_surface_set_opaque_region,
+ xwl_host_surface_set_input_region,
+ xwl_host_surface_commit,
+ xwl_host_surface_set_buffer_transform,
+ xwl_host_surface_set_buffer_scale,
+#ifdef WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION
+ xwl_host_surface_damage_buffer
+#endif
+};
+
+static void
+xwl_destroy_host_surface(struct wl_resource *resource)
+{
+ struct xwl_host_surface *host = wl_resource_get_user_data(resource);
+ struct xwl_window *window;
+
+ wl_list_for_each(window, &host->compositor->xwl->windows, link) {
+ if (window->host_surface_id == wl_resource_get_id(resource)) {
+ window->host_surface_id = 0;
+ xwl_window_update(window);
+ break;
+ }
+ }
+
+ wl_surface_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_compositor_create_host_surface(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ struct xwl_host_compositor *host = wl_resource_get_user_data(resource);
+ struct xwl_host_surface *host_surface;
+ struct xwl_window *window;
+
+ host_surface = malloc(sizeof(*host_surface));
+ assert(host_surface);
+
+ host_surface->compositor = host->compositor;
+ host_surface->has_contents = 0;
+ host_surface->resource = wl_resource_create(
+ client,
+ &wl_surface_interface,
+ wl_resource_get_version(resource),
+ id);
+ wl_resource_set_implementation(host_surface->resource,
+ &xwl_surface_implementation,
+ host_surface,
+ xwl_destroy_host_surface);
+ host_surface->proxy = wl_compositor_create_surface(host->proxy);
+ wl_surface_set_user_data(host_surface->proxy, host_surface);
+
+ wl_list_for_each(window, &host->compositor->xwl->unpaired_windows, link) {
+ if (window->host_surface_id == id) {
+ xwl_window_update(window);
+ break;
+ }
+ }
+}
+
+static void
+xwl_compositor_create_host_region(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ /* Not implemented */
+ wl_resource_post_no_memory(resource);
+}
+
+static const struct wl_compositor_interface xwl_compositor_implementation = {
+ xwl_compositor_create_host_surface,
+ xwl_compositor_create_host_region
+};
+
+static void
+xwl_destroy_host_compositor(struct wl_resource *resource)
+{
+ struct xwl_host_compositor *host = wl_resource_get_user_data(resource);
+
+ wl_compositor_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_bind_host_compositor(struct wl_client *client,
+ void *data,
+ uint32_t version,
+ uint32_t id)
+{
+ struct xwl_compositor* compositor = (struct xwl_compositor *) data;
+ struct xwl_host_compositor *host;
+
+ host = malloc(sizeof(*host));
+ assert(host);
+ host->compositor = compositor;
+ host->resource = wl_resource_create(client,
+ &wl_compositor_interface,
+ MIN(version, compositor->version),
+ id);
+ wl_resource_set_implementation(host->resource,
+ &xwl_compositor_implementation,
+ host,
+ xwl_destroy_host_compositor);
+ host->proxy = wl_registry_bind(
+ wl_display_get_registry(compositor->xwl->display),
+ compositor->id,
+ &wl_compositor_interface,
+ compositor->version);
+ wl_compositor_set_user_data(host->proxy, host);
+}
+
+static void
+xwl_host_buffer_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_buffer_interface xwl_buffer_implementation = {
+ xwl_host_buffer_destroy
+};
+
+static void
+xwl_buffer_release(void *data,
+ struct wl_buffer *buffer)
+{
+ struct xwl_host_buffer *host = wl_buffer_get_user_data(buffer);
+
+ wl_buffer_send_release(host->resource);
+}
+
+static const struct wl_buffer_listener xwl_buffer_listener = {
+ xwl_buffer_release
+};
+
+static void
+xwl_destroy_host_buffer(struct wl_resource *resource)
+{
+ struct xwl_host_buffer *host = wl_resource_get_user_data(resource);
+
+ wl_buffer_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_host_shm_pool_create_host_buffer(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ int32_t offset,
+ int32_t width,
+ int32_t height,
+ int32_t stride,
+ uint32_t format)
+{
+ struct xwl_host_shm_pool *host = wl_resource_get_user_data(resource);
+ struct xwl_host_buffer *host_buffer;
+
+ host_buffer = malloc(sizeof(*host_buffer));
+ assert(host_buffer);
+
+ host_buffer->resource = wl_resource_create(client,
+ &wl_buffer_interface,
+ 1,
+ id);
+ wl_resource_set_implementation(host_buffer->resource,
+ &xwl_buffer_implementation,
+ host_buffer,
+ xwl_destroy_host_buffer);
+ host_buffer->proxy = wl_shm_pool_create_buffer(host->proxy,
+ offset,
+ width,
+ height,
+ stride,
+ format);
+ wl_buffer_set_user_data(host_buffer->proxy, host_buffer);
+ wl_buffer_add_listener(host_buffer->proxy,
+ &xwl_buffer_listener,
+ host_buffer);
+}
+
+static void
+xwl_host_shm_pool_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+xwl_host_shm_pool_resize(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t size)
+{
+ struct xwl_host_shm_pool *host = wl_resource_get_user_data(resource);
+
+ wl_shm_pool_resize(host->proxy, size);
+}
+
+static const struct wl_shm_pool_interface xwl_shm_pool_implementation = {
+ xwl_host_shm_pool_create_host_buffer,
+ xwl_host_shm_pool_destroy,
+ xwl_host_shm_pool_resize
+};
+
+static void
+xwl_destroy_host_shm_pool(struct wl_resource *resource)
+{
+ struct xwl_host_shm_pool *host = wl_resource_get_user_data(resource);
+
+ wl_shm_pool_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_shm_create_host_pool(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ int fd,
+ int32_t size)
+{
+ struct xwl_host_shm *host = wl_resource_get_user_data(resource);
+ struct xwl_host_shm_pool *host_shm_pool;
+
+ host_shm_pool = malloc(sizeof(*host_shm_pool));
+ assert(host_shm_pool);
+
+ host_shm_pool->resource = wl_resource_create(client,
+ &wl_shm_pool_interface,
+ 1,
+ id);
+ wl_resource_set_implementation(host_shm_pool->resource,
+ &xwl_shm_pool_implementation,
+ host_shm_pool,
+ xwl_destroy_host_shm_pool);
+ host_shm_pool->proxy = wl_shm_create_pool(host->proxy, fd, size);
+ wl_shm_pool_set_user_data(host_shm_pool->proxy, host_shm_pool);
+
+ close(fd);
+}
+
+static const struct wl_shm_interface xwl_shm_implementation = {
+ xwl_shm_create_host_pool
+};
+
+static void
+xwl_destroy_host_shm(struct wl_resource *resource)
+{
+ struct xwl_host_shm *host = wl_resource_get_user_data(resource);
+
+ wl_shm_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_bind_host_shm(struct wl_client *client,
+ void *data,
+ uint32_t version,
+ uint32_t id)
+{
+ struct xwl_shm* shm = (struct xwl_shm *) data;
+ struct xwl_host_shm *host;
+
+ host = malloc(sizeof(*host));
+ assert(host);
+ host->shm = shm;
+ host->resource = wl_resource_create(client,
+ &wl_shm_interface,
+ 1,
+ id);
+ wl_resource_set_implementation(host->resource,
+ &xwl_shm_implementation,
+ host,
+ xwl_destroy_host_shm);
+ host->proxy = wl_registry_bind(wl_display_get_registry(shm->xwl->display),
+ shm->id,
+ &wl_shm_interface,
+ wl_resource_get_version(host->resource));
+ wl_shm_set_user_data(host->proxy, host);
+}
+
+static void
+xwl_host_shell_get_host_shell_surface(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface_resource)
+{
+ /* Not implemented */
+ wl_resource_post_no_memory(resource);
+}
+
+static const struct wl_shell_interface xwl_shell_implementation = {
+ xwl_host_shell_get_host_shell_surface
+};
+
+static void
+xwl_destroy_host_shell(struct wl_resource *resource)
+{
+ struct xwl_host_shell *host = wl_resource_get_user_data(resource);
+
+ wl_shell_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_bind_host_shell(struct wl_client *client,
+ void *data,
+ uint32_t version,
+ uint32_t id)
+{
+ struct xwl_shell* shell = (struct xwl_shell *) data;
+ struct xwl_host_shell *host;
+
+ host = malloc(sizeof(*host));
+ assert(host);
+ host->shell = shell;
+ host->resource = wl_resource_create(client,
+ &wl_shell_interface,
+ 1,
+ id);
+ wl_resource_set_implementation(host->resource,
+ &xwl_shell_implementation,
+ host,
+ xwl_destroy_host_shell);
+ host->proxy = wl_registry_bind(wl_display_get_registry(shell->xwl->display),
+ shell->id,
+ &wl_shell_interface,
+ wl_resource_get_version(host->resource));
+ wl_shell_set_user_data(host->proxy, host);
+}
+
+static void
+xwl_output_geometry(void *data,
+ struct wl_output *output,
+ int x,
+ int y,
+ int physical_width,
+ int physical_height,
+ int subpixel,
+ const char *make,
+ const char *model,
+ int transform)
+{
+ struct xwl_host_output *host = wl_output_get_user_data(output);
+
+ wl_output_send_geometry(host->resource,
+ x,
+ y,
+ physical_width,
+ physical_height,
+ subpixel,
+ make,
+ model,
+ transform);
+}
+
+static void
+xwl_output_mode(void *data,
+ struct wl_output *output,
+ uint32_t flags,
+ int width,
+ int height,
+ int refresh)
+{
+ struct xwl_host_output *host = wl_output_get_user_data(output);
+
+ wl_output_send_mode(host->resource, flags, width, height, refresh);
+}
+
+static void
+xwl_output_done(void *data,
+ struct wl_output *output)
+{
+ struct xwl_host_output *host = wl_output_get_user_data(output);
+
+ wl_output_send_done(host->resource);
+}
+
+static void
+xwl_output_scale(void *data,
+ struct wl_output *output,
+ int32_t scale)
+{
+ struct xwl_host_output *host = wl_output_get_user_data(output);
+
+ // Always 1 as device scale factor is emulated.
+ wl_output_send_scale(host->resource, 1);
+}
+
+static const struct wl_output_listener xwl_output_listener = {
+ xwl_output_geometry,
+ xwl_output_mode,
+ xwl_output_done,
+ xwl_output_scale
+};
+
+static void
+xwl_destroy_host_output(struct wl_resource *resource)
+{
+ struct xwl_host_output *host = wl_resource_get_user_data(resource);
+
+ wl_output_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_bind_host_output(struct wl_client *client,
+ void *data,
+ uint32_t version,
+ uint32_t id)
+{
+ struct xwl_output* output = (struct xwl_output *) data;
+ struct xwl_host_output *host;
+
+ host = malloc(sizeof(*host));
+ assert(host);
+ host->output = output;
+ host->resource = wl_resource_create(client,
+ &wl_output_interface,
+ MIN(version, output->version),
+ id);
+ wl_resource_set_implementation(host->resource,
+ NULL,
+ host,
+ xwl_destroy_host_output);
+ host->proxy = wl_registry_bind(
+ wl_display_get_registry(output->xwl->display),
+ output->id,
+ &wl_output_interface,
+ wl_resource_get_version(host->resource));
+ wl_output_set_user_data(host->proxy, host);
+ wl_output_add_listener(host->proxy, &xwl_output_listener, host);
+}
+
+static void
+xwl_host_pointer_set_cursor(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial,
+ struct wl_resource *surface_resource,
+ int32_t hotspot_x,
+ int32_t hotspot_y)
+{
+ struct xwl_host_pointer *host = wl_resource_get_user_data(resource);
+ struct xwl_host_surface *host_surface = NULL;
+ int32_t scale = host->seat->xwl->scale;
+
+ if (surface_resource)
+ host_surface = wl_resource_get_user_data(surface_resource);
+
+ wl_pointer_set_cursor(host->proxy,
+ serial,
+ host_surface ? host_surface->proxy : NULL,
+ hotspot_x / scale,
+ hotspot_y / scale);
+}
+
+static void
+xwl_host_pointer_release(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_pointer_interface xwl_pointer_implementation = {
+ xwl_host_pointer_set_cursor,
+ xwl_host_pointer_release
+};
+
+static void
+xwl_pointer_enter(void *data,
+ struct wl_pointer *pointer,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+ struct xwl_host_surface *host_surface = wl_surface_get_user_data(surface);
+ int32_t scale = host->seat->xwl->scale;
+
+ wl_pointer_send_enter(host->resource,
+ serial,
+ host_surface->resource,
+ x * scale,
+ y * scale);
+}
+
+static void
+xwl_pointer_leave(void *data,
+ struct wl_pointer *pointer,
+ uint32_t serial,
+ struct wl_surface *surface)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+ struct xwl_host_surface *host_surface =
+ surface ? wl_surface_get_user_data(surface) : NULL;
+
+ if (!host_surface)
+ return;
+
+ wl_pointer_send_leave(host->resource, serial, host_surface->resource);
+}
+
+static void
+xwl_pointer_motion(void *data,
+ struct wl_pointer *pointer,
+ uint32_t time,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+ int32_t scale = host->seat->xwl->scale;
+
+ wl_pointer_send_motion(host->resource, time, x * scale, y * scale);
+}
+
+static void
+xwl_pointer_button(void *data,
+ struct wl_pointer *pointer,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t button,
+ uint32_t state)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+
+ wl_pointer_send_button(host->resource,
+ serial,
+ time,
+ button,
+ state);
+}
+
+static void
+xwl_pointer_axis(void *data,
+ struct wl_pointer *pointer,
+ uint32_t time,
+ uint32_t axis,
+ wl_fixed_t value)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+ int32_t scale = host->seat->xwl->scale;
+
+ wl_pointer_send_axis(host->resource, time, axis, value * scale);
+}
+
+#ifdef WL_POINTER_FRAME_SINCE_VERSION
+static void
+xwl_pointer_frame(void *data,
+ struct wl_pointer *pointer)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+
+ wl_pointer_send_frame(host->resource);
+}
+#endif
+
+#ifdef WL_POINTER_AXIS_SOURCE_SINCE_VERSION
+void
+xwl_pointer_axis_source(void *data,
+ struct wl_pointer *pointer,
+ uint32_t axis_source)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+
+ wl_pointer_send_axis_source(host->resource, axis_source);
+}
+#endif
+
+#ifdef WL_POINTER_AXIS_STOP_SINCE_VERSION
+static void
+xwl_pointer_axis_stop(void *data,
+ struct wl_pointer *pointer,
+ uint32_t time,
+ uint32_t axis)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+
+ wl_pointer_send_axis_stop(host->resource, time, axis);
+}
+#endif
+
+#ifdef WL_POINTER_AXIS_DISCRETE_SINCE_VERSION
+static void
+xwl_pointer_axis_discrete(void *data,
+ struct wl_pointer *pointer,
+ uint32_t axis,
+ int32_t discrete)
+{
+ struct xwl_host_pointer *host = wl_pointer_get_user_data(pointer);
+
+ wl_pointer_send_axis_discrete(host->resource, axis, discrete);
+}
+#endif
+
+static const struct wl_pointer_listener xwl_pointer_listener = {
+ xwl_pointer_enter,
+ xwl_pointer_leave,
+ xwl_pointer_motion,
+ xwl_pointer_button,
+ xwl_pointer_axis,
+#ifdef WL_POINTER_FRAME_SINCE_VERSION
+ xwl_pointer_frame,
+#endif
+#ifdef WL_POINTER_AXIS_SOURCE_SINCE_VERSION
+ xwl_pointer_axis_source,
+#endif
+#ifdef WL_POINTER_AXIS_DISCRETE_SINCE_VERSION
+ xwl_pointer_axis_stop,
+#endif
+#ifdef WL_POINTER_AXIS_DISCRETE_SINCE_VERSION
+ xwl_pointer_axis_discrete
+#endif
+};
+
+static void
+xwl_host_keyboard_release(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_keyboard_interface xwl_keyboard_implementation = {
+ xwl_host_keyboard_release
+};
+
+static void
+xwl_keyboard_keymap(void *data,
+ struct wl_keyboard *keyboard,
+ uint32_t format,
+ int32_t fd,
+ uint32_t size)
+{
+ struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
+
+ wl_keyboard_send_keymap(host->resource, format, fd, size);
+
+ close(fd);
+}
+
+static void
+xwl_keyboard_enter(void *data,
+ struct wl_keyboard *keyboard,
+ uint32_t serial,
+ struct wl_surface *surface,
+ struct wl_array *keys)
+{
+ struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
+ struct xwl_host_surface *host_surface = wl_surface_get_user_data(surface);
+ struct xwl *xwl = host->seat->xwl;
+ struct xwl_window *window;
+
+ wl_keyboard_send_enter(host->resource,
+ serial,
+ host_surface->resource,
+ keys);
+
+ wl_list_for_each(window, &xwl->windows, link) {
+ uint32_t host_resource_id = wl_resource_get_id(host_surface->resource);
+ if (window->host_surface_id == host_resource_id) {
+ uint32_t values[1];
+
+ xwl->host_focus_window = window;
+
+ if (window->override_redirect)
+ return;
+
+ xcb_set_input_focus(xwl->connection,
+ XCB_INPUT_FOCUS_NONE,
+ window->id,
+ XCB_CURRENT_TIME);
+ values[0] = XCB_STACK_MODE_ABOVE;
+ xcb_configure_window(xwl->connection,
+ window->id,
+ XCB_CONFIG_WINDOW_STACK_MODE,
+ values);
+ return;
+ }
+ }
+}
+
+static void
+xwl_keyboard_leave(void *data,
+ struct wl_keyboard *keyboard,
+ uint32_t serial,
+ struct wl_surface *surface)
+{
+ struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
+ struct xwl_host_surface *host_surface =
+ surface ? wl_surface_get_user_data(surface) : NULL;
+ struct xwl *xwl = host->seat->xwl;
+
+ if (!host_surface)
+ return;
+
+ wl_keyboard_send_leave(host->resource, serial, host_surface->resource);
+
+ if (xwl->host_focus_window) {
+ uint32_t host_resource_id = wl_resource_get_id(host_surface->resource);
+ if (xwl->host_focus_window->host_surface_id == host_resource_id) {
+ xwl->host_focus_window = NULL;
+ xcb_set_input_focus(xwl->connection,
+ XCB_INPUT_FOCUS_NONE,
+ XCB_NONE,
+ XCB_CURRENT_TIME);
+ }
+ }
+}
+
+static void
+xwl_keyboard_key(void *data,
+ struct wl_keyboard *keyboard,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t key,
+ uint32_t state)
+{
+ struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
+
+ wl_keyboard_send_key(host->resource,
+ serial,
+ time,
+ key,
+ state);
+}
+
+static void
+xwl_keyboard_modifiers(void *data,
+ struct wl_keyboard *keyboard,
+ uint32_t serial,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
+{
+ struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
+
+ wl_keyboard_send_modifiers(host->resource,
+ serial,
+ mods_depressed,
+ mods_latched,
+ mods_locked,
+ group);
+}
+
+#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
+static void
+xwl_keyboard_repeat_info(void *data,
+ struct wl_keyboard *keyboard,
+ int32_t rate,
+ int32_t delay)
+{
+ struct xwl_host_keyboard *host = wl_keyboard_get_user_data(keyboard);
+
+ wl_keyboard_send_repeat_info(host->resource, rate, delay);
+}
+#endif
+
+static const struct wl_keyboard_listener xwl_keyboard_listener = {
+ xwl_keyboard_keymap,
+ xwl_keyboard_enter,
+ xwl_keyboard_leave,
+ xwl_keyboard_key,
+ xwl_keyboard_modifiers,
+#ifdef WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION
+ xwl_keyboard_repeat_info
+#endif
+};
+
+static void
+xwl_host_touch_release(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_touch_interface xwl_touch_implementation = {
+ xwl_host_touch_release
+};
+
+static void
+xwl_host_touch_down(void *data,
+ struct wl_touch *touch,
+ uint32_t serial,
+ uint32_t time,
+ struct wl_surface *surface,
+ int32_t id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct xwl_host_touch *host = wl_touch_get_user_data(touch);
+ struct xwl_host_surface *host_surface = wl_surface_get_user_data(surface);
+ int32_t scale = host->seat->xwl->scale;
+
+ wl_touch_send_down(host->resource,
+ serial,
+ time,
+ host_surface->resource,
+ id,
+ x * scale,
+ y * scale);
+}
+
+static void
+xwl_host_touch_up(void *data,
+ struct wl_touch *touch,
+ uint32_t serial,
+ uint32_t time,
+ int32_t id)
+{
+ struct xwl_host_touch *host = wl_touch_get_user_data(touch);
+
+ wl_touch_send_up(host->resource, serial, time, id);
+}
+
+static void
+xwl_host_touch_motion(void *data,
+ struct wl_touch *touch,
+ uint32_t time,
+ int32_t id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct xwl_host_touch *host = wl_touch_get_user_data(touch);
+ int32_t scale = host->seat->xwl->scale;
+
+ wl_touch_send_motion(host->resource, time, id, x * scale, y * scale);
+}
+
+static void
+xwl_host_touch_frame(void *data,
+ struct wl_touch *touch)
+{
+ struct xwl_host_touch *host = wl_touch_get_user_data(touch);
+
+ wl_touch_send_frame(host->resource);
+}
+
+static void
+xwl_host_touch_cancel(void *data,
+ struct wl_touch *touch)
+{
+ struct xwl_host_touch *host = wl_touch_get_user_data(touch);
+
+ wl_touch_send_cancel(host->resource);
+}
+
+static const struct wl_touch_listener xwl_touch_listener = {
+ xwl_host_touch_down,
+ xwl_host_touch_up,
+ xwl_host_touch_motion,
+ xwl_host_touch_frame,
+ xwl_host_touch_cancel
+};
+
+static void
+xwl_destroy_host_pointer(struct wl_resource *resource)
+{
+ struct xwl_host_pointer *host = wl_resource_get_user_data(resource);
+
+ wl_pointer_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_host_seat_get_host_pointer(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ struct xwl_host_seat *host = wl_resource_get_user_data(resource);
+ struct xwl_host_pointer *host_pointer;
+
+ host_pointer = malloc(sizeof(*host_pointer));
+ assert(host_pointer);
+
+ host_pointer->seat = host->seat;
+ host_pointer->resource = wl_resource_create(
+ client,
+ &wl_pointer_interface,
+ wl_resource_get_version(resource),
+ id);
+ wl_resource_set_implementation(host_pointer->resource,
+ &xwl_pointer_implementation,
+ host_pointer,
+ xwl_destroy_host_pointer);
+ host_pointer->proxy = wl_seat_get_pointer(host->proxy);
+ wl_pointer_set_user_data(host_pointer->proxy, host_pointer);
+ wl_pointer_add_listener(host_pointer->proxy,
+ &xwl_pointer_listener,
+ host_pointer);
+}
+
+static void
+xwl_destroy_host_keyboard(struct wl_resource *resource)
+{
+ struct xwl_host_keyboard *host = wl_resource_get_user_data(resource);
+
+ wl_keyboard_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_host_seat_get_host_keyboard(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ struct xwl_host_seat *host = wl_resource_get_user_data(resource);
+ struct xwl_host_keyboard *host_keyboard;
+
+ host_keyboard = malloc(sizeof(*host_keyboard));
+ assert(host_keyboard);
+
+ host_keyboard->seat = host->seat;
+ host_keyboard->resource = wl_resource_create(
+ client,
+ &wl_keyboard_interface,
+ wl_resource_get_version(resource),
+ id);
+ wl_resource_set_implementation(host_keyboard->resource,
+ &xwl_keyboard_implementation,
+ host_keyboard,
+ xwl_destroy_host_keyboard);
+ host_keyboard->proxy = wl_seat_get_keyboard(host->proxy);
+ wl_keyboard_set_user_data(host_keyboard->proxy, host_keyboard);
+ wl_keyboard_add_listener(host_keyboard->proxy,
+ &xwl_keyboard_listener,
+ host_keyboard);
+}
+
+static void
+xwl_destroy_host_touch(struct wl_resource *resource)
+{
+ struct xwl_host_touch *host = wl_resource_get_user_data(resource);
+
+ wl_touch_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_host_seat_get_host_touch(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ struct xwl_host_seat *host = wl_resource_get_user_data(resource);
+ struct xwl_host_touch *host_touch;
+
+ host_touch = malloc(sizeof(*host_touch));
+ assert(host_touch);
+
+ host_touch->seat = host->seat;
+ host_touch->resource = wl_resource_create(client,
+ &wl_touch_interface,
+ wl_resource_get_version(resource),
+ id);
+ wl_resource_set_implementation(host_touch->resource,
+ &xwl_touch_implementation,
+ host_touch,
+ xwl_destroy_host_touch);
+ host_touch->proxy = wl_seat_get_touch(host->proxy);
+ wl_touch_set_user_data(host_touch->proxy, host_touch);
+ wl_touch_add_listener(host_touch->proxy, &xwl_touch_listener, host_touch);
+}
+
+#ifdef WL_SEAT_RELEASE_SINCE_VERSION
+static void
+xwl_host_seat_release(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct xwl_host_seat *host = wl_resource_get_user_data(resource);
+
+ wl_seat_release(host->proxy);
+}
+#endif
+
+static const struct wl_seat_interface xwl_seat_implementation = {
+ xwl_host_seat_get_host_pointer,
+ xwl_host_seat_get_host_keyboard,
+ xwl_host_seat_get_host_touch,
+#ifdef WL_SEAT_RELEASE_SINCE_VERSION
+ xwl_host_seat_release
+#endif
+};
+
+static void
+xwl_seat_capabilities(void *data,
+ struct wl_seat *seat,
+ uint32_t capabilities)
+{
+ struct xwl_host_seat *host = wl_seat_get_user_data(seat);
+
+ wl_seat_send_capabilities(host->resource, capabilities);
+}
+
+static void
+xwl_seat_name(void *data,
+ struct wl_seat *seat,
+ const char *name)
+{
+ struct xwl_host_seat *host = wl_seat_get_user_data(seat);
+
+ wl_seat_send_name(host->resource, name);
+}
+
+static const struct wl_seat_listener xwl_seat_listener = {
+ xwl_seat_capabilities,
+ xwl_seat_name
+};
+
+static void
+xwl_destroy_host_seat(struct wl_resource *resource)
+{
+ struct xwl_host_seat *host = wl_resource_get_user_data(resource);
+
+ wl_seat_destroy(host->proxy);
+ wl_resource_set_user_data(resource, NULL);
+ free(host);
+}
+
+static void
+xwl_bind_host_seat(struct wl_client *client,
+ void *data,
+ uint32_t version,
+ uint32_t id)
+{
+ struct xwl_seat* seat = (struct xwl_seat *) data;
+ struct xwl_host_seat *host;
+
+ host = malloc(sizeof(*host));
+ assert(host);
+ host->seat = seat;
+ host->resource = wl_resource_create(client,
+ &wl_seat_interface,
+ MIN(version, seat->version),
+ id);
+ wl_resource_set_implementation(host->resource,
+ &xwl_seat_implementation,
+ host,
+ xwl_destroy_host_seat);
+ host->proxy = wl_registry_bind(wl_display_get_registry(seat->xwl->display),
+ seat->id,
+ &wl_seat_interface,
+ wl_resource_get_version(host->resource));
+ wl_seat_set_user_data(host->proxy, host);
+ wl_seat_add_listener(host->proxy, &xwl_seat_listener, host);
+}
+
+static void
+xwl_registry_handler(void* data,
+ struct wl_registry *registry,
+ uint32_t id,
+ const char *interface,
+ uint32_t version)
+{
+ struct xwl *xwl = (struct xwl *) data;
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ struct xwl_compositor *compositor =
+ malloc(sizeof(struct xwl_compositor));
+ assert(compositor);
+ compositor->xwl = xwl;
+ compositor->id = id;
+ assert(version >= 3);
+ compositor->version = 3;
+ compositor->host_global = wl_global_create(xwl->host_display,
+ &wl_compositor_interface,
+ compositor->version,
+ compositor,
+ xwl_bind_host_compositor);
+ compositor->internal = wl_registry_bind(registry,
+ id,
+ &wl_shell_interface,
+ compositor->version);
+ assert(!xwl->compositor);
+ xwl->compositor = compositor;
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ struct xwl_shm *shm = malloc(sizeof(struct xwl_shm));
+ assert(shm);
+ shm->xwl = xwl;
+ shm->id = id;
+ shm->host_global = wl_global_create(xwl->host_display,
+ &wl_shm_interface,
+ 1,
+ shm,
+ xwl_bind_host_shm);
+ assert(!xwl->shm);
+ xwl->shm = shm;
+ } else if (strcmp(interface, "wl_shell") == 0) {
+ struct xwl_shell *shell = malloc(sizeof(struct xwl_shell));
+ assert(shell);
+ shell->xwl = xwl;
+ shell->id = id;
+ shell->host_global = wl_global_create(xwl->host_display,
+ &wl_shell_interface,
+ 1,
+ shell,
+ xwl_bind_host_shell);
+ shell->internal = wl_registry_bind(registry,
+ id,
+ &wl_shell_interface,
+ 1);
+ assert(!xwl->shell);
+ xwl->shell = shell;
+ } else if (strcmp(interface, "wl_output") == 0) {
+ struct xwl_output *output = malloc(sizeof(struct xwl_output));
+ assert(output);
+ output->xwl = xwl;
+ output->id = id;
+ output->version = MIN(2, version);
+ output->host_global = wl_global_create(xwl->host_display,
+ &wl_output_interface,
+ output->version,
+ output,
+ xwl_bind_host_output);
+ wl_list_insert(&xwl->outputs, &output->link);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ struct xwl_seat *seat = malloc(sizeof(struct xwl_seat));
+ assert(seat);
+ seat->xwl = xwl;
+ seat->id = id;
+#ifdef WL_POINTER_FRAME_SINCE_VERSION
+ seat->version = MIN(5, version);
+#else
+ seat->version = MIN(3, version);
+#endif
+ seat->host_global = wl_global_create(xwl->host_display,
+ &wl_seat_interface,
+ seat->version,
+ seat,
+ xwl_bind_host_seat);
+ wl_list_insert(&xwl->seats, &seat->link);
+ }
+}
+
+static void
+xwl_registry_remover(void *data,
+ struct wl_registry *registry,
+ uint32_t id)
+{
+ struct xwl *xwl = (struct xwl *) data;
+ struct xwl_output *output;
+ struct xwl_seat *seat;
+
+ if (xwl->compositor && xwl->compositor->id == id) {
+ wl_global_destroy(xwl->compositor->host_global);
+ wl_compositor_destroy(xwl->compositor->internal);
+ free(xwl->compositor);
+ xwl->compositor = NULL;
+ return;
+ }
+ if (xwl->shm && xwl->shm->id == id) {
+ wl_global_destroy(xwl->shm->host_global);
+ free(xwl->shm);
+ xwl->shm = NULL;
+ return;
+ }
+ if (xwl->shell && xwl->shell->id == id) {
+ wl_global_destroy(xwl->shell->host_global);
+ wl_shell_destroy(xwl->shell->internal);
+ free(xwl->shell);
+ xwl->shell = NULL;
+ return;
+ }
+ wl_list_for_each(output, &xwl->outputs, link) {
+ if (output->id == id) {
+ wl_global_destroy(output->host_global);
+ wl_list_remove(&output->link);
+ free(output);
+ return;
+ }
+ }
+ wl_list_for_each(seat, &xwl->seats, link) {
+ if (seat->id == id) {
+ wl_global_destroy(seat->host_global);
+ wl_list_remove(&seat->link);
+ free(seat);
+ return;
+ }
+ }
+
+ /* Not reached */
+ assert(0);
+}
+
+static const struct wl_registry_listener xwl_registry_listener = {
+ xwl_registry_handler,
+ xwl_registry_remover
+};
+
+static int
+xwl_handle_event(int fd,
+ uint32_t mask,
+ void *data)
+{
+ struct xwl *xwl = (struct xwl *) data;
+ int count = 0;
+
+ if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR))
+ return 0;
+
+ if (mask & WL_EVENT_READABLE)
+ count = wl_display_dispatch(xwl->display);
+ if (mask & WL_EVENT_WRITABLE)
+ wl_display_flush(xwl->display);
+
+ if (mask == 0) {
+ count = wl_display_dispatch_pending(xwl->display);
+ wl_display_flush(xwl->display);
+ }
+
+ return count;
+}
+
+static struct xwl_window *
+xwl_lookup_window(struct xwl* xwl,
+ xcb_window_t id)
+{
+ struct xwl_window *window;
+
+ wl_list_for_each(window, &xwl->windows, link) {
+ if (window->id == id)
+ return window;
+ }
+ wl_list_for_each(window, &xwl->unpaired_windows, link) {
+ if (window->id == id)
+ return window;
+ }
+ return NULL;
+}
+
+static void
+xwl_handle_create_notify(struct xwl *xwl,
+ xcb_create_notify_event_t *event)
+{
+ struct xwl_window *window = malloc(sizeof(struct xwl_window));
+ assert(window);
+ window->xwl = xwl;
+ window->id = event->window;
+ window->host_surface_id = 0;
+ window->unpaired = 1;
+ window->x = event->x;
+ window->y = event->y;
+ window->mapped = 0;
+ window->override_redirect = event->override_redirect;
+ window->shell_surface = NULL;
+ wl_list_insert(&xwl->unpaired_windows, &window->link);
+ if (!event->override_redirect) {
+ uint32_t values[1];
+
+ values[0] = XCB_EVENT_MASK_FOCUS_CHANGE;
+ xcb_change_window_attributes(xwl->connection,
+ window->id,
+ XCB_CW_EVENT_MASK,
+ values);
+ }
+}
+
+static void
+xwl_handle_destroy_notify(struct xwl *xwl,
+ xcb_destroy_notify_event_t *event)
+{
+ struct xwl_window *window = xwl_lookup_window(xwl, event->window);
+ if (window) {
+ if (xwl->host_focus_window == window)
+ xwl->host_focus_window = NULL;
+ if (xwl->focus_window == event->window)
+ xwl->focus_window = 0;
+ if (window->shell_surface)
+ wl_shell_surface_destroy(window->shell_surface);
+ wl_list_remove(&window->link);
+ free(window);
+ }
+}
+
+static void
+xwl_handle_map_request(struct xwl *xwl,
+ xcb_map_request_event_t *event)
+{
+ xcb_map_window(xwl->connection, event->window);
+}
+
+static void
+xwl_handle_map_notify(struct xwl *xwl,
+ xcb_map_notify_event_t *event)
+{
+ struct xwl_window *window = xwl_lookup_window(xwl, event->window);
+ if (window) {
+ assert(!window->mapped);
+ window->mapped = 1;
+ xwl_window_update(window);
+ }
+}
+
+static void
+xwl_handle_unmap_notify(struct xwl *xwl,
+ xcb_unmap_notify_event_t *event)
+{
+ struct xwl_window *window = xwl_lookup_window(xwl, event->window);
+ if (window) {
+ assert(window->mapped);
+ window->mapped = 0;
+ xwl_window_update(window);
+ }
+}
+
+static void
+xwl_handle_configure_request(struct xwl *xwl,
+ xcb_configure_request_event_t *event)
+{
+ uint32_t mask = 0, values[16];
+ int i = 0;
+
+ // Keep all managed windows centered horizontally.
+ if (event->value_mask & (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_WIDTH)) {
+ values[i++] = xwl->screen->width_in_pixels / 2 - event->width / 2;
+ mask |= XCB_CONFIG_WINDOW_X;
+ }
+ // Keep all managed windows centered vertically.
+ if (event->value_mask & (XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_HEIGHT)) {
+ values[i++] = xwl->screen->height_in_pixels / 2 - event->height / 2;
+ mask |= XCB_CONFIG_WINDOW_Y;
+ }
+ if (event->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
+ values[i++] = event->width;
+ mask |= XCB_CONFIG_WINDOW_WIDTH;
+ }
+ if (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
+ values[i++] = event->height;
+ mask |= XCB_CONFIG_WINDOW_HEIGHT;
+ }
+
+ xcb_configure_window(xwl->connection, event->window, mask, values);
+}
+
+static void
+xwl_handle_configure_notify(struct xwl *xwl,
+ xcb_configure_notify_event_t *event)
+{
+ struct xwl_window *window = xwl_lookup_window(xwl, event->window);
+ if (window) {
+ window->x = event->x;
+ window->y = event->y;
+ }
+}
+
+static void
+xwl_handle_client_message(struct xwl *xwl,
+ xcb_client_message_event_t *event)
+{
+ struct xwl_window *window;
+
+ if (event->type != xwl->atoms[ATOM_WL_SURFACE_ID].value)
+ return;
+
+ wl_list_for_each(window, &xwl->unpaired_windows, link) {
+ if (window->id == event->window) {
+ window->host_surface_id = event->data.data32[0];
+ xwl_window_update(window);
+ return;
+ }
+ }
+}
+
+static void
+xwl_handle_focus_in(struct xwl *xwl, xcb_focus_in_event_t *event)
+{
+ xwl->focus_window = event->event;
+}
+
+static void
+xwl_handle_focus_out(struct xwl *xwl, xcb_focus_out_event_t *event)
+{
+}
+
+static int
+xwl_handle_x_connection_event(int fd,
+ uint32_t mask,
+ void *data)
+{
+ struct xwl *xwl = (struct xwl *) data;
+ xcb_generic_event_t *event;
+ uint32_t count = 0;
+
+ if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR))
+ return 0;
+
+ while ((event = xcb_poll_for_event(xwl->connection))) {
+ switch (event->response_type & ~0x80) {
+ case XCB_CREATE_NOTIFY:
+ xwl_handle_create_notify(
+ xwl, (xcb_create_notify_event_t *) event);
+ break;
+ case XCB_DESTROY_NOTIFY:
+ xwl_handle_destroy_notify(
+ xwl, (xcb_destroy_notify_event_t *) event);
+ break;
+ case XCB_MAP_REQUEST:
+ xwl_handle_map_request(xwl,
+ (xcb_map_request_event_t *) event);
+ break;
+ case XCB_MAP_NOTIFY:
+ xwl_handle_map_notify(xwl,
+ (xcb_map_notify_event_t *) event);
+ break;
+ case XCB_UNMAP_NOTIFY:
+ xwl_handle_unmap_notify(xwl,
+ (xcb_unmap_notify_event_t *) event);
+ break;
+ case XCB_CONFIGURE_REQUEST:
+ xwl_handle_configure_request(
+ xwl, (xcb_configure_request_event_t *) event);
+ break;
+ case XCB_CONFIGURE_NOTIFY:
+ xwl_handle_configure_notify(
+ xwl, (xcb_configure_notify_event_t *) event);
+ break;
+ case XCB_CLIENT_MESSAGE:
+ xwl_handle_client_message(
+ xwl, (xcb_client_message_event_t *) event);
+ break;
+ case XCB_FOCUS_IN:
+ xwl_handle_focus_in(xwl, (xcb_focus_in_event_t *) event);
+ break;
+ case XCB_FOCUS_OUT:
+ xwl_handle_focus_out(xwl, (xcb_focus_out_event_t *) event);
+ break;
+ default:
+ break;
+ }
+ free(event);
+ ++count;
+ }
+
+ if ((mask & ~WL_EVENT_WRITABLE) == 0)
+ xcb_flush(xwl->connection);
+
+ return count;
+}
+
+static void
+xwl_connect(struct xwl *xwl)
+{
+ const xcb_setup_t *setup;
+ xcb_screen_iterator_t screen_iterator;
+ uint32_t values[1];
+ xcb_void_cookie_t change_attributes_cookie, redirect_subwindows_cookie;
+ xcb_generic_error_t *error;
+ xcb_intern_atom_reply_t *atom_reply;
+ const xcb_query_extension_reply_t *composite_extension;
+ unsigned i;
+
+ xwl->connection = xcb_connect_to_fd(xwl->wm_fd, NULL);
+ assert(!xcb_connection_has_error(xwl->connection));
+
+ xcb_prefetch_extension_data(xwl->connection, &xcb_composite_id);
+
+ for (i = 0; i < ARRAY_SIZE(xwl->atoms); ++i) {
+ const char *name = xwl->atoms[i].name;
+ xwl->atoms[i].cookie = xcb_intern_atom(xwl->connection,
+ 0,
+ strlen(name),
+ name);
+ }
+
+ setup = xcb_get_setup(xwl->connection);
+ screen_iterator = xcb_setup_roots_iterator(setup);
+ xwl->screen = screen_iterator.data;
+
+ /* Select for substructure redirect. */
+ values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
+ change_attributes_cookie = xcb_change_window_attributes(xwl->connection,
+ xwl->screen->root,
+ XCB_CW_EVENT_MASK,
+ values);
+
+ wl_event_loop_add_fd(wl_display_get_event_loop(xwl->host_display),
+ xcb_get_file_descriptor(xwl->connection),
+ WL_EVENT_READABLE,
+ &xwl_handle_x_connection_event,
+ xwl);
+
+ composite_extension = xcb_get_extension_data(xwl->connection,
+ &xcb_composite_id);
+ assert(composite_extension->present);
+
+ redirect_subwindows_cookie = xcb_composite_redirect_subwindows_checked(
+ xwl->connection, xwl->screen->root, XCB_COMPOSITE_REDIRECT_MANUAL);
+
+ /* Another window manager should not be running */
+ error = xcb_request_check(xwl->connection, change_attributes_cookie);
+ assert(!error);
+
+ /* Redirecting subwindows of root for compositing should have succeeded */
+ error = xcb_request_check(xwl->connection, redirect_subwindows_cookie);
+ assert(!error);
+
+ xwl->window = xcb_generate_id(xwl->connection);
+ xcb_create_window(xwl->connection, 0, xwl->window, xwl->screen->root,
+ 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
+ XCB_COPY_FROM_PARENT, 0, NULL);
+
+ for (i = 0; i < ARRAY_SIZE(xwl->atoms); ++i) {
+ atom_reply = xcb_intern_atom_reply(xwl->connection,
+ xwl->atoms[i].cookie,
+ &error);
+ assert(!error);
+ xwl->atoms[i].value = atom_reply->atom;
+ free(atom_reply);
+ }
+
+ xcb_set_selection_owner(xwl->connection,
+ xwl->window,
+ xwl->atoms[ATOM_WM_S0].value,
+ XCB_CURRENT_TIME);
+ xcb_set_input_focus(xwl->connection,
+ XCB_INPUT_FOCUS_NONE,
+ XCB_NONE,
+ XCB_CURRENT_TIME);
+}
+
+static int
+xwl_handle_display_event(int fd,
+ uint32_t mask,
+ void *data)
+{
+ struct xwl *xwl = (struct xwl *) data;
+ char display_name[9];
+ int bytes_read = 0;
+
+ if (!(mask & WL_EVENT_READABLE))
+ return 0;
+
+ display_name[0] = ':';
+ do {
+ int bytes_left = sizeof(display_name) - bytes_read - 1;
+ int bytes;
+
+ if (!bytes_left)
+ break;
+
+ bytes = read(fd, &display_name[bytes_read + 1], bytes_left);
+ if (!bytes)
+ break;
+
+ bytes_read += bytes;
+ } while (display_name[bytes_read] != '\n');
+
+ display_name[bytes_read] = '\0';
+ setenv("DISPLAY", display_name, 1);
+
+ xwl_connect(xwl);
+
+ wl_event_source_remove(xwl->display_event_source);
+ xwl->display_event_source = NULL;
+ close(fd);
+
+ pthread_barrier_wait(xwl->barrier);
+ return 1;
+}
+
+void
+xwayland_run(pthread_barrier_t *barrier)
+{
+ struct xwl xwl = {
+ .barrier = barrier,
+ .display = NULL,
+ .host_display = NULL,
+ .client = NULL,
+ .compositor = NULL,
+ .shm = NULL,
+ .shell = NULL,
+ .display_event_source = NULL,
+ .connection = NULL,
+ .screen = NULL,
+ .window = 0,
+ .host_focus_window = NULL,
+ .focus_window = 0,
+ .scale = 1,
+ .atoms = {
+ [ATOM_WM_S0] = {"WM_S0"},
+ [ATOM_WM_PROTOCOLS] = {"WM_PROTOCOLS"},
+ [ATOM_WM_DELETE_WINDOW] = {"WM_DELETE_WINDOW"},
+ [ATOM_WL_SURFACE_ID] = {"WL_SURFACE_ID"},
+ }
+ };
+ struct wl_event_loop *event_loop;
+ int sv[2], ds[2], wm[2];
+ pid_t pid;
+ int rv;
+
+ char *scale_str = getenv("_AWT_XWAYLAND_SCALE");
+ if (scale_str != NULL) {
+ xwl.scale = atoi(scale_str);
+ assert(xwl.scale >= 1);
+ }
+
+ xwl.display = wl_display_connect(NULL);
+ assert(!xwl.display);
+
+ wl_list_init(&xwl.outputs);
+ wl_list_init(&xwl.seats);
+ wl_list_init(&xwl.windows);
+ wl_list_init(&xwl.unpaired_windows);
+
+ xwl.host_display = wl_display_create();
+ assert(xwl.host_display);
+
+ event_loop = wl_display_get_event_loop(xwl.host_display);
+
+ wl_event_loop_add_fd(event_loop,
+ wl_display_get_fd(xwl.display),
+ WL_EVENT_READABLE,
+ xwl_handle_event,
+ &xwl);
+
+ wl_registry_add_listener(wl_display_get_registry(xwl.display),
+ &xwl_registry_listener,
+ &xwl);
+
+ wl_display_roundtrip(xwl.display);
+
+ /* Wayland connection from Xwayland */
+ rv = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv);
+ assert(!rv);
+
+ xwl.client = wl_client_create(xwl.host_display, sv[0]);
+
+ /* Xwayland display ready socket */
+ rv = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ds);
+ assert(!rv);
+
+ xwl.display_event_source = wl_event_loop_add_fd(event_loop,
+ ds[0],
+ WL_EVENT_READABLE,
+ xwl_handle_display_event,
+ &xwl);
+
+ /* X connection to Xwayland */
+ rv = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm);
+ assert(!rv);
+
+ xwl.wm_fd = wm[0];
+
+ pid = fork();
+ assert(pid != -1);
+ if (pid == 0) {
+ char fd_str[8], display_fd_str[8], wm_fd_str[8];
+ int fd;
+
+ /* SOCK_CLOEXEC closes both ends, so we need to unset
+ * the flag on the client fd. */
+ fd = dup(sv[1]);
+ snprintf(fd_str, sizeof(fd_str), "%d", fd);
+ setenv("WAYLAND_SOCKET", fd_str, 1);
+ fd = dup(ds[1]);
+ snprintf(display_fd_str, sizeof(display_fd_str), "%d", fd);
+ fd = dup(wm[1]);
+ snprintf(wm_fd_str, sizeof(wm_fd_str), "%d", fd);
+
+ execlp("Xwayland", "Xwayland",
+ "-rootless",
+ "-terminate",
+ "-displayfd", display_fd_str,
+ "-wm", wm_fd_str,
+ NULL);
+ perror("Xwayland");
+ _exit(EXIT_FAILURE);
+ }
+
+ close(sv[1]);
+ close(wm[1]);
+
+ do {
+ wl_display_flush_clients(xwl.host_display);
+ if (xwl.connection)
+ xcb_flush(xwl.connection);
+ wl_display_flush(xwl.display);
+ } while (wl_event_loop_dispatch(event_loop, -1) != -1);
+}
diff --git a/src/solaris/native/sun/awt/xwayland.h b/src/solaris/native/sun/awt/xwayland.h
new file mode 100644
index 0000000..97bdf5a
--- /dev/null
+++ b/src/solaris/native/sun/awt/xwayland.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 The Chromium Authors. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <pthread.h>
+
+/* Initialize Xwayland session and run main loop efter waiting on barrier */
+void xwayland_run(pthread_barrier_t *barrier);
diff --git a/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java b/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java
index cf4933e..f25bd94 100644
--- a/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java
+++ b/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java
@@ -41,16 +41,16 @@
class WindowsDirectoryStream
implements DirectoryStream<Path>
{
+ private static final int NATIVE_BUFFER_SIZE = 8192;
+
private final WindowsPath dir;
private final DirectoryStream.Filter<? super Path> filter;
- // handle to directory
- private final long handle;
- // first entry in the directory
- private final String firstName;
+ // Query directory information data structure
+ private final QueryDirectoryInformation queryDirectoryInformation;
- // buffer for WIN32_FIND_DATA structure that receives information about file
- private final NativeBuffer findDataBuffer;
+ // Buffer used to receive file entries from NtQueryDirectoryInformation calls
+ private final NativeBuffer queryDirectoryInformationBuffer;
private final Object closeLock = new Object();
@@ -65,21 +65,15 @@
this.dir = dir;
this.filter = filter;
+ this.queryDirectoryInformationBuffer = NativeBuffers.getNativeBuffer(NATIVE_BUFFER_SIZE);
try {
- // Need to append * or \* to match entries in directory.
+ // Open the directory for reading and read the first set of entries in the native buffer
String search = dir.getPathForWin32Calls();
- char last = search.charAt(search.length() -1);
- if (last == ':' || last == '\\') {
- search += "*";
- } else {
- search += "\\*";
- }
-
- FirstFile first = FindFirstFile(search);
- this.handle = first.handle();
- this.firstName = first.name();
- this.findDataBuffer = WindowsFileAttributes.getBufferForFindData();
+ this.queryDirectoryInformation = OpenNtQueryDirectoryInformation(search, this.queryDirectoryInformationBuffer);
} catch (WindowsException x) {
+ // Release the buffer, as this instance is not fully constructed
+ this.queryDirectoryInformationBuffer.release();
+
if (x.lastError() == ERROR_DIRECTORY) {
throw new NotDirectoryException(dir.getPathForExceptionMessage());
}
@@ -99,9 +93,9 @@
return;
isOpen = false;
}
- findDataBuffer.release();
+ queryDirectoryInformationBuffer.release();
try {
- FindClose(handle);
+ CloseNtQueryDirectoryInformation(queryDirectoryInformation);
} catch (WindowsException x) {
x.rethrowAsIOException(dir);
}
@@ -115,20 +109,20 @@
synchronized (this) {
if (iterator != null)
throw new IllegalStateException("Iterator already obtained");
- iterator = new WindowsDirectoryIterator(firstName);
+ iterator = new WindowsDirectoryIterator();
return iterator;
}
}
private class WindowsDirectoryIterator implements Iterator<Path> {
private boolean atEof;
- private String first;
private Path nextEntry;
private String prefix;
+ private int nextOffset;
- WindowsDirectoryIterator(String first) {
+ WindowsDirectoryIterator() {
atEof = false;
- this.first = first;
+ nextOffset = 0;
if (dir.needsSlashWhenResolving()) {
prefix = dir.toString() + "\\";
} else {
@@ -156,44 +150,35 @@
// reads next directory entry
private Path readNextEntry() {
- // handle first element returned by search
- if (first != null) {
- nextEntry = isSelfOrParent(first) ? null : acceptEntry(first, null);
- first = null;
- if (nextEntry != null)
- return nextEntry;
- }
-
for (;;) {
- String name = null;
+ String name;
WindowsFileAttributes attrs;
// synchronize on closeLock to prevent close while reading
synchronized (closeLock) {
- try {
- if (isOpen) {
- name = FindNextFile(handle, findDataBuffer.address());
+ // Fetch next set of entries if we don't have anything available in buffer
+ if (nextOffset < 0) {
+ try {
+ atEof = !NextNtQueryDirectoryInformation(queryDirectoryInformation, queryDirectoryInformationBuffer);
+ } catch (WindowsException x) {
+ IOException ioe = x.asIOException(dir);
+ throw new DirectoryIteratorException(ioe);
}
- } catch (WindowsException x) {
- IOException ioe = x.asIOException(dir);
- throw new DirectoryIteratorException(ioe);
+ if (atEof) {
+ return null;
+ }
+ nextOffset = 0;
}
- // NO_MORE_FILES or stream closed
- if (name == null) {
- atEof = true;
- return null;
- }
-
- // ignore link to self and parent directories
- if (isSelfOrParent(name))
+ long fullDirInformationAddress = queryDirectoryInformationBuffer.address() + nextOffset;
+ int nextEntryOffset = WindowsFileAttributes.getNextOffsetFromFileIdFullDirInformation(fullDirInformationAddress);
+ nextOffset = nextEntryOffset == 0 ? -1 : nextOffset + nextEntryOffset;
+ name = WindowsFileAttributes.getFileNameFromFileIdFullDirInformation(fullDirInformationAddress);
+ if (isSelfOrParent(name)) {
+ // Skip "." and ".."
continue;
-
- // grab the attributes from the WIN32_FIND_DATA structure
- // (needs to be done while holding closeLock because close
- // will release the buffer)
- attrs = WindowsFileAttributes
- .fromFindData(findDataBuffer.address());
+ }
+ attrs = WindowsFileAttributes.fromFileIdFullDirInformation(fullDirInformationAddress, queryDirectoryInformation.volSerialNumber());
}
// return entry if accepted by filter
diff --git a/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java b/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java
index 737bbd7..78a81d5 100644
--- a/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java
+++ b/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java
@@ -150,6 +150,23 @@
}
}
+ private static class BasicWithKey extends Basic {
+ BasicWithKey(WindowsPath file, boolean followLinks) {
+ super(file, followLinks);
+ }
+
+ @Override
+ public WindowsFileAttributes readAttributes() throws IOException {
+ file.checkRead();
+ try {
+ return WindowsFileAttributes.getWithFileKey(file, followLinks);
+ } catch (WindowsException x) {
+ x.rethrowAsIOException(file);
+ return null; // keep compiler happy
+ }
+ }
+ }
+
static class Dos extends Basic implements DosFileAttributeView {
private static final String READONLY_NAME = "readonly";
private static final String ARCHIVE_NAME = "archive";
@@ -289,6 +306,10 @@
return new Basic(file, followLinks);
}
+ static Basic createBasicWithKeyView(WindowsPath file, boolean followLinks) {
+ return new BasicWithKey(file, followLinks);
+ }
+
static Dos createDosView(WindowsPath file, boolean followLinks) {
return new Dos(file, followLinks);
}
diff --git a/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java
index 208435d..03b4882 100644
--- a/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java
+++ b/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java
@@ -109,6 +109,34 @@
private static final short OFFSETOF_FIND_DATA_SIZELOW = 32;
private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36;
+ /**
+ * typedef struct _FILE_ID_FULL_DIR_INFORMATION {
+ * ULONG NextEntryOffset; // offset = 0
+ * ULONG FileIndex; // offset = 4
+ * LARGE_INTEGER CreationTime; // offset = 8
+ * LARGE_INTEGER LastAccessTime; // offset = 16
+ * LARGE_INTEGER LastWriteTime; // offset = 24
+ * LARGE_INTEGER ChangeTime; // offset = 32
+ * LARGE_INTEGER EndOfFile; // offset = 40
+ * LARGE_INTEGER AllocationSize; // offset = 48
+ * ULONG FileAttributes; // offset = 56
+ * ULONG FileNameLength; // offset = 60
+ * ULONG EaSize; // offset = 64
+ * LARGE_INTEGER FileId; // offset = 72
+ * WCHAR FileName[1]; // offset = 80
+ * } FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;
+ */
+ private static final int OFFSETOF_FULL_DIR_INFO_NEXT_ENTRY_OFFSET = 0;
+ private static final int OFFSETOF_FULL_DIR_INFO_CREATION_TIME = 8;
+ private static final int OFFSETOF_FULL_DIR_INFO_LAST_ACCESS_TIME = 16;
+ private static final int OFFSETOF_FULL_DIR_INFO_LAST_WRITE_TIME = 24;
+ private static final int OFFSETOF_FULL_DIR_INFO_END_OF_FILE = 40;
+ private static final int OFFSETOF_FULL_DIR_INFO_FILE_ATTRIBUTES = 56;
+ private static final int OFFSETOF_FULL_DIR_INFO_FILENAME_LENGTH = 60;
+ private static final int OFFSETOF_FULL_DIR_INFO_EA_SIZE = 64;
+ private static final int OFFSETOF_FULL_DIR_INFO_FILE_ID = 72;
+ private static final int OFFSETOF_FULL_DIR_INFO_FILENAME = 80;
+
// used to adjust values between Windows and java epoch
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
@@ -134,6 +162,9 @@
private final int fileIndexHigh;
private final int fileIndexLow;
+ // created lazily
+ private volatile WindowsFileKey key;
+
/**
* Convert 64-bit value representing the number of 100-nanosecond intervals
* since January 1, 1601 to a FileTime.
@@ -260,6 +291,47 @@
}
/**
+ * Create a WindowsFileAttributes from a FILE_ID_FULL_DIR_INFORMATION structure
+ */
+ static WindowsFileAttributes fromFileIdFullDirInformation(long address, int volSerialNumber) {
+ int fileAttrs = unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_FILE_ATTRIBUTES);
+ long creationTime = unsafe.getLong(address + OFFSETOF_FULL_DIR_INFO_CREATION_TIME);
+ long lastAccessTime = unsafe.getLong(address + OFFSETOF_FULL_DIR_INFO_LAST_ACCESS_TIME);
+ long lastWriteTime = unsafe.getLong(address + OFFSETOF_FULL_DIR_INFO_LAST_WRITE_TIME);
+ long size = unsafe.getLong(address + OFFSETOF_FULL_DIR_INFO_END_OF_FILE);
+ int reparseTag = isReparsePoint(fileAttrs) ?
+ unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_EA_SIZE) : 0;
+ int fileIndexLow = unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_FILE_ID);
+ int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_FILE_ID + 4);
+
+ return new WindowsFileAttributes(fileAttrs,
+ creationTime,
+ lastAccessTime,
+ lastWriteTime,
+ size,
+ reparseTag,
+ volSerialNumber,
+ fileIndexHigh, // fileIndexHigh
+ fileIndexLow); // fileIndexLow
+ }
+
+ static int getNextOffsetFromFileIdFullDirInformation(long address) {
+ return unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_NEXT_ENTRY_OFFSET);
+ }
+
+ static String getFileNameFromFileIdFullDirInformation(long address) {
+ // copy the name
+ int nameLengthInBytes = unsafe.getInt(address + OFFSETOF_FULL_DIR_INFO_FILENAME_LENGTH);
+ if ((nameLengthInBytes % 2) != 0) {
+ throw new AssertionError("FileNameLength is not a multiple of 2");
+ }
+ char[] nameAsArray = new char[nameLengthInBytes/2];
+ unsafe.copyMemory(null, address + OFFSETOF_FULL_DIR_INFO_FILENAME, nameAsArray,
+ Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes);
+ return new String(nameAsArray);
+ }
+
+ /**
* Reads the attributes of an open file
*/
static WindowsFileAttributes readAttributes(long handle)
@@ -349,6 +421,15 @@
}
// file is reparse point so need to open file to get attributes
+ return getWithFileKey(path, followLinks);
+ }
+
+ /**
+ * Returns attributes of given file.
+ */
+ static WindowsFileAttributes getWithFileKey(WindowsPath path, boolean followLinks)
+ throws WindowsException
+ {
long handle = path.openForReadAttributeAccess(followLinks);
try {
return readAttributes(handle);
@@ -416,7 +497,17 @@
@Override
public Object fileKey() {
- return null;
+ if (volSerialNumber == 0) {
+ return null;
+ }
+ if (key == null) {
+ synchronized (this) {
+ if (key == null) {
+ key = new WindowsFileKey(volSerialNumber, ((long)fileIndexHigh << 32) + fileIndexLow);
+ }
+ }
+ }
+ return key;
}
// package private
diff --git a/src/windows/classes/sun/nio/fs/WindowsFileKey.java b/src/windows/classes/sun/nio/fs/WindowsFileKey.java
new file mode 100644
index 0000000..b61b4d2
--- /dev/null
+++ b/src/windows/classes/sun/nio/fs/WindowsFileKey.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * Container for volume/file id to uniquely identify file.
+ */
+
+class WindowsFileKey {
+ private final int volSerialNumber;
+ private final long fileId;
+
+ WindowsFileKey(int volSerialNumber, long fileId) {
+ this.volSerialNumber = volSerialNumber;
+ this.fileId = fileId;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int)(volSerialNumber ^ (volSerialNumber >>> 16)) +
+ (int)(fileId ^ (fileId >>> 32));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+ if (!(obj instanceof WindowsFileKey))
+ return false;
+ WindowsFileKey other = (WindowsFileKey)obj;
+ return (this.volSerialNumber == other.volSerialNumber) && (this.fileId == other.fileId);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(volId=")
+ .append(Integer.toHexString(volSerialNumber))
+ .append(",fileId=")
+ .append(Long.toHexString(fileId))
+ .append(')');
+ return sb.toString();
+ }
+}
diff --git a/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java
index bd5f890..b33249a 100644
--- a/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java
+++ b/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java
@@ -162,6 +162,8 @@
boolean followLinks = Util.followLinks(options);
if (view == BasicFileAttributeView.class)
return (V) WindowsFileAttributeViews.createBasicView(file, followLinks);
+ if (view == BasicWithKeyFileAttributeView.class)
+ return (V) WindowsFileAttributeViews.createBasicWithKeyView(file, followLinks);
if (view == DosFileAttributeView.class)
return (V) WindowsFileAttributeViews.createDosView(file, followLinks);
if (view == AclFileAttributeView.class)
@@ -199,6 +201,8 @@
boolean followLinks = Util.followLinks(options);
if (name.equals("basic"))
return WindowsFileAttributeViews.createBasicView(file, followLinks);
+ if (name.equals("basicwithkey"))
+ return WindowsFileAttributeViews.createBasicWithKeyView(file, followLinks);
if (name.equals("dos"))
return WindowsFileAttributeViews.createDosView(file, followLinks);
if (name.equals("acl"))
diff --git a/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
index 47d28f8..27036d1 100644
--- a/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
+++ b/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
@@ -275,6 +275,38 @@
*/
static native void FindClose(long handle) throws WindowsException;
+ static QueryDirectoryInformation OpenNtQueryDirectoryInformation(String path, NativeBuffer buffer) throws WindowsException {
+ NativeBuffer pathBuffer = asNativeBuffer(path);
+ try {
+ QueryDirectoryInformation data = new QueryDirectoryInformation();
+ OpenNtQueryDirectoryInformation0(pathBuffer.address(), buffer.address(), buffer.size(), data);
+ return data;
+ } finally {
+ pathBuffer.release();
+ }
+ }
+ static class QueryDirectoryInformation {
+ private long handle;
+ private int volSerialNumber;
+
+ private QueryDirectoryInformation() { }
+ public long handle() { return handle; }
+ public int volSerialNumber() { return volSerialNumber; }
+ }
+ private static native void OpenNtQueryDirectoryInformation0(long lpFileName, long buffer, int bufferSize, QueryDirectoryInformation obj)
+ throws WindowsException;
+
+ static boolean NextNtQueryDirectoryInformation(QueryDirectoryInformation data, NativeBuffer buffer) throws WindowsException {
+ return NextNtQueryDirectoryInformation0(data.handle(), buffer.address(), buffer.size());
+ }
+
+ private static native boolean NextNtQueryDirectoryInformation0(long handle, long buffer, int bufferSize)
+ throws WindowsException;
+
+ static void CloseNtQueryDirectoryInformation(QueryDirectoryInformation data) throws WindowsException {
+ CloseHandle(data.handle);
+ }
+
/**
* GetFileInformationByHandle(
* HANDLE hFile,
diff --git a/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c b/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
index 0a18e0b..e20ebb7 100644
--- a/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
+++ b/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
@@ -42,6 +42,8 @@
#include "jni_util.h"
#include "jlong.h"
+#include "ntifs_min.h"
+
#include "sun_nio_fs_WindowsNativeDispatcher.h"
/**
@@ -54,6 +56,9 @@
static jfieldID findStream_handle;
static jfieldID findStream_name;
+static jfieldID queryDirectoryInformation_handle;
+static jfieldID queryDirectoryInformation_volSerialNumber;
+
static jfieldID volumeInfo_fsName;
static jfieldID volumeInfo_volName;
static jfieldID volumeInfo_volSN;
@@ -76,7 +81,6 @@
static jfieldID backupResult_bytesTransferred;
static jfieldID backupResult_context;
-
/**
* Win32 APIs not available in Windows XP
*/
@@ -86,12 +90,19 @@
typedef BOOLEAN (WINAPI* CreateSymbolicLinkProc) (LPCWSTR, LPCWSTR, DWORD);
typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
+typedef NTSYSCALLAPI NTSTATUS (NTAPI *NtQueryDirectoryFile_Proc) (HANDLE, HANDLE, PIO_APC_ROUTINE,
+ PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN);
+typedef ULONG (NTAPI *RtlNtStatusToDosError_Proc) (NTSTATUS);
+
static FindFirstStream_Proc FindFirstStream_func;
static FindNextStream_Proc FindNextStream_func;
static CreateSymbolicLinkProc CreateSymbolicLink_func;
static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
+static NtQueryDirectoryFile_Proc NtQueryDirectoryFile_func;
+static RtlNtStatusToDosError_Proc RtlNtStatusToDosError_func;
+
static void throwWindowsException(JNIEnv* env, DWORD lastError) {
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/WindowsException",
"(I)V", lastError);
@@ -126,6 +137,13 @@
findStream_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
CHECK_NULL(findStream_name);
+ clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$QueryDirectoryInformation");
+ CHECK_NULL(clazz);
+ queryDirectoryInformation_handle = (*env)->GetFieldID(env, clazz, "handle", "J");
+ CHECK_NULL(queryDirectoryInformation_handle);
+ queryDirectoryInformation_volSerialNumber = (*env)->GetFieldID(env, clazz, "volSerialNumber", "I");;
+ CHECK_NULL(queryDirectoryInformation_volSerialNumber);
+
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$VolumeInformation");
CHECK_NULL(clazz);
volumeInfo_fsName = (*env)->GetFieldID(env, clazz, "fileSystemName", "Ljava/lang/String;");
@@ -193,6 +211,17 @@
GetFinalPathNameByHandle_func =
(GetFinalPathNameByHandleProc)GetProcAddress(h, "GetFinalPathNameByHandleW");
}
+
+ // get handle to ntdll
+ if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ L"ntdll.dll", &h) != 0)
+ {
+ NtQueryDirectoryFile_func =
+ (NtQueryDirectoryFile_Proc)GetProcAddress(h, "NtQueryDirectoryFile");
+ RtlNtStatusToDosError_func =
+ (RtlNtStatusToDosError_Proc)GetProcAddress(h, "RtlNtStatusToDosError");
+ }
+
}
JNIEXPORT jlong JNICALL
@@ -460,6 +489,118 @@
JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_OpenNtQueryDirectoryInformation0(JNIEnv* env, jclass this,
+ jlong address, jlong bufferAddress, jint bufferSize, jobject obj)
+{
+ LPCWSTR lpFileName = jlong_to_ptr(address);
+ BOOL ok;
+ BY_HANDLE_FILE_INFORMATION info;
+ HANDLE handle;
+ NTSTATUS status;
+ ULONG win32ErrorCode;
+ IO_STATUS_BLOCK ioStatusBlock;
+
+ if ((NtQueryDirectoryFile_func == NULL) || (RtlNtStatusToDosError_func == NULL)) {
+ JNU_ThrowInternalError(env, "Should not get here");
+ return;
+ }
+
+ handle = CreateFileW(lpFileName, FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ throwWindowsException(env, GetLastError());
+ return;
+ }
+
+ status = NtQueryDirectoryFile_func(
+ handle, // FileHandle
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock, // IoStatusBlock
+ jlong_to_ptr(bufferAddress), // FileInformation
+ bufferSize, // Length
+ FileIdFullDirectoryInformation, // FileInformationClass
+ FALSE, // ReturnSingleEntry
+ NULL, // FileName
+ FALSE); // RestartScan
+
+ if (!NT_SUCCESS(status)) {
+ /*
+ * NtQueryDirectoryFile returns STATUS_INVALID_PARAMETER when
+ * asked to enumerate an invalid directory (ie it is a file
+ * instead of a directory). Verify that is the actual cause
+ * of the error.
+ */
+ if (status == STATUS_INVALID_PARAMETER) {
+ DWORD attributes = GetFileAttributesW(lpFileName);
+ if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+ status = STATUS_NOT_A_DIRECTORY;
+ }
+ }
+
+ win32ErrorCode = RtlNtStatusToDosError_func(status);
+ throwWindowsException(env, win32ErrorCode);
+ CloseHandle(handle);
+ return;
+ }
+
+ // This call allows retrieving the volume ID of this directory (and all its entries)
+ ok = GetFileInformationByHandle(handle, &info);
+ if (!ok) {
+ throwWindowsException(env, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ (*env)->SetLongField(env, obj, queryDirectoryInformation_handle, ptr_to_jlong(handle));
+ (*env)->SetIntField(env, obj, queryDirectoryInformation_volSerialNumber, info.dwVolumeSerialNumber);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_NextNtQueryDirectoryInformation0(JNIEnv* env, jclass this,
+ jlong handle, jlong address, jint size)
+{
+ HANDLE h = (HANDLE)jlong_to_ptr(handle);
+ ULONG win32ErrorCode;
+ IO_STATUS_BLOCK ioStatusBlock;
+ NTSTATUS status;
+
+ if ((NtQueryDirectoryFile_func == NULL) || (RtlNtStatusToDosError_func == NULL)) {
+ JNU_ThrowInternalError(env, "Should not get here");
+ return JNI_FALSE;
+ }
+
+ status = NtQueryDirectoryFile_func(
+ h, // FileHandle
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock, // IoStatusBlock
+ jlong_to_ptr(address), // FileInformation
+ size, // Length
+ FileIdFullDirectoryInformation, // FileInformationClass
+ FALSE, // ReturnSingleEntry
+ NULL, // FileName
+ FALSE); // RestartScan
+
+ if (NT_SUCCESS(status)) {
+ return JNI_TRUE;
+ }
+
+ // Normal completion: no more files in directory
+ if (status == STATUS_NO_MORE_FILES) {
+ return JNI_FALSE;
+ }
+
+ win32ErrorCode = RtlNtStatusToDosError_func(status);
+ throwWindowsException(env, win32ErrorCode);
+ return JNI_FALSE;
+}
+
+
+JNIEXPORT void JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_GetFileInformationByHandle(JNIEnv* env, jclass this,
jlong handle, jlong address)
{
diff --git a/src/windows/native/sun/nio/fs/ntifs_min.h b/src/windows/native/sun/nio/fs/ntifs_min.h
new file mode 100644
index 0000000..0a895f3
--- /dev/null
+++ b/src/windows/native/sun/nio/fs/ntifs_min.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef _NTIFS_MIN_
+#define _NTIFS_MIN_
+
+/*
+ * Copy necessary structures and definitions out of the Windows DDK
+ * to enable calling NtQueryDirectoryFile()
+ */
+
+typedef LONG NTSTATUS;
+#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
+
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWCH Buffer;
+} UNICODE_STRING;
+typedef UNICODE_STRING *PUNICODE_STRING;
+typedef const UNICODE_STRING *PCUNICODE_STRING;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation,
+ FileBothDirectoryInformation,
+ FileBasicInformation,
+ FileStandardInformation,
+ FileInternalInformation,
+ FileEaInformation,
+ FileAccessInformation,
+ FileNameInformation,
+ FileRenameInformation,
+ FileLinkInformation,
+ FileNamesInformation,
+ FileDispositionInformation,
+ FilePositionInformation,
+ FileFullEaInformation,
+ FileModeInformation,
+ FileAlignmentInformation,
+ FileAllInformation,
+ FileAllocationInformation,
+ FileEndOfFileInformation,
+ FileAlternateNameInformation,
+ FileStreamInformation,
+ FilePipeInformation,
+ FilePipeLocalInformation,
+ FilePipeRemoteInformation,
+ FileMailslotQueryInformation,
+ FileMailslotSetInformation,
+ FileCompressionInformation,
+ FileObjectIdInformation,
+ FileCompletionInformation,
+ FileMoveClusterInformation,
+ FileQuotaInformation,
+ FileReparsePointInformation,
+ FileNetworkOpenInformation,
+ FileAttributeTagInformation,
+ FileTrackingInformation,
+ FileIdBothDirectoryInformation,
+ FileIdFullDirectoryInformation,
+ FileValidDataLengthInformation,
+ FileShortNameInformation,
+ FileIoCompletionNotificationInformation,
+ FileIoStatusBlockRangeInformation,
+ FileIoPriorityHintInformation,
+ FileSfioReserveInformation,
+ FileSfioVolumeInformation,
+ FileHardLinkInformation,
+ FileProcessIdsUsingFileInformation,
+ FileNormalizedNameInformation,
+ FileNetworkPhysicalNameInformation,
+ FileIdGlobalTxDirectoryInformation,
+ FileIsRemoteDeviceInformation,
+ FileAttributeCacheInformation,
+ FileNumaNodeInformation,
+ FileStandardLinkInformation,
+ FileRemoteProtocolInformation,
+ FileMaximumInformation
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_ID_FULL_DIR_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ ULONG EaSize;
+ LARGE_INTEGER FileId;
+ WCHAR FileName[1];
+} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;
+
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ } u;
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef VOID
+(NTAPI *PIO_APC_ROUTINE)(
+ IN PVOID ApcContext,
+ IN PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG Reserved);
+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtQueryDirectoryFile(
+ _In_ HANDLE FileHandle,
+ _In_opt_ HANDLE Event,
+ _In_opt_ PIO_APC_ROUTINE ApcRoutine,
+ _In_opt_ PVOID ApcContext,
+ _Out_ PIO_STATUS_BLOCK IoStatusBlock,
+ _Out_ PVOID FileInformation,
+ _In_ ULONG Length,
+ _In_ FILE_INFORMATION_CLASS FileInformationClass,
+ _In_ BOOLEAN ReturnSingleEntry,
+ _In_opt_ PUNICODE_STRING FileName,
+ _In_ BOOLEAN RestartScan
+);
+
+ULONG
+NTAPI
+RtlNtStatusToDosError(
+ NTSTATUS Status
+);
+
+#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L)
+#define STATUS_NOT_A_DIRECTORY ((NTSTATUS)0xC0000103L)
+
+#endif // _NTIFS_MIN_