8009012: [macosx] DisplayChangedListener is not implemented in LWWindowPeer/CGraphicsEnvironment
authorserb
Wed, 01 May 2013 12:19:25 +0400
changeset 17151 9bfcf2a592fc
parent 17150 a842e8c6660a
child 17152 0467e4708200
8009012: [macosx] DisplayChangedListener is not implemented in LWWindowPeer/CGraphicsEnvironment Reviewed-by: anthony, bae
jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java
jdk/src/macosx/classes/sun/awt/CGraphicsEnvironment.java
jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java
jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
jdk/src/macosx/native/sun/awt/CGraphicsEnv.m
jdk/src/macosx/native/sun/java2d/opengl/CGLLayer.m
--- a/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java	Tue Apr 30 17:27:48 2013 +0400
+++ b/jdk/src/macosx/classes/sun/awt/CGraphicsDevice.java	Wed May 01 12:19:25 2013 +0400
@@ -35,10 +35,18 @@
 
 import sun.java2d.opengl.CGLGraphicsConfig;
 
-public final class CGraphicsDevice extends GraphicsDevice {
+public final class CGraphicsDevice extends GraphicsDevice
+        implements DisplayChangedListener {
 
-    // CoreGraphics display ID
-    private final int displayID;
+    /**
+     * CoreGraphics display ID. This identifier can become non-valid at any time
+     * therefore methods, which is using this id should be ready to it.
+     */
+    private volatile int displayID;
+    private volatile Insets screenInsets;
+    private volatile double xResolution;
+    private volatile double yResolution;
+    private volatile int scale;
 
     // Array of all GraphicsConfig instances for this device
     private final GraphicsConfiguration[] configs;
@@ -51,7 +59,7 @@
     // Save/restore DisplayMode for the Full Screen mode
     private DisplayMode originalMode;
 
-    public CGraphicsDevice(int displayID) {
+    public CGraphicsDevice(final int displayID) {
         this.displayID = displayID;
         configs = new GraphicsConfiguration[] {
             CGLGraphicsConfig.getConfig(this, 0)
@@ -89,7 +97,7 @@
      */
     @Override
     public String getIDstring() {
-        return "Display " + this.displayID;
+        return "Display " + displayID;
     }
 
     /**
@@ -104,15 +112,37 @@
     }
 
     public double getXResolution() {
-        return nativeGetXResolution(displayID);
+        return xResolution;
     }
 
     public double getYResolution() {
-        return nativeGetYResolution(displayID);
+        return yResolution;
     }
 
     public Insets getScreenInsets() {
-        return nativeGetScreenInsets(displayID);
+        return screenInsets;
+    }
+
+    public int getScaleFactor() {
+        return scale;
+    }
+
+    public void invalidate(final int defaultDisplayID) {
+        displayID = defaultDisplayID;
+    }
+
+    @Override
+    public void displayChanged() {
+        xResolution = nativeGetXResolution(displayID);
+        yResolution = nativeGetYResolution(displayID);
+        screenInsets = nativeGetScreenInsets(displayID);
+        scale = (int) nativeGetScaleFactor(displayID);
+        //TODO configs/fullscreenWindow/modes?
+    }
+
+    @Override
+    public void paletteChanged() {
+        // devices do not need to react to this event.
     }
 
     /**
@@ -219,10 +249,6 @@
         return nativeGetDisplayModes(displayID);
     }
 
-    public int getScaleFactor() {
-        return (int) nativeGetScaleFactor(displayID);
-    }
-
     private static native double nativeGetScaleFactor(int displayID);
 
     private static native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate);
--- a/jdk/src/macosx/classes/sun/awt/CGraphicsEnvironment.java	Tue Apr 30 17:27:48 2013 +0400
+++ b/jdk/src/macosx/classes/sun/awt/CGraphicsEnvironment.java	Wed May 01 12:19:25 2013 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -26,19 +26,20 @@
 package sun.awt;
 
 import java.awt.*;
-import java.awt.print.*;
 import java.util.*;
 
 import sun.java2d.*;
 
 /**
- * This is an implementation of a GraphicsEnvironment object for the default local GraphicsEnvironment used by the Java
- * Runtime Environment for Mac OS X GUI environments.
+ * This is an implementation of a GraphicsEnvironment object for the default
+ * local GraphicsEnvironment used by the Java Runtime Environment for Mac OS X
+ * GUI environments.
  *
  * @see GraphicsDevice
  * @see GraphicsConfiguration
  */
-public class CGraphicsEnvironment extends SunGraphicsEnvironment {
+public final class CGraphicsEnvironment extends SunGraphicsEnvironment {
+
     // Global initialization of the Cocoa runtime.
     private static native void initCocoa();
 
@@ -53,7 +54,8 @@
     private static native int getMainDisplayID();
 
     /**
-     * Noop function that just acts as an entry point for someone to force a static initialization of this class.
+     * Noop function that just acts as an entry point for someone to force a
+     * static initialization of this class.
      */
     public static void init() { }
 
@@ -78,8 +80,9 @@
     }
 
     /**
-     * Register the instance with CGDisplayRegisterReconfigurationCallback()
-     * The registration uses a weak global reference -- if our instance is garbage collected, the reference will be dropped.
+     * Register the instance with CGDisplayRegisterReconfigurationCallback().
+     * The registration uses a weak global reference -- if our instance is
+     * garbage collected, the reference will be dropped.
      *
      * @return Return the registration context (a pointer).
      */
@@ -91,7 +94,7 @@
     private native void deregisterDisplayReconfiguration(long context);
 
     /** Available CoreGraphics displays. */
-    private final Map<Integer, CGraphicsDevice> devices = new HashMap<Integer, CGraphicsDevice>();
+    private final Map<Integer, CGraphicsDevice> devices = new HashMap<>(5);
 
     /** Reference to the display reconfiguration callback context. */
     private final long displayReconfigContext;
@@ -118,11 +121,18 @@
     /**
      * Called by the CoreGraphics Display Reconfiguration Callback.
      *
-     * @param displayId
-     *            CoreGraphics displayId
+     * @param displayId CoreGraphics displayId
+     * @param removed   true if displayId was removed, false otherwise.
      */
-    void _displayReconfiguration(long displayId) {
-        displayChanged();
+    void _displayReconfiguration(final int displayId, final boolean removed) {
+        synchronized (this) {
+            if (removed && devices.containsKey(displayId)) {
+                final CGraphicsDevice gd = devices.remove(displayId);
+                gd.invalidate(getMainDisplayID());
+                gd.displayChanged();
+            }
+        }
+        initDevices();
     }
 
     @Override
@@ -135,31 +145,30 @@
     }
 
     /**
-     * (Re)create all CGraphicsDevices
-     *
-     * @return
+     * (Re)create all CGraphicsDevices, reuses a devices if it is possible.
      */
-    private synchronized void initDevices() {
-        devices.clear();
+    private void initDevices() {
+        synchronized (this) {
+            final Map<Integer, CGraphicsDevice> old = new HashMap<>(devices);
+            devices.clear();
 
-        int mainID = getMainDisplayID();
+            int mainID = getMainDisplayID();
 
-        // initialization of the graphics device may change
-        // list of displays on hybrid systems via an activation
-        // of discrete video.
-        // So, we initialize the main display first, and then
-        // retrieve actual list of displays.
-        CGraphicsDevice mainDevice = new CGraphicsDevice(mainID);
+            // initialization of the graphics device may change
+            // list of displays on hybrid systems via an activation
+            // of discrete video.
+            // So, we initialize the main display first, and then
+            // retrieve actual list of displays.
+            if (!old.containsKey(mainID)) {
+                old.put(mainID, new CGraphicsDevice(mainID));
+            }
 
-        final int[] displayIDs = getDisplayIDs();
-
-        for (int displayID : displayIDs) {
-            if (displayID != mainID) {
-                devices.put(displayID, new CGraphicsDevice(displayID));
-            } else {
-                devices.put(mainID, mainDevice);
+            for (final int id : getDisplayIDs()) {
+                devices.put(id, old.containsKey(id) ? old.get(id)
+                                                    : new CGraphicsDevice(id));
             }
         }
+        displayChanged();
     }
 
     @Override
@@ -167,7 +176,7 @@
         final int mainDisplayID = getMainDisplayID();
         CGraphicsDevice d = devices.get(mainDisplayID);
         if (d == null) {
-            // we do not exepct that this may happen, the only responce
+            // we do not expect that this may happen, the only response
             // is to re-initialize the list of devices
             initDevices();
 
--- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java	Tue Apr 30 17:27:48 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java	Wed May 01 12:19:25 2013 +0400
@@ -41,7 +41,7 @@
 
 public class LWWindowPeer
     extends LWContainerPeer<Window, JComponent>
-    implements WindowPeer, FramePeer, DialogPeer, FullScreenCapable
+    implements FramePeer, DialogPeer, FullScreenCapable, DisplayChangedListener
 {
     public static enum PeerType {
         SIMPLEWINDOW,
@@ -189,6 +189,7 @@
         if (getSurfaceData() == null) {
             replaceSurfaceData(false);
         }
+        activateDisplayListener();
     }
 
     // Just a helper method
@@ -205,6 +206,7 @@
 
     @Override
     protected void disposeImpl() {
+        deactivateDisplayListener();
         SurfaceData oldData = getSurfaceData();
         synchronized (surfaceDataLock){
             surfaceData = null;
@@ -875,6 +877,18 @@
 
     // ---- UTILITY METHODS ---- //
 
+    private void activateDisplayListener() {
+        final GraphicsEnvironment ge =
+                GraphicsEnvironment.getLocalGraphicsEnvironment();
+        ((SunGraphicsEnvironment) ge).addDisplayChangedListener(this);
+    }
+
+    private void deactivateDisplayListener() {
+        final GraphicsEnvironment ge =
+                GraphicsEnvironment.getLocalGraphicsEnvironment();
+        ((SunGraphicsEnvironment) ge).removeDisplayChangedListener(this);
+    }
+
     private void postWindowStateChangedEvent(int newWindowState) {
         if (getTarget() instanceof Frame) {
             AWTAccessor.getFrameAccessor().setExtendedState(
@@ -936,7 +950,6 @@
             graphicsDevice = newGraphicsDevice;
         }
 
-        // TODO: DisplayChangedListener stuff
         final GraphicsConfiguration newGC = newGraphicsDevice.getDefaultConfiguration();
 
         if (!setGraphicsConfig(newGC)) return false;
@@ -949,6 +962,20 @@
         return true;
     }
 
+    @Override
+    public final void displayChanged() {
+        updateGraphicsDevice();
+        // Replace surface unconditionally, because internal state of the
+        // GraphicsDevice could be changed.
+        replaceSurfaceData();
+        repaintPeer();
+    }
+
+    @Override
+    public final void paletteChanged() {
+        // components do not need to react to this event.
+    }
+
     /*
      * May be called by delegate to provide SD to Java2D code.
      */
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Tue Apr 30 17:27:48 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Wed May 01 12:19:25 2013 +0400
@@ -32,6 +32,7 @@
 import java.beans.*;
 import java.lang.reflect.InvocationTargetException;
 import java.util.List;
+import java.util.Objects;
 
 import javax.swing.*;
 
@@ -916,9 +917,12 @@
 
         final Rectangle oldB = nativeBounds;
         nativeBounds = new Rectangle(x, y, width, height);
+        final GraphicsConfiguration oldGC = peer.getGraphicsConfiguration();
         peer.notifyReshape(x, y, width, height);
+        final GraphicsConfiguration newGC = peer.getGraphicsConfiguration();
+        // System-dependent appearance optimization.
         if ((byUser && !oldB.getSize().equals(nativeBounds.getSize()))
-            || isFullScreenAnimationOn) {
+            || isFullScreenAnimationOn || !Objects.equals(newGC, oldGC)) {
             flushBuffers();
         }
     }
--- a/jdk/src/macosx/native/sun/awt/CGraphicsEnv.m	Tue Apr 30 17:27:48 2013 +0400
+++ b/jdk/src/macosx/native/sun/awt/CGraphicsEnv.m	Wed May 01 12:19:25 2013 +0400
@@ -124,10 +124,11 @@
 
         jobject graphicsEnv = [wrapper jObjectWithEnv:env];
         if (graphicsEnv == NULL) return; // ref already GC'd
-
         static JNF_CLASS_CACHE(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
-        static JNF_MEMBER_CACHE(jm_displayReconfiguration, jc_CGraphicsEnvironment, "_displayReconfiguration", "(J)V");
-        JNFCallVoidMethod(env, graphicsEnv, jm_displayReconfiguration);
+        static JNF_MEMBER_CACHE(jm_displayReconfiguration, jc_CGraphicsEnvironment, "_displayReconfiguration", "(IZ)V");
+        JNFCallVoidMethod(env, graphicsEnv, jm_displayReconfiguration,
+                            (jint) display, 
+                            (jboolean) flags & kCGDisplayRemoveFlag);
     });
 }
 
--- a/jdk/src/macosx/native/sun/java2d/opengl/CGLLayer.m	Tue Apr 30 17:27:48 2013 +0400
+++ b/jdk/src/macosx/native/sun/java2d/opengl/CGLLayer.m	Wed May 01 12:19:25 2013 +0400
@@ -216,7 +216,11 @@
 {
     JNF_COCOA_ENTER(env);
     CGLLayer *layer = jlong_to_ptr(layerPtr);
-    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
+    // We always call all setXX methods asynchronously, exception is only in 
+    // this method where we need to change native texture size and layer's scale
+    // in one call on appkit, otherwise we'll get window's contents blinking, 
+    // during screen-2-screen moving.
+    [ThreadUtilities performOnMainThreadWaiting:[NSThread isMainThread] block:^(){
         layer.contentsScale = scale;
     }];
     JNF_COCOA_EXIT(env);