# HG changeset patch # User art # Date 1242894565 -14400 # Node ID a139a919f645894a4a04b0ffbc7ef09983f54a8a # Parent db01a7f6d6576ea02572f393059c9492539b5cd1 6794764: Translucent windows are completely repainted on every paint event, on Windows 6719382: Printing of AWT components on windows is not working 6726866: Repainting artifacts when resizing or dragging JInternalFrames in non-opaque toplevel 6683775: Painting artifacts is seen when panel is made setOpaque(false) for a translucent window Reviewed-by: anthony, tdv, alexp diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/java/awt/GraphicsConfiguration.java --- a/jdk/src/share/classes/java/awt/GraphicsConfiguration.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/java/awt/GraphicsConfiguration.java Thu May 21 12:29:25 2009 +0400 @@ -436,7 +436,7 @@ } /** - * Returns whether this GraphicsConfiguration supports + * Returns whether this {@code GraphicsConfiguration} supports * the {@link GraphicsDevice.WindowTranslucency#PERPIXEL_TRANSLUCENT * PERPIXEL_TRANSLUCENT} kind of translucency. * diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/java/awt/GraphicsDevice.java --- a/jdk/src/share/classes/java/awt/GraphicsDevice.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/java/awt/GraphicsDevice.java Thu May 21 12:29:25 2009 +0400 @@ -246,7 +246,7 @@ * Simulated full-screen mode resizes * the window to the size of the screen and positions it at (0,0). *

- * When entering full-screen mode, if the window to be used as the + * When entering full-screen mode, if the window to be used as a * full-screen window is not visible, this method will make it visible. * It will remain visible when returning to windowed mode. *

@@ -261,9 +261,9 @@ * * @param w a window to use as the full-screen window; {@code null} * if returning to windowed mode. Some platforms expect the - * fullscreen window to be a top-level component (i.e., a Frame); - * therefore it is preferable to use a Frame here rather than a - * Window. + * fullscreen window to be a top-level component (i.e., a {@code Frame}); + * therefore it is preferable to use a {@code Frame} here rather than a + * {@code Window}. * * @see #isFullScreenSupported * @see #getFullScreenWindow diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/java/awt/Window.java --- a/jdk/src/share/classes/java/awt/Window.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/java/awt/Window.java Thu May 21 12:29:25 2009 +0400 @@ -296,7 +296,7 @@ transient boolean isInShow = false; /* - * Opacity level of the window + * The opacity level of the window * * @serial * @see #setOpacity(float) @@ -306,7 +306,7 @@ private float opacity = 1.0f; /* - * The shape assigned to this window. This field is set to null if + * The shape assigned to this window. This field is set to {@code null} if * no shape is set (rectangular window). * * @serial @@ -3592,10 +3592,10 @@ @Override public void setBackground(Color bgColor) { Color oldBg = getBackground(); + super.setBackground(bgColor); if (oldBg != null && oldBg.equals(bgColor)) { return; } - super.setBackground(bgColor); int oldAlpha = oldBg != null ? oldBg.getAlpha() : 255; int alpha = bgColor.getAlpha(); if ((oldAlpha == 255) && (alpha < 255)) { // non-opaque window @@ -3623,16 +3623,37 @@ } } - private void updateWindow(BufferedImage backBuffer) { + private void updateWindow() { synchronized (getTreeLock()) { WindowPeer peer = (WindowPeer)getPeer(); if (peer != null) { - peer.updateWindow(backBuffer); + peer.updateWindow(); } } } - private static final Color TRANSPARENT_BACKGROUND_COLOR = new Color(0, 0, 0, 0); + /** + * {@inheritDoc} + * + * @since 1.7 + */ + @Override + public void paint(Graphics g) { + Color bgColor = getBackground(); + if ((bgColor != null) && (bgColor.getAlpha() < 255)) { + Graphics gg = g.create(); + try { + if (gg instanceof Graphics2D) { + gg.setColor(bgColor); + ((Graphics2D)gg).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); + gg.fillRect(0, 0, getWidth(), getHeight()); + } + } finally { + gg.dispose(); + } + } + super.paint(g); + } private static void setLayersOpaque(Component component, boolean isOpaque) { // Shouldn't use instanceof to avoid loading Swing classes @@ -3644,18 +3665,10 @@ Container c = root.getContentPane(); javax.swing.JComponent content = (c instanceof javax.swing.JComponent) ? (javax.swing.JComponent)c : null; - javax.swing.JComponent gp = - (rpc.getGlassPane() instanceof javax.swing.JComponent) ? - (javax.swing.JComponent)rpc.getGlassPane() : null; - if (gp != null) { - gp.setDoubleBuffered(isOpaque); - } lp.setOpaque(isOpaque); root.setOpaque(isOpaque); - root.setDoubleBuffered(isOpaque); if (content != null) { content.setOpaque(isOpaque); - content.setDoubleBuffered(isOpaque); // Iterate down one level to see whether we have a JApplet // (which is also a RootPaneContainer) which requires processing @@ -3748,8 +3761,8 @@ window.setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue(), opaque ? 255 : 0)); } - public void updateWindow(Window window, BufferedImage backBuffer) { - window.updateWindow(backBuffer); + public void updateWindow(Window window) { + window.updateWindow(); } public Dimension getSecurityWarningSize(Window window) { diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/java/awt/peer/WindowPeer.java --- a/jdk/src/share/classes/java/awt/peer/WindowPeer.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/java/awt/peer/WindowPeer.java Thu May 21 12:29:25 2009 +0400 @@ -110,12 +110,11 @@ void setOpaque(boolean isOpaque); /** - * Updates the native part of non-opaque window using - * the given image with color+alpha values for each pixel. + * Updates the native part of non-opaque window. * * @see Window#setBackground(Color) */ - void updateWindow(BufferedImage backBuffer); + void updateWindow(); /** * Instructs the peer to update the position of the security warning. diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/javax/swing/DefaultDesktopManager.java --- a/jdk/src/share/classes/javax/swing/DefaultDesktopManager.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/javax/swing/DefaultDesktopManager.java Thu May 21 12:29:25 2009 +0400 @@ -34,6 +34,9 @@ import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import sun.awt.AWTAccessor; +import sun.awt.SunToolkit; + /** This is an implementation of the DesktopManager. * It currently implements the basic behaviors for managing * JInternalFrames in an arbitrary parent. @@ -361,7 +364,7 @@ g.dispose(); } } else if (dragMode == FASTER_DRAG_MODE) { - dragFrameFaster(f, newX, newY); + dragFrameFaster(f, newX, newY); } else { setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight()); } @@ -634,13 +637,8 @@ boolean floaterCollision = isFloaterCollision(previousBounds, currentBounds); - // System.out.println(previousBounds); JComponent parent = (JComponent)f.getParent(); Rectangle visBounds = previousBounds.intersection(desktopBounds); - // System.out.println(previousBounds); - - - // System.out.println(visBounds); RepaintManager currentManager = RepaintManager.currentManager(f); @@ -682,7 +680,6 @@ } else { dirtyRects = new Rectangle[1]; dirtyRects[0] = previousBounds; - // System.out.println("no intersection"); }; // Fix the damage @@ -701,14 +698,22 @@ parent.paintImmediately(dirtyRects[i]); ((JInternalFrame)f).isDragging = true; - - // System.out.println(dirtyRects[i]); } } } finally { currentManager.endPaint(); } + + // update window if it's non-opaque + Window topLevel = SwingUtilities.getWindowAncestor(f); + Toolkit tk = Toolkit.getDefaultToolkit(); + if (!AWTAccessor.getWindowAccessor().isOpaque(topLevel) && + (tk instanceof SunToolkit) && + ((SunToolkit)tk).needUpdateWindow()) + { + AWTAccessor.getWindowAccessor().updateWindow(topLevel); + } } private boolean isFloaterCollision(Rectangle moveFrom, Rectangle moveTo) { diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/javax/swing/JComponent.java --- a/jdk/src/share/classes/javax/swing/JComponent.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/javax/swing/JComponent.java Thu May 21 12:29:25 2009 +0400 @@ -1021,8 +1021,10 @@ int bw,bh; boolean printing = getFlag(IS_PRINTING); - if(!printing && repaintManager.isDoubleBufferingEnabled() && - !getFlag(ANCESTOR_USING_BUFFER) && isDoubleBuffered()) { + if (!printing && repaintManager.isDoubleBufferingEnabled() && + !getFlag(ANCESTOR_USING_BUFFER) && isDoubleBuffered() && + (getFlag(IS_REPAINTING) || repaintManager.isPainting())) + { repaintManager.beginPaint(); try { repaintManager.paint(this, this, co, clipX, clipY, clipW, diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/javax/swing/RepaintManager.java --- a/jdk/src/share/classes/javax/swing/RepaintManager.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/javax/swing/RepaintManager.java Thu May 21 12:29:25 2009 +0400 @@ -43,7 +43,6 @@ import com.sun.java.swing.SwingUtilities3; - /** * This class manages repaint requests, allowing the number * of repaints to be minimized, for example by collapsing multiple @@ -717,14 +716,12 @@ } } - private Map - updateWindows(Map dirtyComponents) - { + private void updateWindows(Map dirtyComponents) { Toolkit toolkit = Toolkit.getDefaultToolkit(); if (!(toolkit instanceof SunToolkit && ((SunToolkit)toolkit).needUpdateWindow())) { - return dirtyComponents; + return; } Set windows = new HashSet(); @@ -734,25 +731,20 @@ Window window = dirty instanceof Window ? (Window)dirty : SwingUtilities.getWindowAncestor(dirty); - if (window != null && !AWTAccessor.getWindowAccessor().isOpaque(window)) { - // if this component's toplevel is perpixel translucent, it will - // be repainted below - it.remove(); - // add to the set of windows to update (so that we don't update - // the window many times for each component to be repainted that - // belongs to this window) windows.add(window); } } for (Window window : windows) { - AWTAccessor.getWindowAccessor().updateWindow(window, null); + AWTAccessor.getWindowAccessor().updateWindow(window); } + } - return dirtyComponents; + boolean isPainting() { + return painting; } /** @@ -788,10 +780,6 @@ int localBoundsW; Enumeration keys; - // the components belonging to perpixel-translucent windows will be - // removed from the list - tmpDirtyComponents = updateWindows(tmpDirtyComponents); - roots = new ArrayList(count); for (Component dirty : tmpDirtyComponents.keySet()) { @@ -799,13 +787,11 @@ } count = roots.size(); - // System.out.println("roots size is " + count); painting = true; try { for(i=0 ; i < count ; i++) { dirtyComponent = roots.get(i); rect = tmpDirtyComponents.get(dirtyComponent); - // System.out.println("Should refresh :" + rect); localBoundsH = dirtyComponent.getHeight(); localBoundsW = dirtyComponent.getWidth(); @@ -848,6 +834,9 @@ } finally { painting = false; } + + updateWindows(tmpDirtyComponents); + tmpDirtyComponents.clear(); } @@ -1004,6 +993,16 @@ return delegate.getVolatileOffscreenBuffer(c, proposedWidth, proposedHeight); } + + // If the window is non-opaque, it's double-buffered at peer's level + Window w = (c instanceof Window) ? (Window)c : SwingUtilities.getWindowAncestor(c); + if (!AWTAccessor.getWindowAccessor().isOpaque(w)) { + Toolkit tk = Toolkit.getDefaultToolkit(); + if ((tk instanceof SunToolkit) && (((SunToolkit)tk).needUpdateWindow())) { + return null; + } + } + GraphicsConfiguration config = c.getGraphicsConfiguration(); if (config == null) { config = GraphicsEnvironment.getLocalGraphicsEnvironment(). @@ -1031,6 +1030,15 @@ DoubleBufferInfo doubleBuffer; int width, height; + // If the window is non-opaque, it's double-buffered at peer's level + Window w = (c instanceof Window) ? (Window)c : SwingUtilities.getWindowAncestor(c); + if (!AWTAccessor.getWindowAccessor().isOpaque(w)) { + Toolkit tk = Toolkit.getDefaultToolkit(); + if ((tk instanceof SunToolkit) && (((SunToolkit)tk).needUpdateWindow())) { + return null; + } + } + if (standardDoubleBuffer == null) { standardDoubleBuffer = new DoubleBufferInfo(); } diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/sun/awt/AWTAccessor.java --- a/jdk/src/share/classes/sun/awt/AWTAccessor.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java Thu May 21 12:29:25 2009 +0400 @@ -132,7 +132,7 @@ /* * Update the image of a non-opaque (translucent) window. */ - void updateWindow(Window window, BufferedImage backBuffer); + void updateWindow(Window window); /** Get the size of the security warning. */ diff -r db01a7f6d657 -r a139a919f645 jdk/src/share/classes/sun/awt/EmbeddedFrame.java --- a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java Thu May 21 12:29:25 2009 +0400 @@ -592,8 +592,9 @@ public void setOpaque(boolean isOpaque) { } - public void updateWindow(BufferedImage bi) { + public void updateWindow() { } + public void repositionSecurityWarning() { } } diff -r db01a7f6d657 -r a139a919f645 jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java --- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java Thu May 21 12:29:25 2009 +0400 @@ -2058,7 +2058,7 @@ } @Override - public void updateWindow(BufferedImage backBuffer) { + public void updateWindow() { // no-op } } diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/classes/sun/awt/windows/TranslucentWindowPainter.java --- a/jdk/src/windows/classes/sun/awt/windows/TranslucentWindowPainter.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/classes/sun/awt/windows/TranslucentWindowPainter.java Thu May 21 12:29:25 2009 +0400 @@ -105,9 +105,10 @@ } /** - * Creates (if needed), clears and returns the buffer for this painter. + * Creates (if needed), clears (if requested) and returns the buffer + * for this painter. */ - protected abstract Image getBackBuffer(); + protected abstract Image getBackBuffer(boolean clear); /** * Updates the the window associated with this painter with the contents @@ -123,31 +124,16 @@ public abstract void flush(); /** - * Updates the window associated with the painter given the passed image. - * If the passed image is null the painter will use its own buffer for - * rendering the contents of the window into it and updating the window. + * Updates the window associated with the painter. * - * If the passed buffer has dimensions different from the window, it is - * copied into the internal buffer first and the latter is used to update - * the window. - * - * @param bb the image to update the non opaque window with, or null. - * If not null, the image must be of ARGB_PRE type. + * @param repaint indicates if the window should be completely repainted + * to the back buffer using {@link java.awt.Window#paintAll} before update. */ - public void updateWindow(Image bb) { + public void updateWindow(boolean repaint) { boolean done = false; - if (bb != null && (window.getWidth() != bb.getWidth(null) || - window.getHeight() != bb.getHeight(null))) - { - Image ourBB = getBackBuffer(); - Graphics2D g = (Graphics2D)ourBB.getGraphics(); - g.drawImage(bb, 0, 0, null); - g.dispose(); - bb = ourBB; - } - do { - if (bb == null) { - bb = getBackBuffer(); + Image bb = getBackBuffer(repaint); + while (!done) { + if (repaint) { Graphics2D g = (Graphics2D)bb.getGraphics(); try { window.paintAll(g); @@ -156,17 +142,12 @@ } } - peer.paintAppletWarning((Graphics2D)bb.getGraphics(), - bb.getWidth(null), bb.getHeight(null)); - done = update(bb); - // in case they passed us a lost VI, next time around we'll use our - // own bb because we can not validate and restore the contents of - // their VI if (!done) { - bb = null; + repaint = true; + bb = getBackBuffer(true); } - } while (!done); + } } private static final Image clearImage(Image bb) { @@ -190,30 +171,24 @@ * method (VI, BI, regular Images). */ private static class BIWindowPainter extends TranslucentWindowPainter { - private WeakReference biRef; + private BufferedImage backBuffer; protected BIWindowPainter(WWindowPeer peer) { super(peer); } - private BufferedImage getBIBackBuffer() { + @Override + protected Image getBackBuffer(boolean clear) { int w = window.getWidth(); int h = window.getHeight(); - BufferedImage bb = biRef == null ? null : biRef.get(); - if (bb == null || bb.getWidth() != w || bb.getHeight() != h) { - if (bb != null) { - bb.flush(); - bb = null; - } - bb = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); - biRef = new WeakReference(bb); + if (backBuffer == null || + backBuffer.getWidth() != w || + backBuffer.getHeight() != h) + { + flush(); + backBuffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); } - return (BufferedImage)clearImage(bb); - } - - @Override - protected Image getBackBuffer() { - return getBIBackBuffer(); + return clear ? (BufferedImage)clearImage(backBuffer) : backBuffer; } @Override @@ -246,10 +221,7 @@ } // copy the passed image into our own buffer, then upload - BufferedImage bi = getBIBackBuffer(); - Graphics2D g = (Graphics2D)bi.getGraphics(); - g.setComposite(AlphaComposite.Src); - g.drawImage(bb, 0, 0, null); + BufferedImage bi = (BufferedImage)clearImage(backBuffer); int data[] = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData(); @@ -259,8 +231,9 @@ } public void flush() { - if (biRef != null) { - biRef.clear(); + if (backBuffer != null) { + backBuffer.flush(); + backBuffer = null; } } } @@ -271,27 +244,22 @@ * Java heap-based buffer (which is then uploaded to the layered window) */ private static class VIWindowPainter extends BIWindowPainter { - private WeakReference viRef; + private VolatileImage viBB; protected VIWindowPainter(WWindowPeer peer) { super(peer); } @Override - protected Image getBackBuffer() { + protected Image getBackBuffer(boolean clear) { int w = window.getWidth(); int h = window.getHeight(); GraphicsConfiguration gc = peer.getGraphicsConfiguration(); - VolatileImage viBB = viRef == null ? null : viRef.get(); - if (viBB == null || viBB.getWidth() != w || viBB.getHeight() != h || viBB.validate(gc) == IMAGE_INCOMPATIBLE) { - if (viBB != null) { - viBB.flush(); - viBB = null; - } + flush(); if (gc instanceof AccelGraphicsConfig) { AccelGraphicsConfig agc = ((AccelGraphicsConfig)gc); @@ -303,21 +271,16 @@ viBB = gc.createCompatibleVolatileImage(w, h, TRANSLUCENT); } viBB.validate(gc); - viRef = new WeakReference(viBB); } - return clearImage(viBB); + return clear ? clearImage(viBB) : viBB; } @Override public void flush() { - if (viRef != null) { - VolatileImage viBB = viRef.get(); - if (viBB != null) { - viBB.flush(); - viBB = null; - } - viRef.clear(); + if (viBB != null) { + viBB.flush(); + viBB = null; } } } diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/classes/sun/awt/windows/WCanvasPeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WCanvasPeer.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/classes/sun/awt/windows/WCanvasPeer.java Thu May 21 12:29:25 2009 +0400 @@ -78,25 +78,6 @@ super.paint(g); } - public void print(Graphics g) { - if (!(target instanceof Window) || - AWTAccessor.getWindowAccessor().isOpaque((Window)target)) - { - Dimension d = ((Component)target).getSize(); - if (g instanceof Graphics2D || - g instanceof sun.awt.Graphics2Delegate) { - // background color is setup correctly, so just use clearRect - g.clearRect(0, 0, d.width, d.height); - } else { - // emulate clearRect - g.setColor(((Component)target).getBackground()); - g.fillRect(0, 0, d.width, d.height); - g.setColor(((Component)target).getForeground()); - } - } - super.print(g); - } - public boolean shouldClearRectBeforePaint() { return eraseBackground; } diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java Thu May 21 12:29:25 2009 +0400 @@ -239,7 +239,8 @@ private static final double BANDING_DIVISOR = 4.0; private native int[] createPrintedPixels(int srcX, int srcY, - int srcW, int srcH); + int srcW, int srcH, + int alpha); public void print(Graphics g) { Component comp = (Component)target; @@ -261,7 +262,9 @@ } int h = endY - startY + 1; - int[] pix = createPrintedPixels(0, startY, totalW, h); + Color bgColor = comp.getBackground(); + int[] pix = createPrintedPixels(0, startY, totalW, h, + bgColor == null ? 255 : bgColor.getAlpha()); if (pix != null) { BufferedImage bim = new BufferedImage(totalW, h, BufferedImage.TYPE_INT_ARGB); diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/classes/sun/awt/windows/WObjectPeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WObjectPeer.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/classes/sun/awt/windows/WObjectPeer.java Thu May 21 12:29:25 2009 +0400 @@ -42,6 +42,9 @@ // set from JNI if any errors in creating the peer occur protected Error createError = null; + // used to synchronize the state of this peer + private final Object stateLock = new Object(); + public static WObjectPeer getPeerForTarget(Object t) { WObjectPeer peer = (WObjectPeer) WToolkit.targetToPeer(t); return peer; @@ -55,6 +58,10 @@ return target; } + public final Object getStateLock() { + return stateLock; + } + /* * Subclasses should override disposeImpl() instead of dispose(). Client * code should always invoke dispose(), never disposeImpl(). diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java --- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Thu May 21 12:29:25 2009 +0400 @@ -54,7 +54,7 @@ private boolean isOpaque; - private volatile TranslucentWindowPainter painter; + private TranslucentWindowPainter painter; /* * A key used for storing a list of active windows in AppContext. The value @@ -106,11 +106,13 @@ GraphicsConfiguration gc = getGraphicsConfiguration(); ((Win32GraphicsDevice)gc.getDevice()).removeDisplayChangedListener(this); - TranslucentWindowPainter currentPainter = painter; - if (currentPainter != null) { - currentPainter.flush(); - // don't set the current one to null here; reduces the chances of - // MT issues (like NPEs) + synchronized (getStateLock()) { + TranslucentWindowPainter currentPainter = painter; + if (currentPainter != null) { + currentPainter.flush(); + // don't set the current one to null here; reduces the chances of + // MT issues (like NPEs) + } } super.disposeImpl(); @@ -178,9 +180,23 @@ updateIconImages(); - updateShape(); - updateOpacity(); - updateOpaque(); + Shape shape = ((Window)target).getShape(); + if (shape != null) { + applyShape(Region.getInstance(shape, null)); + } + + float opacity = ((Window)target).getOpacity(); + if (opacity < 1.0f) { + setOpacity(opacity); + } + + synchronized (getStateLock()) { + // default value of a boolean field is 'false', so set isOpaque to + // true here explicitly + this.isOpaque = true; + Color bgColor = ((Window)target).getBackground(); + setOpaque((bgColor == null) || (bgColor.getAlpha() == 255)); + } } native void createAwtWindow(WComponentPeer parent); @@ -214,7 +230,11 @@ setAlwaysOnTop(alwaysOnTop); } - updateWindow(null); + synchronized (getStateLock()) { + if (!isOpaque) { + updateWindow(true); + } + } } // Synchronize the insets members (here & in helper) with actual window @@ -334,29 +354,6 @@ } } - private void updateShape() { - Shape shape = ((Window)target).getShape(); - if (shape != null) { - applyShape(Region.getInstance(shape, null)); - } - } - - private void updateOpacity() { - float opacity = ((Window)target).getOpacity(); - if (opacity < 1.0f) { - setOpacity(opacity); - } - } - - private void updateOpaque() { - this.isOpaque = true; - // boolean opaque = ((Window)target).isOpaque(); - boolean opaque = AWTAccessor.getWindowAccessor().isOpaque((Window)target); - if (!opaque) { - setOpaque(opaque); - } - } - native void setMinSize(int width, int height); /* @@ -579,6 +576,26 @@ } } + @Override + public Graphics getGraphics() { + synchronized (getStateLock()) { + if (!isOpaque) { + return painter.getBackBuffer(false).getGraphics(); + } + } + return super.getGraphics(); + } + + @Override + public void setBackground(Color c) { + super.setBackground(c); + synchronized (getStateLock()) { + if (!isOpaque && ((Window)target).isVisible()) { + updateWindow(true); + } + } + } + private native void setOpacity(int iOpacity); public void setOpacity(float opacity) { @@ -600,12 +617,23 @@ } setOpacity(iOpacity); - updateWindow(null); + + synchronized (getStateLock()) { + if (!isOpaque && ((Window)target).isVisible()) { + updateWindow(true); + } + } } private native void setOpaqueImpl(boolean isOpaque); public void setOpaque(boolean isOpaque) { + synchronized (getStateLock()) { + if (this.isOpaque == isOpaque) { + return; + } + } + Window target = (Window)getTarget(); if (!isOpaque) { @@ -617,20 +645,17 @@ } } - boolean opaqueChanged = this.isOpaque != isOpaque; boolean isVistaOS = Win32GraphicsEnvironment.isVistaOS(); - if (opaqueChanged && !isVistaOS){ + if (!isVistaOS) { // non-Vista OS: only replace the surface data if the opacity // status changed (see WComponentPeer.isAccelCapable() for more) replaceSurfaceDataRecursively(target); } - this.isOpaque = isOpaque; - - setOpaqueImpl(isOpaque); - - if (opaqueChanged) { + synchronized (getStateLock()) { + this.isOpaque = isOpaque; + setOpaqueImpl(isOpaque); if (isOpaque) { TranslucentWindowPainter currentPainter = painter; if (currentPainter != null) { @@ -642,7 +667,7 @@ } } - if (opaqueChanged && isVistaOS) { + if (isVistaOS) { // On Vista: setting the window non-opaque makes the window look // rectangular, though still catching the mouse clicks within // its shape only. To restore the correct visual appearance @@ -654,42 +679,33 @@ } } - updateWindow(null); + if (((Window)target).isVisible()) { + updateWindow(true); + } } public native void updateWindowImpl(int[] data, int width, int height); - public void updateWindow(BufferedImage backBuffer) { - if (isOpaque) { - return; - } - - Component target = (Component)this.target; - if (target.getWidth() <= 0 || target.getHeight() <= 0) { - return; - } - - TranslucentWindowPainter currentPainter = painter; - if (currentPainter != null) { - currentPainter.updateWindow(backBuffer); - } else if (log.isLoggable(Level.FINER)) { - log.log(Level.FINER, - "Translucent window painter is null in updateWindow"); - } + public void updateWindow() { + updateWindow(false); } - /** - * Paints the Applet Warning into the passed Graphics2D. This method is - * called by the TranslucentWindowPainter before updating the layered - * window. - * - * @param g Graphics context to paint the warning to - * @param w the width of the area - * @param h the height of the area - * @see TranslucentWindowPainter - */ - public void paintAppletWarning(Graphics2D g, int w, int h) { - // REMIND: the applet warning needs to be painted here + private void updateWindow(boolean repaint) { + Window w = (Window)target; + synchronized (getStateLock()) { + if (isOpaque || !w.isVisible() || + (w.getWidth() <= 0) || (w.getHeight() <= 0)) + { + return; + } + TranslucentWindowPainter currentPainter = painter; + if (currentPainter != null) { + currentPainter.updateWindow(repaint); + } else if (log.isLoggable(Level.FINER)) { + log.log(Level.FINER, + "Translucent window painter is null in updateWindow"); + } + } } /* diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/native/sun/windows/awt_Component.cpp --- a/jdk/src/windows/native/sun/windows/awt_Component.cpp Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/native/sun/windows/awt_Component.cpp Thu May 21 12:29:25 2009 +0400 @@ -30,6 +30,7 @@ #include "jlong.h" #include "awt_AWTEvent.h" +#include "awt_BitmapUtil.h" #include "awt_Component.h" #include "awt_Cursor.h" #include "awt_Dimension.h" @@ -127,6 +128,7 @@ jobject component; int srcx, srcy; int srcw, srch; + jint alpha; }; // Struct for _SetRectangularShape() method struct SetRectangularShapeStruct { @@ -361,8 +363,8 @@ AwtComponent* AwtComponent::GetComponentImpl(HWND hWnd) { AwtComponent *component = (AwtComponent *)::GetWindowLongPtr(hWnd, GWLP_USERDATA); - DASSERT( !IsBadReadPtr(component, sizeof(AwtComponent)) ); - DASSERT( component->GetHWnd() == hWnd ); + DASSERT(!component || !IsBadReadPtr(component, sizeof(AwtComponent)) ); + DASSERT(!component || component->GetHWnd() == hWnd ); return component; } @@ -1918,11 +1920,14 @@ mr = mrConsume; break; } - case WM_AWT_CREATE_PRINTED_PIXELS: - retValue = (LRESULT)CreatePrintedPixels(*((SIZE *)wParam), - *((SIZE *)lParam)); + case WM_AWT_CREATE_PRINTED_PIXELS: { + CreatePrintedPixelsStruct* cpps = (CreatePrintedPixelsStruct*)wParam; + SIZE loc = { cpps->srcx, cpps->srcy }; + SIZE size = { cpps->srcw, cpps->srch }; + retValue = (LRESULT)CreatePrintedPixels(loc, size, cpps->alpha); mr = mrConsume; break; + } case WM_UNDOCUMENTED_CLICKMENUBAR: { if (::IsWindow(AwtWindow::GetModalBlocker(GetHWnd()))) { @@ -4526,18 +4531,20 @@ void AwtComponent::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha) { - if (bitmapBits) { - DWORD* dest = (DWORD*)bitmapBits; - //XXX: might be optimized to use one loop (cy*cx -> 0). - for (int i = 0; i < size.cy; i++ ) { - for (int j = 0; j < size.cx; j++ ) { - ((BYTE*)(dest++))[3] = alpha; - } + if (!bitmapBits) { + return; + } + + DWORD* dest = (DWORD*)bitmapBits; + //XXX: might be optimized to use one loop (cy*cx -> 0) + for (int i = 0; i < size.cy; i++ ) { + for (int j = 0; j < size.cx; j++ ) { + ((BYTE*)(dest++))[3] = alpha; } } } -jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size) { +jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); if (!::IsWindowVisible(GetHWnd())) { @@ -4549,12 +4556,12 @@ return NULL; } HDC hMemoryDC = ::CreateCompatibleDC(hdc); - HBITMAP hBitmap = ::CreateCompatibleBitmap(hdc, size.cx, size.cy); + void *bitmapBits = NULL; + HBITMAP hBitmap = BitmapUtil::CreateARGBBitmap(size.cx, size.cy, &bitmapBits); HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemoryDC, hBitmap); SendMessage(WM_AWT_RELEASEDC, (WPARAM)hdc); - RECT eraseR = { 0, 0, size.cx, size.cy }; - VERIFY(::FillRect(hMemoryDC, &eraseR, GetBackgroundBrush())); + FillBackground(hMemoryDC, size); VERIFY(::SetWindowOrgEx(hMemoryDC, loc.cx, loc.cy, NULL)); @@ -4562,6 +4569,14 @@ // above. SendMessage(WM_PRINT, (WPARAM)hMemoryDC, PRF_CLIENT | PRF_NONCLIENT); + // First make sure the system completed any drawing to the bitmap. + ::GdiFlush(); + + // WM_PRINT does not fill the alpha-channel of the ARGB bitmap + // leaving it equal to zero. Hence we need to fill it manually. Otherwise + // the pixels will be considered transparent when interpreting the data. + FillAlpha(bitmapBits, size, alpha); + ::SelectObject(hMemoryDC, hOldBitmap); BITMAPINFO bmi; @@ -5937,10 +5952,6 @@ CreatePrintedPixelsStruct *cpps = (CreatePrintedPixelsStruct *)param; jobject self = cpps->component; - jint srcx = cpps->srcx; - jint srcy = cpps->srcy; - jint srcw = cpps->srcw; - jint srch = cpps->srch; jintArray result = NULL; AwtComponent *c = NULL; @@ -5950,12 +5961,7 @@ c = (AwtComponent *)pData; if (::IsWindow(c->GetHWnd())) { - SIZE loc = { srcx, srcy }; - SIZE size = { srcw, srch }; - - result = (jintArray) - c->SendMessage(WM_AWT_CREATE_PRINTED_PIXELS, (WPARAM)&loc, - (LPARAM)&size); + result = (jintArray)c->SendMessage(WM_AWT_CREATE_PRINTED_PIXELS, (WPARAM)cpps, 0); } ret: env->DeleteGlobalRef(self); @@ -6749,7 +6755,7 @@ */ JNIEXPORT jintArray JNICALL Java_sun_awt_windows_WComponentPeer_createPrintedPixels(JNIEnv* env, - jobject self, jint srcX, jint srcY, jint srcW, jint srcH) + jobject self, jint srcX, jint srcY, jint srcW, jint srcH, jint alpha) { TRY; @@ -6761,6 +6767,7 @@ cpps->srcy = srcY; cpps->srcw = srcW; cpps->srch = srcH; + cpps->alpha = alpha; jintArray globalRef = (jintArray)AwtToolkit::GetInstance().SyncCall( (void*(*)(void*))AwtComponent::_CreatePrintedPixels, cpps); diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/native/sun/windows/awt_Component.h --- a/jdk/src/windows/native/sun/windows/awt_Component.h Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/native/sun/windows/awt_Component.h Thu May 21 12:29:25 2009 +0400 @@ -596,7 +596,7 @@ void UpdateColorModel(); - jintArray CreatePrintedPixels(SIZE &loc, SIZE &size); + jintArray CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha); /* * HWND, AwtComponent and Java Peer interaction @@ -738,7 +738,6 @@ virtual void SetDragCapture(UINT flags); virtual void ReleaseDragCapture(UINT flags); - //These functions are overridden in AwtWindow to handle non-opaque windows. virtual void FillBackground(HDC hMemoryDC, SIZE &size); virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha); diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/native/sun/windows/awt_Window.cpp --- a/jdk/src/windows/native/sun/windows/awt_Window.cpp Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/native/sun/windows/awt_Window.cpp Thu May 21 12:29:25 2009 +0400 @@ -464,7 +464,7 @@ size_t length = env->GetStringLength(javaWarningString) + 1; warningString = new WCHAR[length]; env->GetStringRegion(javaWarningString, 0, - static_cast(length - 1), warningString); + static_cast(length - 1), reinterpret_cast(warningString)); warningString[length-1] = L'\0'; env->DeleteLocalRef(javaWarningString); @@ -2651,20 +2651,6 @@ ::LeaveCriticalSection(&contentBitmapCS); } -void AwtWindow::FillBackground(HDC hMemoryDC, SIZE &size) -{ - if (isOpaque()) { - AwtCanvas::FillBackground(hMemoryDC, size); - } -} - -void AwtWindow::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha) -{ - if (isOpaque()) { - AwtCanvas::FillAlpha(bitmapBits, size, alpha); - } -} - /* * Fixed 6353381: it's improved fix for 4792958 * which was backed-out to avoid 5059656 diff -r db01a7f6d657 -r a139a919f645 jdk/src/windows/native/sun/windows/awt_Window.h --- a/jdk/src/windows/native/sun/windows/awt_Window.h Tue May 19 17:03:13 2009 +0400 +++ b/jdk/src/windows/native/sun/windows/awt_Window.h Thu May 21 12:29:25 2009 +0400 @@ -343,11 +343,6 @@ BOOL m_iconInherited; /* TRUE if icon is inherited from the owner */ BOOL m_filterFocusAndActivation; /* Used in the WH_CBT hook */ - //These are used in AwtComponent::CreatePrintedPixels. They are overridden - //here to handle non-opaque windows. - virtual void FillBackground(HDC hMemoryDC, SIZE &size); - virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha); - inline BOOL IsUntrusted() { return warningString != NULL; } diff -r db01a7f6d657 -r a139a919f645 jdk/test/javax/swing/JComponent/6683775/bug6683775.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JComponent/6683775/bug6683775.java Thu May 21 12:29:25 2009 +0400 @@ -0,0 +1,82 @@ +/* @test + @bug 6683775 6794764 + @summary Painting artifacts is seen when panel is made setOpaque(false) for a translucent window + @author Alexander Potochkin + @run main bug6683775 +*/ + +import com.sun.awt.AWTUtilities; +import sun.awt.SunToolkit; + +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; + +public class bug6683775 { + public static void main(String[] args) throws Exception { + GraphicsConfiguration gc = getGC(); + if (!AWTUtilities.isTranslucencySupported( + AWTUtilities.Translucency.PERPIXEL_TRANSLUCENT) + || gc == null) { + return; + } + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + Robot robot = new Robot(); + final JFrame testFrame = new JFrame(gc); + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + JFrame backgroundFrame = new JFrame("Background frame"); + backgroundFrame.setUndecorated(true); + JPanel panel = new JPanel(); + panel.setBackground(Color.RED); + backgroundFrame.add(panel); + backgroundFrame.setSize(200, 200); + backgroundFrame.setVisible(true); + + testFrame.setUndecorated(true); + JPanel p = new JPanel(); + p.setOpaque(false); + testFrame.add(p); + AWTUtilities.setWindowOpaque(testFrame, false); + testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + testFrame.setSize(400, 400); + testFrame.setLocation(0, 0); + testFrame.setVisible(true); + } + }); + + toolkit.realSync(); + + //robot.getPixelColor() didn't work right for some reason + BufferedImage capture = robot.createScreenCapture(new Rectangle(100, 100)); + + int redRGB = Color.RED.getRGB(); + if (redRGB != capture.getRGB(10, 10)) { + throw new RuntimeException("Transparent frame is not transparent!"); + } + } + + private static GraphicsConfiguration getGC() { + GraphicsConfiguration transparencyCapableGC = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + if (!AWTUtilities.isTranslucencyCapable(transparencyCapableGC)) { + transparencyCapableGC = null; + + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] devices = env.getScreenDevices(); + + for (int i = 0; i < devices.length && transparencyCapableGC == null; i++) { + GraphicsConfiguration[] configs = devices[i].getConfigurations(); + for (int j = 0; j < configs.length && transparencyCapableGC == null; j++) { + if (AWTUtilities.isTranslucencyCapable(configs[j])) { + transparencyCapableGC = configs[j]; + } + } + } + } + return transparencyCapableGC; + } +} diff -r db01a7f6d657 -r a139a919f645 jdk/test/javax/swing/JInternalFrame/6726866/bug6726866.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JInternalFrame/6726866/bug6726866.html Thu May 21 12:29:25 2009 +0400 @@ -0,0 +1,7 @@ + + + +Drag the internal frame inside the green undecorated window, +if you can drag it the test passes, otherwise fails. + + diff -r db01a7f6d657 -r a139a919f645 jdk/test/javax/swing/JInternalFrame/6726866/bug6726866.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JInternalFrame/6726866/bug6726866.java Thu May 21 12:29:25 2009 +0400 @@ -0,0 +1,44 @@ +/* @test + @bug 6726866 + @summary Repainting artifacts when resizing or dragging JInternalFrames in non-opaque toplevel + @author Alexander Potochkin + @run applet/manual=yesno bug6726866.html +*/ + +import javax.swing.*; +import java.awt.*; +import java.lang.reflect.Method; + +public class bug6726866 extends JApplet { + + public void init() { + JFrame frame = new JFrame("bug6726866"); + frame.setUndecorated(true); + setWindowNonOpaque(frame); + + JDesktopPane desktop = new JDesktopPane(); + desktop.setBackground(Color.GREEN); + JInternalFrame iFrame = new JInternalFrame("Test", true, true, true, true); + iFrame.add(new JLabel("internal Frame")); + iFrame.setBounds(10, 10, 300, 200); + iFrame.setVisible(true); + desktop.add(iFrame); + frame.add(desktop); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(400, 400); + frame.setVisible(true); + frame.toFront(); + } + + private void setWindowNonOpaque(Window w) { + try { + Class c = Class.forName("com.sun.awt.AWTUtilities"); + Method m = c.getMethod("setWindowOpaque", Window.class, boolean.class); + m.invoke(null, w, false); + } + catch (Exception e) { + e.printStackTrace(); + } + } +}