diff --git a/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java b/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java index 847fc700e09..0f3f195fb19 100644 --- a/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java +++ b/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -364,7 +364,38 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment AffineTransform tx = gc.getDefaultTransform(); x = Region.clipRound(x * tx.getScaleX()); y = Region.clipRound(y * tx.getScaleY()); - return new Point((int) x, (int) y); } + + /** + * Converts bounds from the user's space to the device space using + * appropriate device transformation. + * + * @param bounds the rectangle in the user space + * @return the rectangle which uses device space(pixels) + */ + public static Rectangle convertToDeviceSpace(Rectangle bounds) { + GraphicsConfiguration gc = getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + gc = getGraphicsConfigurationAtPoint(gc, bounds.x, bounds.y); + return convertToDeviceSpace(gc, bounds); + } + + /** + * Converts bounds from the user's space to the device space using + * appropriate device transformation of the passed graphics configuration. + * + * @param bounds the rectangle in the user space + * @return the rectangle which uses device space(pixels) + */ + public static Rectangle convertToDeviceSpace(GraphicsConfiguration gc, + Rectangle bounds) { + AffineTransform tx = gc.getDefaultTransform(); + return new Rectangle( + Region.clipRound(bounds.x * tx.getScaleX()), + Region.clipRound(bounds.y * tx.getScaleY()), + Region.clipRound(bounds.width * tx.getScaleX()), + Region.clipRound(bounds.height * tx.getScaleY()) + ); + } } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java index 36dcc87011d..3d66b0f5f78 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,24 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package sun.awt.windows; -import java.awt.*; -import java.awt.peer.*; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.MenuBar; +import java.awt.Rectangle; +import java.awt.peer.FramePeer; +import java.security.AccessController; + import sun.awt.AWTAccessor; import sun.awt.im.InputMethodManager; -import java.security.AccessController; import sun.security.action.GetPropertyAction; +import static sun.java2d.SunGraphicsEnvironment.convertToDeviceSpace; + class WFramePeer extends WWindowPeer implements FramePeer { static { @@ -65,49 +74,51 @@ class WFramePeer extends WWindowPeer implements FramePeer { "sun.awt.keepWorkingSetOnMinimize"))); @Override - public void setMaximizedBounds(Rectangle b) { + public final void setMaximizedBounds(Rectangle b) { if (b == null) { clearMaximizedBounds(); } else { - Rectangle adjBounds = (Rectangle)b.clone(); - adjustMaximizedBounds(adjBounds); - setMaximizedBounds(adjBounds.x, adjBounds.y, adjBounds.width, adjBounds.height); + b = adjustMaximizedBounds(b); + setMaximizedBounds(b.x, b.y, b.width, b.height); } } /** * The incoming bounds describe the maximized size and position of the - * window on the monitor that displays the window. But the window manager - * expects that the bounds are based on the size and position of the - * primary monitor, even if the window ultimately maximizes onto a - * secondary monitor. And the window manager adjusts these values to - * compensate for differences between the primary monitor and the monitor - * that displays the window. + * window in the virtual coordinate system. But the window manager expects + * that the bounds are based on the size of the primary monitor and + * position is based on the actual window monitor, even if the window + * ultimately maximizes onto a secondary monitor. And the window manager + * adjusts these values to compensate for differences between the primary + * monitor and the monitor that displays the window. + *

* The method translates the incoming bounds to the values acceptable * by the window manager. For more details, please refer to 6699851. */ - private void adjustMaximizedBounds(Rectangle b) { - GraphicsConfiguration currentDevGC = getGraphicsConfiguration(); + private Rectangle adjustMaximizedBounds(Rectangle bounds) { + // All calculations should be done in the device space + bounds = convertToDeviceSpace(bounds); - GraphicsDevice primaryDev = GraphicsEnvironment - .getLocalGraphicsEnvironment().getDefaultScreenDevice(); - GraphicsConfiguration primaryDevGC = primaryDev.getDefaultConfiguration(); - - if (currentDevGC != null && currentDevGC != primaryDevGC) { - Rectangle currentDevBounds = currentDevGC.getBounds(); - Rectangle primaryDevBounds = primaryDevGC.getBounds(); - - boolean isCurrentDevLarger = - ((currentDevBounds.width - primaryDevBounds.width > 0) || - (currentDevBounds.height - primaryDevBounds.height > 0)); - - // the window manager doesn't seem to compensate for differences when - // the primary monitor is larger than the monitor that display the window - if (isCurrentDevLarger) { - b.width -= (currentDevBounds.width - primaryDevBounds.width); - b.height -= (currentDevBounds.height - primaryDevBounds.height); - } - } + GraphicsConfiguration gc = getGraphicsConfiguration(); + Rectangle currentDevBounds = convertToDeviceSpace(gc, gc.getBounds()); + // Prepare data for WM_GETMINMAXINFO message. + // ptMaxPosition should be in coordinate system of the current monitor, + // not the main monitor, or monitor on which we maximize the window. + bounds.x -= currentDevBounds.x; + bounds.y -= currentDevBounds.y; + // ptMaxSize will be used as-is if the size is smaller than the main + // monitor. If the size is larger than the main monitor then the + // window manager adjusts the size, like this: + // result = bounds.w + (current.w - main.w); =>> wrong size + // We can try to compensate for this adjustment like this: + // result = bounds.w - (current.w - main.w); + // but this can result to the size smaller than the main screen, so no + // adjustment will be done by the window manager =>> wrong size. + // So we skip compensation here and cut the adjustment on + // WM_WINDOWPOSCHANGING event. + // Note that the result does not depend on the monitor on which we + // maximize the window. + return bounds; } @Override diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp index 7d5c2aa1dbb..6ea6f54a8f4 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -897,6 +897,21 @@ MsgRouting AwtFrame::WmGetMinMaxInfo(LPMINMAXINFO lpmmi) return mrConsume; } +MsgRouting AwtFrame::WmWindowPosChanging(LPARAM windowPos) { + if (::IsZoomed(GetHWnd()) && m_maxBoundsSet) { + // Limits the size of the maximized window, effectively cuts the + // adjustments added by the window manager + WINDOWPOS *wp = (WINDOWPOS *) windowPos; + if (m_maxSize.x < java_lang_Integer_MAX_VALUE && wp->cx > m_maxSize.x) { + wp->cx = m_maxSize.x; + } + if (m_maxSize.y < java_lang_Integer_MAX_VALUE && wp->cy > m_maxSize.y) { + wp->cy = m_maxSize.y; + } + } + return AwtWindow::WmWindowPosChanging(windowPos); +} + MsgRouting AwtFrame::WmSize(UINT type, int w, int h) { currentWmSizeState = type; diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Frame.h b/src/java.desktop/windows/native/libawt/windows/awt_Frame.h index 54a40e92386..1c49d8cfb93 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Frame.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Frame.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,6 +116,7 @@ public: MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button); MsgRouting WmGetIcon(WPARAM iconType, LRESULT& retVal); MsgRouting WmShowWindow(BOOL show, UINT status); + MsgRouting WmWindowPosChanging(LPARAM windowPos); virtual MsgRouting WmSysCommand(UINT uCmdType, int xPos, int yPos); diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index efdc2b78c1d..7f785f9bf68 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -211,7 +211,6 @@ java/awt/event/KeyEvent/KeyMaskTest/KeyMaskTest.java 8129778 generic-all java/awt/event/MouseEvent/MouseButtonsAndKeyMasksTest/MouseButtonsAndKeyMasksTest.java 8129778 generic-all java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java 8194947 generic-all -java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java 8196006 windows-all java/awt/Frame/FramesGC/FramesGC.java 8079069 macosx-all java/awt/FullScreen/AltTabCrashTest/AltTabCrashTest.java 8047218 generic-all java/awt/GridLayout/LayoutExtraGaps/LayoutExtraGaps.java 8000171 windows-all diff --git a/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenBig.java b/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenBig.java new file mode 100644 index 00000000000..e8301c0b470 --- /dev/null +++ b/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenBig.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; + +/** + * @test + * @bug 8176359 8231564 + * @key headful + * @requires (os.family == "windows" | os.family == "mac") + * @summary setMaximizedBounds() should work if set to the screen other than + * current screen of the Frame, the size of the frame is intentionally + * big + * @run main/othervm MaximizedToOppositeScreenBig + * @run main/othervm -Dsun.java2d.uiScale=1 MaximizedToOppositeScreenBig + * @run main/othervm -Dsun.java2d.uiScale=1.2 MaximizedToOppositeScreenBig + * @run main/othervm -Dsun.java2d.uiScale=1.25 MaximizedToOppositeScreenBig + * @run main/othervm -Dsun.java2d.uiScale=1.5 MaximizedToOppositeScreenBig + * @run main/othervm -Dsun.java2d.uiScale=1.75 MaximizedToOppositeScreenBig + * @run main/othervm -Dsun.java2d.uiScale=2 MaximizedToOppositeScreenBig + * @run main/othervm -Dsun.java2d.uiScale=2.25 MaximizedToOppositeScreenBig + */ +public final class MaximizedToOppositeScreenBig { + + public static void main(String[] args) throws Exception { + //Supported platforms are Windows and OS X. + String os = System.getProperty("os.name").toLowerCase(); + if (!os.contains("windows") && !os.contains("os x")) { + return; + } + + if (!Toolkit.getDefaultToolkit(). + isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { + return; + } + + var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] gds = ge.getScreenDevices(); + Robot robot = new Robot(); + for (GraphicsDevice gd1 : gds) { + Rectangle framAt = gd1.getDefaultConfiguration().getBounds(); + framAt.grow(-200, -200); + for (GraphicsDevice gd2 : gds) { + Rectangle maxTo = gd2.getDefaultConfiguration().getBounds(); + maxTo.grow(-150, -150); + Frame frame = new Frame(gd1.getDefaultConfiguration()); + try { + frame.setBounds(framAt); + frame.setVisible(true); + robot.waitForIdle(); + robot.delay(1000); + + frame.setMaximizedBounds(maxTo); + frame.setExtendedState(Frame.MAXIMIZED_BOTH); + robot.waitForIdle(); + robot.delay(1000); + + Rectangle actual = frame.getBounds(); + if (!actual.equals(maxTo)) { + System.err.println("Actual: " + actual); + System.err.println("Expected: " + maxTo); + throw new RuntimeException("Wrong bounds"); + } + } finally { + frame.dispose(); + } + } + } + } +} + diff --git a/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenSmall.java b/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenSmall.java new file mode 100644 index 00000000000..eac72fd0fbb --- /dev/null +++ b/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenSmall.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; + +/** + * @test + * @bug 8176359 8231564 + * @key headful + * @requires (os.family == "windows" | os.family == "mac") + * @summary setMaximizedBounds() should work if set to the screen other than + * current screen of the Frame, the size of the frame is intentionally + * small + */ +public final class MaximizedToOppositeScreenSmall { + + public static void main(String[] args) throws Exception { + //Supported platforms are Windows and OS X. + String os = System.getProperty("os.name").toLowerCase(); + if (!os.contains("windows") && !os.contains("os x")) { + return; + } + + if (!Toolkit.getDefaultToolkit(). + isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { + return; + } + + var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] gds = ge.getScreenDevices(); + Robot robot = new Robot(); + for (GraphicsDevice gd1 : gds) { + Rectangle framAt = gd1.getDefaultConfiguration().getBounds(); + framAt.grow(-framAt.width / 2 + 100, -framAt.height / 2 + 100); + for (GraphicsDevice gd2 : gds) { + Rectangle maxTo = gd2.getDefaultConfiguration().getBounds(); + maxTo.grow(-maxTo.width / 2 + 120, -maxTo.height / 2 + 120); + Frame frame = new Frame(gd1.getDefaultConfiguration()); + try { + frame.setBounds(framAt); + frame.setVisible(true); + robot.waitForIdle(); + robot.delay(1000); + + frame.setMaximizedBounds(maxTo); + frame.setExtendedState(Frame.MAXIMIZED_BOTH); + robot.waitForIdle(); + robot.delay(1000); + + Rectangle actual = frame.getBounds(); + if (!actual.equals(maxTo)) { + System.err.println("Actual: " + actual); + System.err.println("Expected: " + maxTo); + throw new RuntimeException("Wrong bounds"); + } + } finally { + frame.dispose(); + } + } + } + } +} + diff --git a/test/jdk/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java b/test/jdk/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java index 0a52a1e2334..3a5d95100b4 100644 --- a/test/jdk/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java +++ b/test/jdk/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,23 +21,27 @@ * questions. */ -import java.awt.*; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; /** * @test * @key headful - * @bug 8065739 8131339 + * @bug 8065739 8131339 8231564 + * @requires (os.family == "windows" | os.family == "mac") * @summary When Frame.setExtendedState(Frame.MAXIMIZED_BOTH) * is called for a Frame after been called setMaximizedBounds() with * certain value, Frame bounds must equal to this value. - * - * @run main SetMaximizedBounds */ - public class SetMaximizedBounds { public static void main(String[] args) throws Exception { - //Supported platforms are Windows and OS X. String os = System.getProperty("os.name").toLowerCase(); if (!os.contains("windows") && !os.contains("os x")) { @@ -52,10 +56,6 @@ public class SetMaximizedBounds { GraphicsEnvironment ge = GraphicsEnvironment. getLocalGraphicsEnvironment(); - if (ge.isHeadlessInstance()) { - return; - } - for (GraphicsDevice gd : ge.getScreenDevices()) { for (GraphicsConfiguration gc : gd.getConfigurations()) { testMaximizedBounds(gc, false); @@ -78,10 +78,10 @@ public class SetMaximizedBounds { frame = new Frame(); frame.setUndecorated(undecorated); Rectangle maximizedBounds = new Rectangle( - maxArea.x + maxArea.width / 6, - maxArea.y + maxArea.height / 6, - maxArea.width / 3, - maxArea.height / 3); + maxArea.x + maxArea.width / 5, + maxArea.y + maxArea.height / 5, + maxArea.width / 2, + maxArea.height / 2); frame.setMaximizedBounds(maximizedBounds); frame.setSize(maxArea.width / 8, maxArea.height / 8); frame.setVisible(true); @@ -93,6 +93,8 @@ public class SetMaximizedBounds { Rectangle bounds = frame.getBounds(); if (!bounds.equals(maximizedBounds)) { + System.err.println("Expected: " + maximizedBounds); + System.err.println("Actual: " + bounds); throw new RuntimeException("The bounds of the Frame do not equal to what" + " is specified when the frame is in Frame.MAXIMIZED_BOTH state"); } @@ -102,10 +104,10 @@ public class SetMaximizedBounds { robot.delay(1000); maximizedBounds = new Rectangle( - maxArea.x + maxArea.width / 10, - maxArea.y + maxArea.height / 10, - maxArea.width / 5, - maxArea.height / 5); + maxArea.x + maxArea.width / 6, + maxArea.y + maxArea.height / 6, + maxArea.width / 3, + maxArea.height / 3); frame.setMaximizedBounds(maximizedBounds); frame.setExtendedState(Frame.MAXIMIZED_BOTH); robot.waitForIdle(); @@ -113,6 +115,8 @@ public class SetMaximizedBounds { bounds = frame.getBounds(); if (!bounds.equals(maximizedBounds)) { + System.err.println("Expected: " + maximizedBounds); + System.err.println("Actual: " + bounds); throw new RuntimeException("The bounds of the Frame do not equal to what" + " is specified when the frame is in Frame.MAXIMIZED_BOTH state"); }