7198229: Painting during resizing of the frame should be more smooth
authorserb
Mon, 29 Oct 2012 23:10:41 +0400
changeset 14306 8d823e84507a
parent 14305 52548c249171
child 14307 2378cc5c46cc
7198229: Painting during resizing of the frame should be more smooth Reviewed-by: anthony, denis, skovatch
jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java
jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java
jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java
jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java
jdk/src/macosx/native/sun/awt/AWTView.m
jdk/src/macosx/native/sun/java2d/opengl/CGLLayer.m
--- a/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java	Thu Oct 25 19:50:30 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/LWWindowPeer.java	Mon Oct 29 23:10:41 2012 +0400
@@ -598,29 +598,21 @@
     }
 
     /**
-     * Called by the delegate when any part of the window should be repainted.
+     * Called by the {@code PlatformWindow} when any part of the window should
+     * be repainted.
      */
-    public void notifyExpose(final int x, final int y, final int w, final int h) {
-        // TODO: there's a serious problem with Swing here: it handles
-        // the exposition internally, so SwingPaintEventDispatcher always
-        // return null from createPaintEvent(). However, we flush the
-        // back buffer here unconditionally, so some flickering may appear.
-        // A possible solution is to split postPaintEvent() into two parts,
-        // and override that part which is only called after if
-        // createPaintEvent() returned non-null value and flush the buffer
-        // from the overridden method
-        flushOnscreenGraphics();
-        repaintPeer(new Rectangle(x, y, w, h));
+    public final void notifyExpose(final Rectangle r) {
+        repaintPeer(r);
     }
 
     /**
-     * Called by the delegate when this window is moved/resized by user.
-     * There's no notifyReshape() in LWComponentPeer as the only
+     * 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.
      */
     public final void notifyReshape(int x, int y, int w, int h) {
-        boolean moved = false;
-        boolean resized = false;
+        final boolean moved;
+        final boolean resized;
         synchronized (getStateLock()) {
             moved = (x != sysX) || (y != sysY);
             resized = (w != sysW) || (h != sysH);
@@ -644,12 +636,13 @@
             flushOnscreenGraphics();
         }
 
-        // Third, COMPONENT_MOVED/COMPONENT_RESIZED events
+        // Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events
         if (moved) {
             handleMove(x, y, true);
         }
         if (resized) {
-            handleResize(w, h,true);
+            handleResize(w, h, true);
+            repaintPeer();
         }
     }
 
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java	Thu Oct 25 19:50:30 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformView.java	Mon Oct 29 23:10:41 2012 +0400
@@ -26,7 +26,6 @@
 package sun.lwawt.macosx;
 
 import java.awt.*;
-import java.awt.event.*;
 import java.awt.image.VolatileImage;
 
 import sun.awt.CGraphicsConfig;
@@ -202,12 +201,11 @@
                                  event.getCharactersIgnoringModifiers(), event.getKeyCode(), true);
     }
 
+    /**
+     * Called by the native delegate in layer backed view mode or in the simple
+     * NSView mode. See NSView.drawRect().
+     */
     private void deliverWindowDidExposeEvent() {
-        Rectangle r = peer.getBounds();
-        peer.notifyExpose(0, 0, r.width, r.height);
-    }
-
-    private void deliverWindowDidExposeEvent(float x, float y, float w, float h) {
-        peer.notifyExpose((int)x, (int)y, (int)w, (int)h);
+        peer.notifyExpose(peer.getSize());
     }
 }
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Thu Oct 25 19:50:30 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Mon Oct 29 23:10:41 2012 +0400
@@ -46,7 +46,7 @@
 import com.apple.laf.ClientPropertyApplicator.Property;
 import com.sun.awt.AWTUtilities;
 
-public class CPlatformWindow extends CFRetainedResource implements PlatformWindow {
+public final class CPlatformWindow extends CFRetainedResource implements PlatformWindow {
     private native long nativeCreateNSWindow(long nsViewPtr, long styleBits, double x, double y, double w, double h);
     private static native void nativeSetNSWindowStyleBits(long nsWindowPtr, int mask, int data);
     private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr);
@@ -199,7 +199,7 @@
     // In order to keep it up-to-date we will update them on
     // 1) setting native bounds via nativeSetBounds() call
     // 2) getting notification from the native level via deliverMoveResizeEvent()
-    private Rectangle nativeBounds;
+    private Rectangle nativeBounds = new Rectangle(0, 0, 0, 0);
     private volatile boolean isFullScreenMode = false;
 
     private Window target;
@@ -869,6 +869,12 @@
         }
     }
 
+    private void flushBuffers() {
+        if (isVisible() && !nativeBounds.isEmpty()) {
+            LWCToolkit.getLWCToolkit().flushPendingEventsOnAppkit(target);
+        }
+    }
+
     /*************************************************************
      * Callbacks from the AWTWindow and AWTView objc classes.
      *************************************************************/
@@ -886,10 +892,16 @@
         // move/resize notifications contain a bounds smaller than
         // the whole screen and therefore we ignore the native notifications
         // and the content view itself creates correct synthetic notifications
-        if (isFullScreenMode) return;
+        if (isFullScreenMode) {
+            return;
+        }
 
+        final Rectangle oldB = nativeBounds;
         nativeBounds = new Rectangle(x, y, width, height);
         peer.notifyReshape(x, y, width, height);
+        if (!oldB.getSize().equals(nativeBounds.getSize()) ) {
+            flushBuffers();
+        }
         //TODO validateSurface already called from notifyReshape
         validateSurface();
     }
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Thu Oct 25 19:50:30 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Mon Oct 29 23:10:41 2012 +0400
@@ -150,6 +150,10 @@
            });
     }
 
+    public static LWCToolkit getLWCToolkit() {
+        return (LWCToolkit)Toolkit.getDefaultToolkit();
+    }
+
     @Override
     protected PlatformWindow createPlatformWindow(PeerType peerType) {
         if (peerType == PeerType.EMBEDDEDFRAME) {
@@ -407,7 +411,6 @@
         return BUTTONS;
     }
 
-
     @Override
     public boolean isTraySupported() {
         return true;
@@ -489,6 +492,22 @@
         synchronized(ret) { return ret[0]; }
     }
 
+    /**
+     * Just a wrapper for LWCToolkit.invokeAndWait. Posts an empty event to the
+     * appropriate event queue and waits for it to finish.
+     */
+    public static void flushPendingEventsOnAppkit(final Component component) {
+        try {
+            invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                }
+            }, component);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
     // Kicks an event over to the appropriate eventqueue and waits for it to finish
     // To avoid deadlocking, we manually run the NSRunLoop while waiting
     // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop
--- a/jdk/src/macosx/native/sun/awt/AWTView.m	Thu Oct 25 19:50:30 2012 +0400
+++ b/jdk/src/macosx/native/sun/awt/AWTView.m	Mon Oct 29 23:10:41 2012 +0400
@@ -86,11 +86,14 @@
 
     if (windowLayer != nil) {
         self.cglLayer = windowLayer;
+        //Layer hosting view
+        [self setLayer: cglLayer];
         [self setWantsLayer: YES];
-        [self.layer addSublayer: (CALayer *)cglLayer];
-        [self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize];
-        [self setLayerContentsPlacement: NSViewLayerContentsPlacementTopLeft];
-        [self setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
+        //Layer backed view
+        //[self.layer addSublayer: (CALayer *)cglLayer];
+        //[self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize];
+        //[self setLayerContentsPlacement: NSViewLayerContentsPlacementTopLeft];
+        //[self setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
 
 #ifdef REMOTELAYER
         CGLLayer *parentLayer = (CGLLayer*)self.cglLayer;
--- a/jdk/src/macosx/native/sun/java2d/opengl/CGLLayer.m	Thu Oct 25 19:50:30 2012 +0400
+++ b/jdk/src/macosx/native/sun/java2d/opengl/CGLLayer.m	Mon Oct 29 23:10:41 2012 +0400
@@ -57,9 +57,10 @@
 
     // NOTE: async=YES means that the layer is re-cached periodically
     self.asynchronous = FALSE;
-    self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
     self.contentsGravity = kCAGravityTopLeft;
-    self.needsDisplayOnBoundsChange = YES;
+    //Layer backed view
+    //self.needsDisplayOnBoundsChange = YES;
+    //self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
     textureID = 0; // texture will be created by rendering pipe
     target = 0;
 
@@ -109,6 +110,10 @@
     glDisable(target);
 }
 
+-(BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp{
+    return textureID == 0 ? NO : YES;
+}
+
 -(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
 {
     AWT_ASSERT_APPKIT_THREAD;