8003173: [macosx] Fullscreen on Mac leaves an empty rectangle
Reviewed-by: anthony, alexsch
--- a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java Thu Jan 24 17:26:32 2013 +0400
+++ b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java Thu Jan 24 17:50:03 2013 +0400
@@ -30,6 +30,7 @@
import java.awt.Window;
import java.awt.AWTPermission;
import java.awt.DisplayMode;
+import java.util.Objects;
import sun.java2d.opengl.CGLGraphicsConfig;
@@ -122,12 +123,12 @@
boolean fsSupported = isFullScreenSupported();
if (fsSupported && old != null) {
- // enter windowed mode (and restore original display mode)
- exitFullScreenExclusive(old);
+ // restore original display mode and enter windowed mode.
if (originalMode != null) {
setDisplayMode(originalMode);
originalMode = null;
}
+ exitFullScreenExclusive(old);
}
super.setFullScreenWindow(w);
@@ -186,13 +187,20 @@
}
@Override
- public void setDisplayMode(DisplayMode dm) {
+ public void setDisplayMode(final DisplayMode dm) {
if (dm == null) {
throw new IllegalArgumentException("Invalid display mode");
}
- nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(), dm.getBitDepth(), dm.getRefreshRate());
- if (isFullScreenSupported() && getFullScreenWindow() != null) {
- getFullScreenWindow().setSize(dm.getWidth(), dm.getHeight());
+ if (!Objects.equals(dm, getDisplayMode())) {
+ final Window w = getFullScreenWindow();
+ if (w != null) {
+ exitFullScreenExclusive(w);
+ }
+ nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(),
+ dm.getBitDepth(), dm.getRefreshRate());
+ if (isFullScreenSupported() && w != null) {
+ enterFullScreenExclusive(w);
+ }
}
}
--- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java Thu Jan 24 17:26:32 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java Thu Jan 24 17:50:03 2013 +0400
@@ -53,7 +53,7 @@
private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWWindowPeer");
- private PlatformWindow platformWindow;
+ private final PlatformWindow platformWindow;
// Window bounds reported by the native system (as opposed to
// regular bounds inherited from LWComponentPeer which are
@@ -554,12 +554,14 @@
/**
* Called by the {@code PlatformWindow} when this window is moved/resized by
- * user. There's no notifyReshape() in LWComponentPeer as the only
- * components which could be resized by user are top-level windows.
+ * user or window insets are changed. There's no notifyReshape() in
+ * LWComponentPeer as the only components which could be resized by user are
+ * top-level windows.
*/
public final void notifyReshape(int x, int y, int w, int h) {
final boolean moved;
final boolean resized;
+ final boolean invalid = updateInsets(platformWindow.getInsets());
synchronized (getStateLock()) {
moved = (x != sysX) || (y != sysY);
resized = (w != sysW) || (h != sysH);
@@ -570,7 +572,7 @@
}
// Check if anything changed
- if (!moved && !resized) {
+ if (!moved && !resized && !invalid) {
return;
}
// First, update peer's bounds
@@ -584,10 +586,10 @@
}
// Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events
- if (moved) {
+ if (moved || invalid) {
handleMove(x, y, true);
}
- if (resized) {
+ if (resized || invalid) {
handleResize(w, h, true);
repaintPeer();
}
@@ -999,27 +1001,21 @@
}
}
- /*
- * Request the window insets from the delegate and compares it
- * with the current one. This method is mostly called by the
- * delegate, e.g. when the window state is changed and insets
- * should be recalculated.
- *
+ /**
+ * Request the window insets from the delegate and compares it with the
+ * current one. This method is mostly called by the delegate, e.g. when the
+ * window state is changed and insets should be recalculated.
+ * <p/>
* This method may be called on the toolkit thread.
*/
- public boolean updateInsets(Insets newInsets) {
- boolean changed = false;
+ public final boolean updateInsets(final Insets newInsets) {
synchronized (getStateLock()) {
- changed = (insets.equals(newInsets));
+ if (insets.equals(newInsets)) {
+ return false;
+ }
insets = newInsets;
}
-
- if (changed) {
- replaceSurfaceData();
- repaintPeer();
- }
-
- return changed;
+ return true;
}
public static LWWindowPeer getWindowUnderCursor() {
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java Thu Jan 24 17:26:32 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java Thu Jan 24 17:50:03 2013 +0400
@@ -27,7 +27,6 @@
import java.awt.*;
import java.awt.geom.Rectangle2D;
-import java.awt.image.VolatileImage;
import sun.awt.CGraphicsConfig;
import sun.awt.CGraphicsEnvironment;
@@ -89,29 +88,8 @@
return peer;
}
- public void enterFullScreenMode(final long nsWindowPtr) {
+ public void enterFullScreenMode() {
CWrapper.NSView.enterFullScreenMode(ptr);
-
- // REMIND: CGLSurfaceData expects top-level's size
- // and therefore we need to account insets before
- // recreating the surface data
- Insets insets = peer.getInsets();
-
- Rectangle screenBounds;
- final long screenPtr = CWrapper.NSWindow.screen(nsWindowPtr);
- try {
- screenBounds = CWrapper.NSScreen.frame(screenPtr).getBounds();
- } finally {
- CWrapper.NSObject.release(screenPtr);
- }
-
- // the move/size notification from the underlying system comes
- // but it contains a bounds smaller than the whole screen
- // and therefore we need to create the synthetic notifications
- peer.notifyReshape(screenBounds.x - insets.left,
- screenBounds.y - insets.bottom,
- screenBounds.width + insets.left + insets.right,
- screenBounds.height + insets.top + insets.bottom);
}
public void exitFullScreenMode() {
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Thu Jan 24 17:26:32 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Thu Jan 24 17:50:03 2013 +0400
@@ -38,7 +38,6 @@
import sun.java2d.SurfaceData;
import sun.java2d.opengl.CGLSurfaceData;
import sun.lwawt.*;
-import sun.lwawt.LWWindowPeer.PeerType;
import sun.util.logging.PlatformLogger;
import com.apple.laf.*;
@@ -196,7 +195,8 @@
// 1) setting native bounds via nativeSetBounds() call
// 2) getting notification from the native level via deliverMoveResizeEvent()
private Rectangle nativeBounds = new Rectangle(0, 0, 0, 0);
- private volatile boolean isFullScreenMode = false;
+ private volatile boolean isFullScreenMode;
+ private boolean isFullScreenAnimationOn;
private Window target;
private LWWindowPeer peer;
@@ -414,8 +414,10 @@
@Override // PlatformWindow
public Insets getInsets() {
- final Insets insets = nativeGetNSWindowInsets(getNSWindowPtr());
- return insets;
+ if (!isFullScreenMode) {
+ return nativeGetNSWindowInsets(getNSWindowPtr());
+ }
+ return new Insets(0, 0, 0, 0);
}
@Override // PlatformWindow
@@ -727,7 +729,19 @@
@Override
public void enterFullScreenMode() {
isFullScreenMode = true;
- contentView.enterFullScreenMode(getNSWindowPtr());
+ contentView.enterFullScreenMode();
+ // the move/size notification from the underlying system comes
+ // but it contains a bounds smaller than the whole screen
+ // and therefore we need to create the synthetic notifications
+ Rectangle screenBounds;
+ final long screenPtr = CWrapper.NSWindow.screen(getNSWindowPtr());
+ try {
+ screenBounds = CWrapper.NSScreen.frame(screenPtr).getBounds();
+ } finally {
+ CWrapper.NSObject.release(screenPtr);
+ }
+ peer.notifyReshape(screenBounds.x, screenBounds.y, screenBounds.width,
+ screenBounds.height);
}
@Override
@@ -874,11 +888,10 @@
final Rectangle oldB = nativeBounds;
nativeBounds = new Rectangle(x, y, width, height);
peer.notifyReshape(x, y, width, height);
- if (byUser && !oldB.getSize().equals(nativeBounds.getSize())) {
+ if ((byUser && !oldB.getSize().equals(nativeBounds.getSize()))
+ || isFullScreenAnimationOn) {
flushBuffers();
}
- //TODO validateSurface already called from notifyReshape
- validateSurface();
}
private void deliverWindowClosingEvent() {
@@ -978,27 +991,19 @@
orderAboveSiblings();
}
- private void updateDisplay() {
- EventQueue.invokeLater(new Runnable() {
- public void run() {
- validateSurface();
- }
- });
+ private void windowWillEnterFullScreen() {
+ isFullScreenAnimationOn = true;
+ }
+
+ private void windowDidEnterFullScreen() {
+ isFullScreenAnimationOn = false;
}
- private void updateWindowContent() {
- ComponentEvent resizeEvent = new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED);
- SunToolkit.postEvent(SunToolkit.targetToAppContext(target), resizeEvent);
+ private void windowWillExitFullScreen() {
+ isFullScreenAnimationOn = true;
}
- private void windowWillEnterFullScreen() {
- updateWindowContent();
- }
- private void windowDidEnterFullScreen() {
- updateDisplay();
+ private void windowDidExitFullScreen() {
+ isFullScreenAnimationOn = false;
}
- private void windowWillExitFullScreen() {
- updateWindowContent();
- }
- private void windowDidExitFullScreen() {}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java Thu Jan 24 17:50:03 2013 +0400
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.AWTException;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.DisplayMode;
+import java.awt.Frame;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Insets;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.image.BufferedImage;
+
+import sun.awt.SunToolkit;
+
+/**
+ * @test
+ * @bug 8003173 7019055
+ * @summary Full-screen windows should have the proper insets.
+ * @author Sergey Bylokhov
+ */
+public final class FullScreenInsets {
+
+ private static boolean passed = true;
+
+ public static void main(final String[] args) {
+ final GraphicsEnvironment ge = GraphicsEnvironment
+ .getLocalGraphicsEnvironment();
+ final GraphicsDevice[] devices = ge.getScreenDevices();
+
+ final Window wGreen = new Frame();
+ wGreen.setBackground(Color.GREEN);
+ wGreen.setSize(300, 300);
+ wGreen.setVisible(true);
+ sleep();
+ final Insets iGreen = wGreen.getInsets();
+ final Dimension sGreen = wGreen.getSize();
+
+ final Window wRed = new Frame();
+ wRed.setBackground(Color.RED);
+ wRed.setSize(300, 300);
+ wRed.setVisible(true);
+ sleep();
+ final Insets iRed = wGreen.getInsets();
+ final Dimension sRed = wGreen.getSize();
+
+ for (final GraphicsDevice device : devices) {
+ if (!device.isFullScreenSupported()) {
+ continue;
+ }
+ device.setFullScreenWindow(wGreen);
+ sleep();
+ testWindowBounds(device.getDisplayMode(), wGreen);
+ testColor(wGreen, Color.GREEN);
+
+ device.setFullScreenWindow(wRed);
+ sleep();
+ testWindowBounds(device.getDisplayMode(), wRed);
+ testColor(wRed, Color.RED);
+
+ device.setFullScreenWindow(null);
+ sleep();
+ testInsets(wGreen.getInsets(), iGreen);
+ testInsets(wRed.getInsets(), iRed);
+ testSize(wGreen.getSize(), sGreen);
+ testSize(wRed.getSize(), sRed);
+ }
+ wGreen.dispose();
+ wRed.dispose();
+ if (!passed) {
+ throw new RuntimeException("Test failed");
+ }
+ }
+
+ private static void testSize(final Dimension actual, final Dimension exp) {
+ if (!exp.equals(actual)) {
+ System.err.println(" Wrong window size:" +
+ " Expected: " + exp + " Actual: " + actual);
+ passed = false;
+ }
+ }
+
+ private static void testInsets(final Insets actual, final Insets exp) {
+ if (!actual.equals(exp)) {
+ System.err.println(" Wrong window insets:" +
+ " Expected: " + exp + " Actual: " + actual);
+ passed = false;
+ }
+ }
+
+ private static void testWindowBounds(final DisplayMode dm, final Window w) {
+ if (w.getWidth() != dm.getWidth() || w.getHeight() != dm.getHeight()) {
+ System.err.println(" Wrong window bounds:" +
+ " Expected: width = " + dm.getWidth()
+ + ", height = " + dm.getHeight() + " Actual: "
+ + w.getSize());
+ passed = false;
+ }
+ }
+
+ private static void testColor(final Window w, final Color color) {
+ final Robot r;
+ try {
+ r = new Robot(w.getGraphicsConfiguration().getDevice());
+ } catch (AWTException e) {
+ e.printStackTrace();
+ passed = false;
+ return;
+ }
+ final BufferedImage bi = r.createScreenCapture(w.getBounds());
+ for (int y = 0; y < bi.getHeight(); y++) {
+ for (int x = 0; x < bi.getWidth(); x++) {
+ if (bi.getRGB(x, y) != color.getRGB()) {
+ System.err.println(
+ "Incorrect pixel at " + x + "x" + y + " : " +
+ Integer.toHexString(bi.getRGB(x, y)) +
+ " ,expected : " + Integer.toHexString(
+ color.getRGB()));
+ passed = false;
+ return;
+ }
+ }
+ }
+ }
+
+ private static void sleep() {
+ ((SunToolkit) Toolkit.getDefaultToolkit()).realSync();
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignored) {
+ }
+ }
+}