--- old/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c 2016-02-23 11:54:28.661720720 +0530 +++ new/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c 2016-02-23 11:54:28.429720718 +0530 @@ -802,5 +802,44 @@ float *scaleFactor) { *scaleFactor = 1; +#ifndef __linux__ + return NULL; +#endif + *scaleFactor = getNativeScaleFactor("GDK_SCALE"); + if (*scaleFactor == 2.0) { + char *scaledImgName = NULL; + size_t length = 0; + char *stringToAppend = ".java-scale2x"; + char *dupFileName = strdup(fileName); + char *fileExtension = strrchr(dupFileName, '.'); + + if (fileExtension == NULL) { + length = strlen(dupFileName) + strlen(stringToAppend) + 1; + scaledImgName = SAFE_SIZE_ARRAY_ALLOC(malloc, length, sizeof (char)); + snprintf(scaledImgName, length, "%s%s", + dupFileName, stringToAppend); + } else { + length = fileExtension - dupFileName + 1; + char *fileNameWithoutExt = SAFE_SIZE_ARRAY_ALLOC(malloc, length, sizeof (char)); + memcpy(fileNameWithoutExt, dupFileName, length); + fileNameWithoutExt[length - 1] = '\0'; + length = strlen(fileNameWithoutExt) + + strlen(stringToAppend) + strlen(fileExtension) + 1; + scaledImgName = SAFE_SIZE_ARRAY_ALLOC(malloc, length, sizeof (char)); + snprintf(scaledImgName, length, "%s%s%s", + fileNameWithoutExt, stringToAppend, fileExtension); + free(fileNameWithoutExt); + } + free(dupFileName); + FILE *fp; + if (!(fp = fopen(scaledImgName, "r"))) { + *scaleFactor = 1; + free(scaledImgName); + return NULL; + } + fclose(fp); + return scaledImgName; + } return NULL; } + --- old/src/java.desktop/unix/native/libsplashscreen/splashscreen_config.h 2016-02-23 11:54:29.201720726 +0530 +++ new/src/java.desktop/unix/native/libsplashscreen/splashscreen_config.h 2016-02-23 11:54:29.005720724 +0530 @@ -39,6 +39,7 @@ #include #include #include +#include "systemScale.h" typedef uint32_t rgbquad_t; typedef uint16_t word_t; @@ -57,5 +58,4 @@ #define INLINE static #define SPLASHEXPORT - #endif --- old/make/mapfiles/libsplashscreen/mapfile-vers 2016-02-23 11:54:29.729720732 +0530 +++ new/make/mapfiles/libsplashscreen/mapfile-vers 2016-02-23 11:54:29.505720730 +0530 @@ -42,6 +42,8 @@ SplashInit; SplashClose; SplashSetFileJarName; + SplashSetScaleFactor; + SplashGetScaledImageName; local: *; }; --- old/src/java.desktop/share/classes/java/awt/SplashScreen.java 2016-02-23 11:54:30.201720737 +0530 +++ new/src/java.desktop/share/classes/java/awt/SplashScreen.java 2016-02-23 11:54:29.997720735 +0530 @@ -251,7 +251,7 @@ assert scale > 0; if (scale > 0 && scale != 1) { bounds.setSize((int) (bounds.getWidth() / scale), - (int) (bounds.getWidth() / scale)); + (int) (bounds.getHeight() / scale)); } return bounds; } --- old/make/lib/Awt2dLibraries.gmk 2016-02-23 11:54:30.709720743 +0530 +++ new/make/lib/Awt2dLibraries.gmk 2016-02-23 11:54:30.517720741 +0530 @@ -327,6 +327,11 @@ -DPACKAGE_PATH=\"$(PACKAGE_PATH)\" \ $(CUPS_CFLAGS) + ifneq (,$(filter $(OPENJDK_TARGET_OS),linux solaris)) + LIBAWT_XAWT_DIRS += $(JDK_TOPDIR)/src/java.desktop/unix/native/common/awt/systemscale + LIBAWT_XAWT_CFLAGS += -I$(JDK_TOPDIR)/src/java.desktop/unix/native/common/awt/systemscale + endif + ifeq ($(OPENJDK_TARGET_OS), solaris) LIBAWT_XAWT_CFLAGS += -DFUNCPROTO=15 endif @@ -861,6 +866,11 @@ $(LIBJAVA_HEADER_FLAGS) \ # + ifneq (,$(filter $(OPENJDK_TARGET_OS),linux solaris)) + LIBSPLASHSCREEN_DIRS += $(JDK_TOPDIR)/src/java.desktop/unix/native/common/awt/systemscale + LIBSPLASHSCREEN_CFLAGS += -I$(JDK_TOPDIR)/src/java.desktop/unix/native/common/awt/systemscale + endif + ifeq ($(OPENJDK_TARGET_OS), macosx) LIBSPLASHSCREEN_CFLAGS += -DWITH_MACOSX LIBSPLASHSCREEN_CFLAGS += -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libosxapp @@ -896,7 +906,7 @@ -framework JavaNativeFoundation else ifeq ($(OPENJDK_TARGET_OS), windows) LIBSPLASHSCREEN_LDFLAGS := -delayload:user32.dll - LIBSPLASHSCREEN_LIBS += kernel32.lib user32.lib gdi32.lib delayimp.lib + LIBSPLASHSCREEN_LIBS += kernel32.lib user32.lib gdi32.lib delayimp.lib $(WIN_JAVA_LIB) jvm.lib else LIBSPLASHSCREEN_LIBS += $(X_LIBS) -lX11 -lXext $(LIBM) -lpthread endif --- /dev/null 2016-02-23 10:30:46.165665023 +0530 +++ new/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java 2016-02-23 11:54:31.025720746 +0530 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.SplashScreen; +import java.awt.TextField; +import java.awt.Window; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.imageio.ImageIO; + +/** + * @test @bug 8145174 + * @summary HiDPI splash screen support on Linux + * @modules java.desktop/sun.java2d + * @run main UnixMultiResolutionSplashTest + */ +public class UnixMultiResolutionSplashTest { + + private static final int IMAGE_WIDTH = 300; + private static final int IMAGE_HEIGHT = 200; + private static int inx = 0; + private static final ImageInfo[] tests = { + new ImageInfo("splash1.png", "splash1.java-scale2x.png", Color.BLUE, Color.GREEN), + new ImageInfo("splash2", "splash2.java-scale2x", Color.WHITE, Color.BLACK), + new ImageInfo("splash3.", "splash3.java-scale2x.", Color.YELLOW, Color.RED) + }; + + public static void main(String[] args) throws Exception { + + if (args.length == 0) { + generateImages(); + for (ImageInfo test : tests) { + createChildProcess(test); + } + } else { + int index = Integer.parseInt(args[0]); + testSplash(tests[index]); + } + } + + static void createChildProcess(ImageInfo test) { + String javaPath = System.getProperty("java.home"); + File file = new File(test.name1x); + String classPathDir = System.getProperty("java.class.path"); + Map env = new HashMap(); + env.put("GDK_SCALE", "2"); + int exitValue = doExec(env, javaPath + File.separator + "bin" + File.separator + + "java", "-splash:" + file.getAbsolutePath(), "-cp", + classPathDir, "UnixMultiResolutionSplashTest", String.valueOf(inx++)); + if (exitValue != 0) { + throw new RuntimeException("Test Failed"); + } + } + + static void testSplash(ImageInfo test) throws Exception { + SplashScreen splashScreen = SplashScreen.getSplashScreen(); + if (splashScreen == null) { + throw new RuntimeException("Splash screen is not shown!"); + } + Graphics2D g = splashScreen.createGraphics(); + Rectangle splashBounds = splashScreen.getBounds(); + int screenX = (int) splashBounds.getCenterX(); + int screenY = (int) splashBounds.getCenterY(); + System.out.println(screenX); + System.out.println(screenY); + Robot robot = new Robot(); + Color splashScreenColor = robot.getPixelColor(screenX, screenY); + + float scaleFactor = getScaleFactor(); + Color testColor = (1 < scaleFactor) ? test.color2x : test.color1x; + if (!compare(testColor, splashScreenColor)) { + throw new RuntimeException( + "Image with wrong resolution is used for splash screen!"); + } + } + + static int doExec(Map envToSet, String... cmds) { + Process p = null; + ProcessBuilder pb = new ProcessBuilder(cmds); + Map env = pb.environment(); + for (String cmd : cmds) { + System.out.print(cmd + " "); + } + System.out.println(); + if (envToSet != null) { + env.putAll(envToSet); + } + BufferedReader rdr = null; + try { + List outputList = new ArrayList<>(); + pb.redirectErrorStream(true); + p = pb.start(); + rdr = new BufferedReader(new InputStreamReader(p.getInputStream())); + String in = rdr.readLine(); + while (in != null) { + outputList.add(in); + in = rdr.readLine(); + System.out.println(in); + } + p.waitFor(); + p.destroy(); + } catch (Exception ex) { + ex.printStackTrace(); + } + return p.exitValue(); + } + + static void testFocus() throws Exception { + + System.out.println("Focus Test!"); + Robot robot = new Robot(); + robot.setAutoDelay(50); + Frame frame = new Frame(); + frame.setSize(100, 100); + String test = "123"; + TextField textField = new TextField(test); + textField.selectAll(); + frame.add(textField); + frame.setVisible(true); + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.keyPress(KeyEvent.VK_B); + robot.keyRelease(KeyEvent.VK_B); + robot.waitForIdle(); + + frame.dispose(); + if (!textField.getText().equals("ab")) { + throw new RuntimeException("Focus is lost!"); + } + } + + static boolean compare(Color c1, Color c2) { + return compare(c1.getRed(), c2.getRed()) + && compare(c1.getGreen(), c2.getGreen()) + && compare(c1.getBlue(), c2.getBlue()); + } + + static boolean compare(int n, int m) { + return Math.abs(n - m) <= 50; + } + + static float getScaleFactor() { + + final Dialog dialog = new Dialog((Window) null); + dialog.setSize(100, 100); + dialog.setModal(true); + float[] scaleFactors = new float[1]; + Panel panel = new Panel() { + + @Override + public void paint(Graphics g) { + String scaleStr = System.getenv("GDK_SCALE"); + if (scaleStr != null && !scaleStr.equals("")) { + try { + scaleFactors[0] = Float.valueOf(scaleStr); + } catch (NumberFormatException ex) { + scaleFactors[0] = 1.0f; + } + } + dialog.setVisible(false); + } + }; + dialog.add(panel); + dialog.setVisible(true); + dialog.dispose(); + return scaleFactors[0]; + } + + static void generateImages() throws Exception { + for (ImageInfo test : tests) { + generateImage(test.name1x, test.color1x, 1); + generateImage(test.name2x, test.color2x, 2); + } + } + + static void generateImage(String name, Color color, int scale) throws Exception { + File file = new File(name); + if (file.exists()) { + return; + } + BufferedImage image = new BufferedImage(scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.getGraphics(); + g.setColor(color); + g.fillRect(0, 0, scale * IMAGE_WIDTH, scale * IMAGE_HEIGHT); + ImageIO.write(image, "png", file); + } + + static class ImageInfo { + + final String name1x; + final String name2x; + final Color color1x; + final Color color2x; + + public ImageInfo(String name1x, String name2x, Color color1x, Color color2x) { + this.name1x = name1x; + this.name2x = name2x; + this.color1x = color1x; + this.color2x = color2x; + } + } +} + --- old/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2016-02-23 11:54:31.701720754 +0530 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2016-02-23 11:54:31.509720752 +0530 @@ -43,7 +43,7 @@ #include #include #include - +#include "systemScale.h" #include #include "awt_GraphicsEnv.h" @@ -2083,17 +2083,6 @@ * End DisplayMode/FullScreen support */ -int getScale(const char *name) { - char *uiScale = getenv(name); - if (uiScale != NULL) { - double scale = strtod(uiScale, NULL); - if (errno == ERANGE || scale < 1) { - return -1; - } - return (int) scale; - } - return -1; -} /* * Class: sun_awt_X11GraphicsDevice @@ -2108,12 +2097,12 @@ static int scale = -2.0; if (scale == -2) { - scale = getScale("J2D_UISCALE"); + scale = getNativeScaleFactor("J2D_UISCALE"); } if (scale >= 1) { return scale; } - return getScale("GDK_SCALE"); + return getNativeScaleFactor("GDK_SCALE"); } --- /dev/null 2016-02-23 10:30:46.165665023 +0530 +++ new/src/java.desktop/unix/native/common/awt/systemscale/systemScale.h 2016-02-23 11:54:31.993720757 +0530 @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2015, 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. +*/ +#ifndef _AWT_SYSTEMSCALE_H +#define _AWT_SYSTEMSCALE_H + +#include +#include + +int getNativeScaleFactor(const char * name); + +#endif + --- /dev/null 2016-02-23 10:30:46.165665023 +0530 +++ new/src/java.desktop/unix/native/common/awt/systemscale/systemScale.c 2016-02-23 11:54:32.477720763 +0530 @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2015, 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. +*/ + +#include "systemScale.h" + +int getNativeScaleFactor(const char * name) { + char *uiScale = getenv(name); + if (uiScale != NULL) { + double scale = strtod(uiScale, NULL); + if (scale < 1) { + return -1; + } + return (int) scale; + } + return -1; +} +