# HG changeset patch # User serb # Date 1571954071 25200 # Node ID d2123a27cfe74085b4ce4d2b52de66734666305d # Parent f4270450976b4d9f66dff07e04a8c1cb1d50ff2b 8232200: [macos 10.15] Windows in fullscreen tests jumps around the screen Reviewed-by: prr diff -r f4270450976b -r d2123a27cfe7 src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java --- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java Wed Oct 30 13:47:49 2019 -0700 +++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsDevice.java Thu Oct 24 14:54:31 2019 -0700 @@ -33,11 +33,14 @@ import java.awt.Rectangle; import java.awt.Window; import java.awt.geom.Rectangle2D; +import java.awt.peer.WindowPeer; import java.util.Objects; import sun.java2d.SunGraphicsEnvironment; import sun.java2d.opengl.CGLGraphicsConfig; +import static java.awt.peer.ComponentPeer.SET_BOUNDS; + public final class CGraphicsDevice extends GraphicsDevice implements DisplayChangedListener { @@ -129,6 +132,7 @@ } public void invalidate(final int defaultDisplayID) { + //TODO do we need to restore the full-screen window/modes on old device? displayID = defaultDisplayID; } @@ -138,7 +142,8 @@ yResolution = nativeGetYResolution(displayID); bounds = nativeGetBounds(displayID).getBounds(); //does integer rounding initScaleFactor(); - //TODO configs/fullscreenWindow/modes? + resizeFSWindow(getFullScreenWindow(), bounds); + //TODO configs? } @Override @@ -217,6 +222,18 @@ } } + /** + * Reapplies the size of this device to the full-screen window. + */ + private static void resizeFSWindow(final Window w, final Rectangle b) { + if (w != null) { + WindowPeer peer = AWTAccessor.getComponentAccessor().getPeer(w); + if (peer != null) { + peer.setBounds(b.x, b.y, b.width, b.height, SET_BOUNDS); + } + } + } + @Override public boolean isDisplayChangeSupported() { return true; @@ -229,10 +246,7 @@ } if (!Objects.equals(dm, getDisplayMode())) { nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(), - dm.getBitDepth(), dm.getRefreshRate()); - if (isFullScreenSupported() && getFullScreenWindow() != null) { - getFullScreenWindow().setSize(dm.getWidth(), dm.getHeight()); - } + dm.getBitDepth(), dm.getRefreshRate()); } } diff -r f4270450976b -r d2123a27cfe7 test/jdk/ProblemList.txt --- a/test/jdk/ProblemList.txt Wed Oct 30 13:47:49 2019 -0700 +++ b/test/jdk/ProblemList.txt Thu Oct 24 14:54:31 2019 -0700 @@ -530,6 +530,8 @@ java/awt/TextArea/AutoScrollOnSelectAndAppend/AutoScrollOnSelectAndAppend.java 8213120 macosx-all java/awt/Window/MainKeyWindowTest/TestMainKeyWindow.java 8213126 macosx-all +java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java 7099223 linux-all,solaris-all,windows-all + ############################################################################ # jdk_beans diff -r f4270450976b -r d2123a27cfe7 test/jdk/java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java Thu Oct 24 14:54:31 2019 -0700 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.Component; +import java.awt.DisplayMode; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Transparency; +import java.awt.Window; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.image.BufferedImage; +import java.util.ArrayList; + +/** + * @test + * @bug 4836241 6364134 8232200 + * @key headful + * @summary verify that images are restored correctly after display mode + * switches and that no other rendering or crash problems occur + * @run main/timeout=500 CycleDMImage + */ +public class CycleDMImage extends Component implements Runnable, KeyListener { + /** + * This test cycles through all available display modes, waiting after + * each call to setDisplayMode() to ensure that the new one is active + * before proceeding on to the next one. The Component is filled with + * a green background color and then compatible images of all 3 + * Transparency types are copied to the screen. The results of these + * operations are checked (using Robot) and the test fails if any of the + * rendering is wrong in any of the DisplayModes. The purpose of this + * test is to ensure that display mode switches do not cause problems + * with image restoration (or other rendering operations). + */ + boolean painted = false; + boolean earlyExit = false; + Image rImage = null, wImage = null, bImage = null; + int imgSize = 10; + Robot robot = null; + volatile static boolean done = false; + static String errorMessage = null; + + public synchronized void paint(Graphics g) { + if (!painted) { + painted = true; + (new Thread(this)).start(); + } + if (rImage == null) { + GraphicsConfiguration gc = getGraphicsConfiguration(); + rImage = gc.createCompatibleImage(imgSize, imgSize); + wImage = gc.createCompatibleImage(imgSize, imgSize, + Transparency.BITMASK); + bImage = gc.createCompatibleImage(imgSize, imgSize, + Transparency.TRANSLUCENT); + Graphics imgGraphics = rImage.getGraphics(); + imgGraphics.setColor(Color.red); + imgGraphics.fillRect(0, 0, imgSize, imgSize); + imgGraphics = wImage.getGraphics(); + imgGraphics.setColor(Color.white); + imgGraphics.fillRect(0, 0, imgSize, imgSize); + imgGraphics = bImage.getGraphics(); + imgGraphics.setColor(Color.blue); + imgGraphics.fillRect(0, 0, imgSize, imgSize); + } + g.setColor(Color.green); + g.fillRect(0, 0, getWidth(), getHeight()); + g.drawImage(rImage, 0, 0, this); + g.drawImage(wImage, imgSize, 0, this); + g.drawImage(bImage, imgSize*2, 0, this); + g.drawImage(rImage, 0, getHeight()-imgSize, null); + g.drawImage(rImage, getWidth()-imgSize, getHeight()-imgSize, null); + g.drawImage(rImage, getWidth()-imgSize, 0, null); + } + + static void delay(long ms) { + try { + Thread.sleep(ms); + } catch (Exception e) {} + } + + public boolean checkResult(DisplayMode dm) { + if (robot == null) { + try { + robot = new Robot(); + } + catch (Exception e) { + errorMessage = "Problems creating Robot"; + return false; + } + } + Rectangle bounds = getGraphicsConfiguration().getBounds(); + int pixels[] = new int[imgSize * 4]; + BufferedImage clientPixels = + robot.createScreenCapture(new Rectangle(bounds.x, bounds.y, + imgSize*4, 1)); + clientPixels.getRGB(0, 0, imgSize * 4, 1, pixels, 0, getWidth()); + // Now check the results. We expect: imgSize blocks of r/w/b/g + int colors[] = {0xffff0000, 0xffffffff, 0xff0000ff, 0xff00ff00}; + for (int color = 0; color < 4; ++color) { + for (int i = 0; i < imgSize; ++i) { + int pixelIndex = imgSize * color + i; + if (pixels[pixelIndex] != colors[color]) { + errorMessage = "\n DisplayMode(" + + dm.getWidth() + " x " + + dm.getHeight() + " x " + + dm.getBitDepth() + "bpp x " + + dm.getRefreshRate() + + ")\n Pixel " + i + + ": Expected " + + Integer.toHexString(colors[color]) + + ", got " + + Integer.toHexString(pixels[pixelIndex]) + + " at " + i; + return false; + } + } + } + return true; + } + + boolean displayModesEqual(DisplayMode dm1, DisplayMode dm2) { + if (dm1.equals(dm2)) { + return true; + } + // not enough - check whether the modes are equal except for + // refreshRate, if either mode has REFRESH_RATE_UNKNOWN + // value for this parameter + if (dm1.getWidth() != dm2.getWidth() || + dm1.getHeight() != dm2.getHeight() || + dm1.getBitDepth() != dm2.getBitDepth()) + { + // core parameters must match + return false; + } + // Now we know that w1 == w2, h1 == h2, and d1 == d2; must be the + // case that the refresh rates do not match. + // Is either one REFRESH_RATE_UNKNOWN? + if (dm1.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN || + dm2.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) + { + return true; + } + return false; + } + + public void run() { + GraphicsDevice gd = getGraphicsConfiguration().getDevice(); + gd.setFullScreenWindow((Window) getParent()); + // First, delay a bit just to let the fullscreen window + // settle down before switching display modes + delay(1000); + + if (!gd.isDisplayChangeSupported()) { + System.err.println("Display change is not supported,"+ + " the test is considered passed."); + finished(); + return; + } + + // We are really only interested in unique w/h/d resolutions + // and it would be nice to skip the myriad of refresh rate + // varations, so let us construct a subset that contains + // only those DisplayModes with unique w/h/d values + // Also, due to a current bug (4837228), we should skip the + // 24-bit depths since attempting to create bitmask-transparent + // ddraw images can cause the test to crash (we should change this + // test to include that depth when the bug is fixed). + ArrayList dmSubset = new ArrayList<>(); + for (final DisplayMode dm : gd.getDisplayModes()) { + boolean skip = false; + for (final DisplayMode dmUnique : dmSubset) { + int bitDepth = dm.getBitDepth(); + if (bitDepth == 24 || + (dmUnique.getWidth() == dm.getWidth() && + dmUnique.getHeight() == dm.getHeight() && + dmUnique.getBitDepth() == dm.getBitDepth())) { + skip = true; + break; + } + } + if (!skip) { + dmSubset.add(dm); + } + } + + // Now, cycle through the display modes one-by-one. For + // each new display mode, delay until we detect that the + // new mode == the current mode. Then delay an additional + // second (to allow any repaints to occur) + + for (DisplayMode newDM : dmSubset) { + gd.setDisplayMode(newDM); + while (!displayModesEqual(newDM, gd.getDisplayMode())) { + delay(100); + } + // Delay another few seconds after the new display mode is active + delay(4000); + + // Check the rendering results + if (!checkResult(newDM)) { + finished(); + return; + } + + // Escape out if requested by the user + if (earlyExit) { + System.out.println("Exiting test early, by request"); + System.exit(0); + } + } + + // Done with test; if we got here, we passed + System.out.println("Passed"); + finished(); + } + + public static void finished() { + synchronized (CycleDMImage.class) { + done = true; + CycleDMImage.class.notify(); + } + } + + /** + * KeyListener methods; these provide a way for a user to escape out of + * a potentially lengthy test. + */ + + public void keyTyped(KeyEvent e) { + } + + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + earlyExit = true; + } + } + + public void keyReleased(KeyEvent e) { + } + + public static void main(String args[]) { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (final GraphicsDevice gd: ge.getScreenDevices()) { + if (!gd.isFullScreenSupported()) { + System.err.println("FullScreen mode is not supported,"+ + " the test is considered passed."); + continue; + } + done = false; + Frame frame = new Frame(gd.getDefaultConfiguration()); + try { + frame.setSize(400, 400); + frame.setUndecorated(true); + CycleDMImage comp = new CycleDMImage(); + frame.addKeyListener(comp); + frame.add(comp); + frame.setVisible(true); + // Sleep awaiting frame disposal + synchronized (CycleDMImage.class) { + while (!done) { + try { + CycleDMImage.class.wait(100); + } catch (InterruptedException e) { + } + } + } + } finally { + frame.dispose(); + } + if (errorMessage != null) { + throw new RuntimeException(errorMessage); + } + // delay a bit just to let the fullscreen window disposing complete + // before switching to next display + delay(4000); + } + } +}