8065739: [macosx] Frame warps to lower left of screen when
authoralexsch
Fri, 22 May 2015 15:19:05 +0400
changeset 30944 b24bdcb53f5a
parent 30943 f228418099a8
child 30945 20e72c2570e2
8065739: [macosx] Frame warps to lower left of screen when 7124365: [macosx] setMaximizedBounds() should be implemented Reviewed-by: serb, azvegint
jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java
jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java
jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h
jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m
jdk/test/java/awt/Frame/MaximizedToUnmaximized/MaximizedToUnmaximized.java
jdk/test/java/awt/Frame/SetMaximizedBounds/MaximizedMovedWindow.java
jdk/test/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java	Wed May 20 17:10:15 2015 +0300
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java	Fri May 22 15:19:05 2015 +0400
@@ -61,6 +61,7 @@
     private static final int MINIMUM_HEIGHT = 1;
 
     private Insets insets = new Insets(0, 0, 0, 0);
+    private Rectangle maximizedBounds;
 
     private GraphicsDevice graphicsDevice;
     private GraphicsConfiguration graphicsConfig;
@@ -176,8 +177,10 @@
 
 
         if (getTarget() instanceof Frame) {
-            setTitle(((Frame) getTarget()).getTitle());
-            setState(((Frame) getTarget()).getExtendedState());
+            Frame frame = (Frame) getTarget();
+            setTitle(frame.getTitle());
+            setState(frame.getExtendedState());
+            setMaximizedBounds(frame.getMaximizedBounds());
         } else if (getTarget() instanceof Dialog) {
             setTitle(((Dialog) getTarget()).getTitle());
         }
@@ -543,9 +546,40 @@
         return windowState;
     }
 
+    private boolean isMaximizedBoundsSet() {
+        synchronized (getStateLock()) {
+            return maximizedBounds != null;
+        }
+    }
+
+    private Rectangle getDefaultMaximizedBounds() {
+        GraphicsConfiguration config = getGraphicsConfiguration();
+        Insets screenInsets = ((CGraphicsDevice) config.getDevice())
+                .getScreenInsets();
+        Rectangle gcBounds = config.getBounds();
+        return new Rectangle(
+                gcBounds.x + screenInsets.left,
+                gcBounds.y + screenInsets.top,
+                gcBounds.width - screenInsets.left - screenInsets.right,
+                gcBounds.height - screenInsets.top - screenInsets.bottom);
+    }
+
     @Override
     public void setMaximizedBounds(Rectangle bounds) {
-        // TODO: not implemented
+        boolean isMaximizedBoundsSet;
+        synchronized (getStateLock()) {
+            this.maximizedBounds = (isMaximizedBoundsSet = (bounds != null))
+                    ? constrainBounds(bounds) : null;
+        }
+
+        setPlatformMaximizedBounds(isMaximizedBoundsSet ? maximizedBounds
+                : getDefaultMaximizedBounds());
+    }
+
+    private void setPlatformMaximizedBounds(Rectangle bounds) {
+        platformWindow.setMaximizedBounds(
+                bounds.x, bounds.y,
+                bounds.width, bounds.height);
     }
 
     @Override
@@ -635,6 +669,10 @@
 
         // Second, update the graphics config and surface data
         final boolean isNewDevice = updateGraphicsDevice();
+        if (isNewDevice && !isMaximizedBoundsSet()) {
+            setPlatformMaximizedBounds(getDefaultMaximizedBounds());
+        }
+
         if (resized || isNewDevice) {
             replaceSurfaceData();
             updateMinimumSize();
@@ -1055,6 +1093,9 @@
     public final void displayChanged() {
         if (updateGraphicsDevice()) {
             updateMinimumSize();
+            if (!isMaximizedBoundsSet()) {
+                setPlatformMaximizedBounds(getDefaultMaximizedBounds());
+            }
         }
         // Replace surface unconditionally, because internal state of the
         // GraphicsDevice could be changed.
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java	Wed May 20 17:10:15 2015 +0300
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java	Fri May 22 15:19:05 2015 +0400
@@ -67,6 +67,11 @@
     public void setBounds(int x, int y, int w, int h);
 
     /*
+     * Sets the maximized bounds.
+     */
+    public default void setMaximizedBounds(int x, int y, int w, int h){}
+
+    /*
      * Returns the graphics device where the window is.
      */
     public GraphicsDevice getGraphicsDevice();
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Wed May 20 17:10:15 2015 +0300
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Fri May 22 15:19:05 2015 +0400
@@ -51,6 +51,8 @@
     private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr);
     private static native Insets nativeGetNSWindowInsets(long nsWindowPtr);
     private static native void nativeSetNSWindowBounds(long nsWindowPtr, double x, double y, double w, double h);
+    private static native void nativeSetNSWindowStandardFrame(long nsWindowPtr,
+            double x, double y, double w, double h);
     private static native void nativeSetNSWindowMinMax(long nsWindowPtr, double minW, double minH, double maxW, double maxH);
     private static native void nativePushNSWindowToBack(long nsWindowPtr);
     private static native void nativePushNSWindowToFront(long nsWindowPtr);
@@ -474,6 +476,10 @@
         nativeSetNSWindowBounds(getNSWindowPtr(), x, y, w, h);
     }
 
+    public void setMaximizedBounds(int x, int y, int w, int h) {
+        nativeSetNSWindowStandardFrame(getNSWindowPtr(), x, y, w, h);
+    }
+
     private boolean isMaximized() {
         return undecorated ? this.normalBounds != null
                 : CWrapper.NSWindow.isZoomed(getNSWindowPtr());
@@ -979,13 +985,11 @@
     }
 
     private void checkZoom() {
-        if (target instanceof Frame && isVisible()) {
-            Frame targetFrame = (Frame)target;
-            if (targetFrame.getExtendedState() != Frame.MAXIMIZED_BOTH && isMaximized()) {
-                deliverZoom(true);
-            } else if (targetFrame.getExtendedState() == Frame.MAXIMIZED_BOTH && !isMaximized()) {
-                deliverZoom(false);
-            }
+        int state = peer.getState();
+        if (state != Frame.MAXIMIZED_BOTH && isMaximized()) {
+            deliverZoom(true);
+        } else if (state == Frame.MAXIMIZED_BOTH && !isMaximized()) {
+            deliverZoom(false);
         }
     }
 
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h	Wed May 20 17:10:15 2015 +0300
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h	Fri May 22 15:19:05 2015 +0400
@@ -46,6 +46,7 @@
     NSWindow *nsWindow;
     AWTWindow *ownerWindow;
     jint preFullScreenLevel;
+    NSRect standardFrame;
 }
 
 // An instance of either AWTWindow_Normal or AWTWindow_Panel
@@ -59,7 +60,7 @@
 @property (nonatomic) jint styleBits;
 @property (nonatomic) BOOL isEnabled;
 @property (nonatomic) jint preFullScreenLevel;
-
+@property (nonatomic) NSRect standardFrame;
 
 - (id) initWithPlatformWindow:(JNFWeakJObjectWrapper *)javaPlatformWindow
                   ownerWindow:owner
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Wed May 20 17:10:15 2015 +0300
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Fri May 22 15:19:05 2015 +0400
@@ -184,6 +184,7 @@
 @synthesize isEnabled;
 @synthesize ownerWindow;
 @synthesize preFullScreenLevel;
+@synthesize standardFrame;
 
 - (void) updateMinMaxSize:(BOOL)resizable {
     if (resizable) {
@@ -509,6 +510,12 @@
     // window exposing in _setVisible:(BOOL)
 }
 
+- (NSRect)windowWillUseStandardFrame:(NSWindow *)window
+                        defaultFrame:(NSRect)newFrame {
+
+    return [self standardFrame];
+}
+
 - (void) _deliverIconify:(BOOL)iconify {
 AWT_ASSERT_APPKIT_THREAD;
 
@@ -953,6 +960,30 @@
 
 /*
  * Class:     sun_lwawt_macosx_CPlatformWindow
+ * Method:    nativeSetNSWindowStandardFrame
+ * Signature: (JDDDD)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStandardFrame
+(JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY,
+     jdouble width, jdouble height)
+{
+    JNF_COCOA_ENTER(env);
+    
+    NSRect jrect = NSMakeRect(originX, originY, width, height);
+    
+    NSWindow *nsWindow = OBJC(windowPtr);
+    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
+        
+        NSRect rect = ConvertNSScreenRect(NULL, jrect);
+        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
+        window.standardFrame = rect;
+    }];
+    
+    JNF_COCOA_EXIT(env);
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPlatformWindow
  * Method:    nativeSetNSWindowMinMax
  * Signature: (JDDDD)V
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/MaximizedToUnmaximized/MaximizedToUnmaximized.java	Fri May 22 15:19:05 2015 +0400
@@ -0,0 +1,79 @@
+/*
+ * 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.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+
+/**
+ * @test
+ * @bug 8065739
+ * @summary [macosx] Frame warps to lower left of screen when displayed
+ * @author Alexandr Scherbatiy
+ */
+public class MaximizedToUnmaximized {
+
+    public static void main(String[] args) throws Exception {
+        testFrame(false);
+        testFrame(true);
+    }
+
+    static void testFrame(boolean isUndecorated) throws Exception {
+        Frame frame = new Frame();
+        try {
+            Robot robot = new Robot();
+            robot.setAutoDelay(100);
+
+            frame.setUndecorated(isUndecorated);
+            GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
+                    .getDefaultScreenDevice().getDefaultConfiguration();
+            Rectangle bounds = gc.getBounds();
+            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+            int x = bounds.x + insets.left;
+            int y = bounds.y + insets.top;
+            int width = bounds.width - insets.left - insets.right;
+            int height = bounds.height - insets.top - insets.bottom;
+            Rectangle rect = new Rectangle(x, y, width, height);
+            frame.pack();
+            frame.setBounds(rect);
+            frame.setVisible(true);
+            robot.waitForIdle();
+            robot.delay(500);
+
+            if (frame.getWidth() <= width / 2
+                    || frame.getHeight() <= height / 2) {
+                throw new RuntimeException("Frame size is small!");
+            }
+
+            if (!isUndecorated && frame.getExtendedState() != Frame.MAXIMIZED_BOTH) {
+                throw new RuntimeException("Frame state does not equal"
+                        + " MAXIMIZED_BOTH!");
+            }
+        } finally {
+            frame.dispose();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/SetMaximizedBounds/MaximizedMovedWindow.java	Fri May 22 15:19:05 2015 +0400
@@ -0,0 +1,127 @@
+/*
+ * 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.*;
+
+/*
+ * @test
+ * @bug 8065739
+ * @summary Moved window is maximazed to new screen
+ * @author Alexandr Scherbatiy
+ *
+ * @run main MaximizedMovedWindow
+ */
+public class MaximizedMovedWindow {
+
+    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("os x")) {
+            return;
+        }
+
+        if (!Toolkit.getDefaultToolkit().
+                isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
+            return;
+        }
+
+        GraphicsEnvironment ge = GraphicsEnvironment.
+                getLocalGraphicsEnvironment();
+
+        if (ge.isHeadlessInstance()) {
+            return;
+        }
+
+        GraphicsDevice[] devices = ge.getScreenDevices();
+
+        if (devices.length < 2) {
+            return;
+        }
+
+        Frame frame = null;
+        try {
+
+            GraphicsConfiguration gc1 = devices[0].getDefaultConfiguration();
+            GraphicsConfiguration gc2 = devices[1].getDefaultConfiguration();
+
+            Robot robot = new Robot();
+            robot.setAutoDelay(50);
+
+            frame = new Frame();
+            Rectangle maxArea1 = getMaximizedScreenArea(gc1);
+            frame.setBounds(getSmallerRectangle(maxArea1));
+            frame.setVisible(true);
+            robot.waitForIdle();
+
+            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            Rectangle bounds = frame.getBounds();
+            if (!bounds.equals(maxArea1)) {
+                throw new RuntimeException("The bounds of the Frame do not equal"
+                        + " to screen 1 size");
+            }
+
+            frame.setExtendedState(Frame.NORMAL);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            Rectangle maxArea2 = getMaximizedScreenArea(gc2);
+            frame.setBounds(getSmallerRectangle(maxArea2));
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            bounds = frame.getBounds();
+            if (!bounds.equals(maxArea2)) {
+                throw new RuntimeException("The bounds of the Frame do not equal"
+                        + " to screen 2 size");
+            }
+        } finally {
+            if (frame != null) {
+                frame.dispose();
+            }
+        }
+    }
+
+    static Rectangle getSmallerRectangle(Rectangle rect) {
+        return new Rectangle(
+                rect.x + rect.width / 6,
+                rect.y + rect.height / 6,
+                rect.width / 3,
+                rect.height / 3);
+    }
+    static Rectangle getMaximizedScreenArea(GraphicsConfiguration gc) {
+        Rectangle bounds = gc.getBounds();
+        Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+        return new Rectangle(
+                bounds.x + insets.left,
+                bounds.y + insets.top,
+                bounds.width - insets.left - insets.right,
+                bounds.height - insets.top - insets.bottom);
+    }
+}
--- a/jdk/test/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java	Wed May 20 17:10:15 2015 +0300
+++ b/jdk/test/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java	Fri May 22 15:19:05 2015 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -22,67 +22,108 @@
  */
 
 import java.awt.*;
-
 /*
  * @test
  * @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.
  *
- * @library ../../../../lib/testlibrary
- * @build ExtendedRobot
  * @run main SetMaximizedBounds
  */
 
 public class SetMaximizedBounds {
 
-    Frame frame;
-    Rectangle bound;
-    boolean supported;
-    ExtendedRobot robot;
-    static Rectangle max = new Rectangle(100,100,400,400);
+    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;
+        }
 
-    public void doTest() throws Exception {
-        robot = new ExtendedRobot();
+        GraphicsEnvironment ge = GraphicsEnvironment.
+                getLocalGraphicsEnvironment();
+
+        if (ge.isHeadlessInstance()) {
+            return;
+        }
+
+        for (GraphicsDevice gd : ge.getScreenDevices()) {
+            for (GraphicsConfiguration gc : gd.getConfigurations()) {
+                testMaximizedBounds(gc);
+            }
+        }
+    }
 
-        EventQueue.invokeAndWait( () -> {
-            frame = new Frame( "TestFrame ");
-            frame.setLayout(new FlowLayout());
+    static void testMaximizedBounds(GraphicsConfiguration gc) throws Exception {
+
+        Frame frame = null;
+        try {
+
+            Rectangle maxArea = getMaximizedScreenArea(gc);
+
+            Robot robot = new Robot();
+            robot.setAutoDelay(50);
 
-            if (Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
-                supported = true;
-                frame.setMaximizedBounds(max);
-            } else {
-                supported = false;
+            frame = new Frame();
+            Rectangle maximizedBounds = new Rectangle(
+                    maxArea.x + maxArea.width / 6,
+                    maxArea.y + maxArea.height / 6,
+                    maxArea.width / 3,
+                    maxArea.height / 3);
+            frame.setMaximizedBounds(maximizedBounds);
+            frame.setSize(maxArea.width / 8, maxArea.height / 8);
+            frame.setVisible(true);
+            robot.waitForIdle();
+
+            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            Rectangle bounds = frame.getBounds();
+            if (!bounds.equals(maximizedBounds)) {
+                throw new RuntimeException("The bounds of the Frame do not equal to what"
+                        + " is specified when the frame is in Frame.MAXIMIZED_BOTH state");
             }
 
-            frame.setSize(200, 200);
-            frame.setVisible(true);
-        });
+            frame.setExtendedState(Frame.NORMAL);
+            robot.waitForIdle();
+            robot.delay(1000);
 
-        robot.waitForIdle(2000);
-        if (supported) {
-            EventQueue.invokeAndWait( () -> {
-                frame.setExtendedState(Frame.MAXIMIZED_BOTH);
-            });
-            robot.waitForIdle(2000);
-            bound = frame.getBounds();
-            if(!bound.equals(max))
+            maximizedBounds = new Rectangle(
+                    maxArea.x + maxArea.width / 10,
+                    maxArea.y + maxArea.height / 10,
+                    maxArea.width / 5,
+                    maxArea.height / 5);
+            frame.setMaximizedBounds(maximizedBounds);
+            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            bounds = frame.getBounds();
+            if (!bounds.equals(maximizedBounds)) {
                 throw new RuntimeException("The bounds of the Frame do not equal to what"
-                    + " is specified when the frame is in Frame.MAXIMIZED_BOTH state");
-        } else {
-            System.out.println("Frame.MAXIMIZED_BOTH not supported");
+                        + " is specified when the frame is in Frame.MAXIMIZED_BOTH state");
+            }
+        } finally {
+            if (frame != null) {
+                frame.dispose();
+            }
         }
-
-        frame.dispose();
     }
 
-    public static void main(String[] args) throws Exception {
-        String os = System.getProperty("os.name").toLowerCase();
-        System.out.println(os);
-        if (os.contains("windows") || os.contains("os x"))
-            new SetMaximizedBounds().doTest();
-        else
-            System.out.println("Platform "+os+" is not supported. Supported platforms are Windows and OS X.");
+    static Rectangle getMaximizedScreenArea(GraphicsConfiguration gc) {
+        Rectangle bounds = gc.getBounds();
+        Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+        return new Rectangle(
+                bounds.x + insets.left,
+                bounds.y + insets.top,
+                bounds.width - insets.left - insets.right,
+                bounds.height - insets.top - insets.bottom);
     }
 }