7198229: Painting during resizing of the frame should be more smooth

Reviewed-by: anthony, denis, skovatch
This commit is contained in:
Sergey Bylokhov 2012-10-29 23:10:41 +04:00
parent bf6c304c44
commit 46c74fcecb
6 changed files with 65 additions and 35 deletions

View File

@ -598,29 +598,21 @@ public class LWWindowPeer
} }
/** /**
* 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) { public final void notifyExpose(final Rectangle r) {
// TODO: there's a serious problem with Swing here: it handles repaintPeer(r);
// 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));
} }
/** /**
* Called by the delegate when this window is moved/resized by user. * Called by the {@code PlatformWindow} when this window is moved/resized by
* There's no notifyReshape() in LWComponentPeer as the only * user. There's no notifyReshape() in LWComponentPeer as the only
* components which could be resized by user are top-level windows. * components which could be resized by user are top-level windows.
*/ */
public final void notifyReshape(int x, int y, int w, int h) { public final void notifyReshape(int x, int y, int w, int h) {
boolean moved = false; final boolean moved;
boolean resized = false; final boolean resized;
synchronized (getStateLock()) { synchronized (getStateLock()) {
moved = (x != sysX) || (y != sysY); moved = (x != sysX) || (y != sysY);
resized = (w != sysW) || (h != sysH); resized = (w != sysW) || (h != sysH);
@ -644,12 +636,13 @@ public class LWWindowPeer
flushOnscreenGraphics(); flushOnscreenGraphics();
} }
// Third, COMPONENT_MOVED/COMPONENT_RESIZED events // Third, COMPONENT_MOVED/COMPONENT_RESIZED/PAINT events
if (moved) { if (moved) {
handleMove(x, y, true); handleMove(x, y, true);
} }
if (resized) { if (resized) {
handleResize(w, h,true); handleResize(w, h, true);
repaintPeer();
} }
} }

View File

@ -26,7 +26,6 @@
package sun.lwawt.macosx; package sun.lwawt.macosx;
import java.awt.*; import java.awt.*;
import java.awt.event.*;
import java.awt.image.VolatileImage; import java.awt.image.VolatileImage;
import sun.awt.CGraphicsConfig; import sun.awt.CGraphicsConfig;
@ -202,12 +201,11 @@ public class CPlatformView extends CFRetainedResource {
event.getCharactersIgnoringModifiers(), event.getKeyCode(), true); 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() { private void deliverWindowDidExposeEvent() {
Rectangle r = peer.getBounds(); peer.notifyExpose(peer.getSize());
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);
} }
} }

View File

@ -46,7 +46,7 @@ import com.apple.laf.*;
import com.apple.laf.ClientPropertyApplicator.Property; import com.apple.laf.ClientPropertyApplicator.Property;
import com.sun.awt.AWTUtilities; 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 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 nativeSetNSWindowStyleBits(long nsWindowPtr, int mask, int data);
private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr); private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr);
@ -199,7 +199,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
// In order to keep it up-to-date we will update them on // In order to keep it up-to-date we will update them on
// 1) setting native bounds via nativeSetBounds() call // 1) setting native bounds via nativeSetBounds() call
// 2) getting notification from the native level via deliverMoveResizeEvent() // 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 volatile boolean isFullScreenMode = false;
private Window target; private Window target;
@ -869,6 +869,12 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
} }
} }
private void flushBuffers() {
if (isVisible() && !nativeBounds.isEmpty()) {
LWCToolkit.getLWCToolkit().flushPendingEventsOnAppkit(target);
}
}
/************************************************************* /*************************************************************
* Callbacks from the AWTWindow and AWTView objc classes. * Callbacks from the AWTWindow and AWTView objc classes.
*************************************************************/ *************************************************************/
@ -886,10 +892,16 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
// move/resize notifications contain a bounds smaller than // move/resize notifications contain a bounds smaller than
// the whole screen and therefore we ignore the native notifications // the whole screen and therefore we ignore the native notifications
// and the content view itself creates correct synthetic 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); nativeBounds = new Rectangle(x, y, width, height);
peer.notifyReshape(x, y, width, height); peer.notifyReshape(x, y, width, height);
if (!oldB.getSize().equals(nativeBounds.getSize()) ) {
flushBuffers();
}
//TODO validateSurface already called from notifyReshape //TODO validateSurface already called from notifyReshape
validateSurface(); validateSurface();
} }

View File

@ -150,6 +150,10 @@ public final class LWCToolkit extends LWToolkit {
}); });
} }
public static LWCToolkit getLWCToolkit() {
return (LWCToolkit)Toolkit.getDefaultToolkit();
}
@Override @Override
protected PlatformWindow createPlatformWindow(PeerType peerType) { protected PlatformWindow createPlatformWindow(PeerType peerType) {
if (peerType == PeerType.EMBEDDEDFRAME) { if (peerType == PeerType.EMBEDDEDFRAME) {
@ -407,7 +411,6 @@ public final class LWCToolkit extends LWToolkit {
return BUTTONS; return BUTTONS;
} }
@Override @Override
public boolean isTraySupported() { public boolean isTraySupported() {
return true; return true;
@ -489,6 +492,22 @@ public final class LWCToolkit extends LWToolkit {
synchronized(ret) { return ret[0]; } 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 // Kicks an event over to the appropriate eventqueue and waits for it to finish
// To avoid deadlocking, we manually run the NSRunLoop while waiting // To avoid deadlocking, we manually run the NSRunLoop while waiting
// Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop // Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop

View File

@ -86,11 +86,14 @@ AWT_ASSERT_APPKIT_THREAD;
if (windowLayer != nil) { if (windowLayer != nil) {
self.cglLayer = windowLayer; self.cglLayer = windowLayer;
//Layer hosting view
[self setLayer: cglLayer];
[self setWantsLayer: YES]; [self setWantsLayer: YES];
[self.layer addSublayer: (CALayer *)cglLayer]; //Layer backed view
[self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize]; //[self.layer addSublayer: (CALayer *)cglLayer];
[self setLayerContentsPlacement: NSViewLayerContentsPlacementTopLeft]; //[self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize];
[self setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable]; //[self setLayerContentsPlacement: NSViewLayerContentsPlacementTopLeft];
//[self setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
#ifdef REMOTELAYER #ifdef REMOTELAYER
CGLLayer *parentLayer = (CGLLayer*)self.cglLayer; CGLLayer *parentLayer = (CGLLayer*)self.cglLayer;

View File

@ -57,9 +57,10 @@ AWT_ASSERT_APPKIT_THREAD;
// NOTE: async=YES means that the layer is re-cached periodically // NOTE: async=YES means that the layer is re-cached periodically
self.asynchronous = FALSE; self.asynchronous = FALSE;
self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
self.contentsGravity = kCAGravityTopLeft; 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 textureID = 0; // texture will be created by rendering pipe
target = 0; target = 0;
@ -109,6 +110,10 @@ AWT_ASSERT_APPKIT_THREAD;
glDisable(target); 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 -(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
{ {
AWT_ASSERT_APPKIT_THREAD; AWT_ASSERT_APPKIT_THREAD;