/* * Copyright (c) 2005, 2011, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */package javax.swing; import java.applet.Applet;import java.awt.*;import java.awt.event.*;import java.awt.image.*;import java.lang.reflect.*;import java.lang.ref.WeakReference;import java.security.AccessController;import java.util.*; import com.sun.java.swing.SwingUtilities3; import sun.awt.SubRegionShowable;import sun.java2d.SunGraphics2D;import sun.security.action.GetPropertyAction;import sun.java2d.pipe.hw.ExtendedBufferCapabilities;import sun.awt.SunToolkit;import sun.util.logging.PlatformLogger; /** * A PaintManager implementation that uses a BufferStrategy for * rendering. * * @author Scott Violet */class BufferStrategyPaintManager extends RepaintManager.PaintManager { // // All drawing is done to a BufferStrategy. At the end of painting // (endPaint) the region that was painted is flushed to the screen // (using BufferStrategy.show). // // PaintManager.show is overriden to show directly from the // BufferStrategy (when using blit), if successful true is // returned and a paint event will not be generated. To avoid // showing from the buffer while painting a locking scheme is // implemented. When beginPaint is invoked the field painting is // set to true. If painting is true and show is invoked we // immediately return false. This is done to avoid blocking the // toolkit thread while painting happens. In a similar way when // show is invoked the field showing is set to true, beginPaint // will then block until showing is true. This scheme ensures we // only ever have one thread using the BufferStrategy and it also // ensures the toolkit thread remains as responsive as possible. // // If we're using a flip strategy the contents of the backbuffer may // have changed and so show only attempts to show from the backbuffer // if we get a blit strategy. // // // Methods used to create BufferStrategy for Applets. // private static Method COMPONENT_CREATE_BUFFER_STRATEGY_METHOD; private static Method COMPONENT_GET_BUFFER_STRATEGY_METHOD; private static final PlatformLogger LOGGER = PlatformLogger.getLogger( "javax.swing.BufferStrategyPaintManager"); /** * List of BufferInfos. We don't use a Map primarily because * there are typically only a handful of top level components making * a Map overkill. */ private ArrayList<BufferInfo> bufferInfos; /** * Indicates <code>beginPaint</code> has been invoked. This is * set to true for the life of beginPaint/endPaint pair. */ private boolean painting; /** * Indicates we're in the process of showing. All painting, on the EDT, * is blocked while this is true. */ private boolean showing; // // Region that we need to flush. When beginPaint is called these are // reset and any subsequent calls to paint/copyArea then update these // fields accordingly. When endPaint is called we then try and show // the accumulated region. // These fields are in the coordinate system of the root. // private int accumulatedX; private int accumulatedY; private int accumulatedMaxX; private int accumulatedMaxY; // // The following fields are set by prepare // /** * Farthest JComponent ancestor for the current paint/copyArea. */ private JComponent rootJ; /** * Parent Applet/Window for the current paint/copyArea */ private Container root; /** * Location of component being painted relative to root. */ private int xOffset; /** * Location of component being painted relative to root. */ private int yOffset; /** * Graphics from the BufferStrategy. */ private Graphics bsg; /** * BufferStrategy currently being used. */ private BufferStrategy bufferStrategy; /** * BufferInfo corresponding to root. */ private BufferInfo bufferInfo; /** * Set to true if the bufferInfo needs to be disposed when current * paint loop is done. */ private boolean disposeBufferOnEnd; private static Method getGetBufferStrategyMethod() { if (COMPONENT_GET_BUFFER_STRATEGY_METHOD == null) { getMethods(); } return COMPONENT_GET_BUFFER_STRATEGY_METHOD; } private static Method getCreateBufferStrategyMethod() { if (COMPONENT_CREATE_BUFFER_STRATEGY_METHOD == null) { getMethods(); } return COMPONENT_CREATE_BUFFER_STRATEGY_METHOD; } private static void getMethods() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Object>() { public Object run() { try { COMPONENT_CREATE_BUFFER_STRATEGY_METHOD = Component.class. getDeclaredMethod("createBufferStrategy", new Class[] { int.class, BufferCapabilities.class }); COMPONENT_CREATE_BUFFER_STRATEGY_METHOD. setAccessible(true); COMPONENT_GET_BUFFER_STRATEGY_METHOD = Component.class. getDeclaredMethod("getBufferStrategy"); COMPONENT_GET_BUFFER_STRATEGY_METHOD.setAccessible(true); } catch (SecurityException e) { assert false; } catch (NoSuchMethodException nsme) { assert false; } return null; } }); } BufferStrategyPaintManager() { bufferInfos = new ArrayList<BufferInfo>(1); } // // PaintManager methods // /** * Cleans up any created BufferStrategies. */ protected void dispose() { // dipose can be invoked at any random time. To avoid // threading dependancies we do the actual diposing via an // invokeLater. SwingUtilities.invokeLater(new Runnable() { public void run() { java.util.List<BufferInfo> bufferInfos; synchronized(BufferStrategyPaintManager.this) { while (showing) { try { BufferStrategyPaintManager.this.wait(); } catch (InterruptedException ie) { } } bufferInfos = BufferStrategyPaintManager.this.bufferInfos; BufferStrategyPaintManager.this.bufferInfos = null; } dispose(bufferInfos); } }); } private void dispose(java.util.List<BufferInfo> bufferInfos) { if (LOGGER.isLoggable(PlatformLogger.FINER)) { LOGGER.finer("BufferStrategyPaintManager disposed", new RuntimeException()); } if (bufferInfos != null) { for (BufferInfo bufferInfo : bufferInfos) { bufferInfo.dispose(); } } } /** * Shows the specified region of the back buffer. This will return * true if successful, false otherwise. This is invoked on the * toolkit thread in response to an expose event. */ public boolean show(Container c, int x, int y, int w, int h) { synchronized(this) { if (painting) { // Don't show from backbuffer while in the process of // painting. return false; } showing = true; } try { BufferInfo info = getBufferInfo(c); BufferStrategy bufferStrategy; if (info != null && info.isInSync() && (bufferStrategy = info.getBufferStrategy(false)) != null) { SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy; boolean paintAllOnExpose = info.getPaintAllOnExpose(); info.setPaintAllOnExpose(false); if (bsSubRegion.showIfNotLost(x, y, (x + w), (y + h))) { return !paintAllOnExpose; } // Mark the buffer as needing to be repainted. We don't // immediately do a repaint as this method will return false // indicating a PaintEvent should be generated which will // trigger a complete repaint. bufferInfo.setContentsLostDuringExpose(true); } } finally { synchronized(this) { showing = false; notifyAll(); } } return false; } public boolean paint(JComponent paintingComponent, JComponent bufferComponent, Graphics g, int x, int y, int w, int h) { if (prepare(paintingComponent, true, x, y, w, h)) { if ((g instanceof SunGraphics2D) && ((SunGraphics2D)g).getDestination() == root) { // BufferStrategy may have already constrained the Graphics. To // account for that we revert the constrain, then apply a // constrain for Swing on top of that. int cx = ((SunGraphics2D)bsg).constrainX; int cy = ((SunGraphics2D)bsg).constrainY; if (cx != 0 || cy != 0) { bsg.translate(-cx, -cy); } ((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy, x + w, y + h); bsg.setClip(x, y, w, h); paintingComponent.paintToOffscreen(bsg, x, y, w, h, x + w, y + h); accumulate(xOffset + x, yOffset + y, w, h); return true; } else { // Assume they are going to eventually render to the screen. // This disables showing from backbuffer until a complete // repaint occurs. bufferInfo.setInSync(false); // Fall through to old rendering. } } // Invalid root, do what Swing has always done. if (LOGGER.isLoggable(PlatformLogger.FINER)) { LOGGER.finer("prepare failed"); } return super.paint(paintingComponent, bufferComponent, g, x, y, w, h); } public void copyArea(JComponent c, Graphics g, int x, int y, int w, int h, int deltaX, int deltaY, boolean clip) { // Note: this method is only called internally and we know that // g is from a heavyweight Component, so no check is necessary as // it is in paint() above. // // If the buffer isn't in sync there is no point in doing a copyArea, // it has garbage. if (prepare(c, false, 0, 0, 0, 0) && bufferInfo.isInSync()) { if (clip) { Rectangle cBounds = c.getVisibleRect(); int relX = xOffset + x; int relY = yOffset + y; bsg.clipRect(xOffset + cBounds.x, yOffset + cBounds.y, cBounds.width, cBounds.height); bsg.copyArea(relX, relY, w, h, deltaX, deltaY); } else { bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX, deltaY); } accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h); } else { if (LOGGER.isLoggable(PlatformLogger.FINER)) { LOGGER.finer("copyArea: prepare failed or not in sync"); } // Prepare failed, or not in sync. By calling super.copyArea // we'll copy on screen. We need to flush any pending paint to // the screen otherwise we'll do a copyArea on the wrong thing. if (!flushAccumulatedRegion()) { // Flush failed, copyArea will be copying garbage, // force repaint of all. rootJ.repaint(); } else { super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip); } } } public void beginPaint() { synchronized(this) { painting = true; // Make sure another thread isn't attempting to show from // the back buffer. while(showing) { try { wait(); } catch (InterruptedException ie) { } } } if (LOGGER.isLoggable(PlatformLogger.FINEST)) { LOGGER.finest("beginPaint"); } // Reset the area that needs to be painted. resetAccumulated(); } public void endPaint() { if (LOGGER.isLoggable(PlatformLogger.FINEST)) { LOGGER.finest("endPaint: region " + accumulatedX + " " + accumulatedY + " " + accumulatedMaxX + " " + accumulatedMaxY); } if (painting) { if (!flushAccumulatedRegion()) { if (!isRepaintingRoot()) { repaintRoot(rootJ); } else { // Contents lost twice in a row, punt. resetDoubleBufferPerWindow(); // In case we've left junk on the screen, force a repaint. rootJ.repaint(); } } } BufferInfo toDispose = null; synchronized(this) { painting = false; if (disposeBufferOnEnd) { disposeBufferOnEnd = false; toDispose = bufferInfo; bufferInfos.remove(toDispose); } } if (toDispose != null) { toDispose.dispose(); } } /** * Renders the BufferStrategy to the screen. * * @return true if successful, false otherwise. */ private boolean flushAccumulatedRegion() { boolean success = true; if (accumulatedX != Integer.MAX_VALUE) { SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy; boolean contentsLost = bufferStrategy.contentsLost(); if (!contentsLost) { bsSubRegion.show(accumulatedX, accumulatedY, accumulatedMaxX, accumulatedMaxY); contentsLost = bufferStrategy.contentsLost(); } if (contentsLost) { if (LOGGER.isLoggable(PlatformLogger.FINER)) { LOGGER.finer("endPaint: contents lost"); } // Shown region was bogus, mark buffer as out of sync. bufferInfo.setInSync(false); success = false; } } resetAccumulated(); return success; } private void resetAccumulated() { accumulatedX = Integer.MAX_VALUE; accumulatedY = Integer.MAX_VALUE; accumulatedMaxX = 0; accumulatedMaxY = 0; } /** * Invoked when the double buffering or useTrueDoubleBuffering * changes for a JRootPane. If the rootpane is not double * buffered, or true double buffering changes we throw out any * cache we may have. */ public void doubleBufferingChanged(final JRootPane rootPane) { if ((!rootPane.isDoubleBuffered() || !rootPane.getUseTrueDoubleBuffering()) && rootPane.getParent() != null) { if (!SwingUtilities.isEventDispatchThread()) { Runnable updater = new Runnable() { public void run() { doubleBufferingChanged0(rootPane); } }; SwingUtilities.invokeLater(updater); } else { doubleBufferingChanged0(rootPane); } } } /** * Does the work for doubleBufferingChanged. */ private void doubleBufferingChanged0(JRootPane rootPane) { // This will only happen on the EDT. BufferInfo info; synchronized(this) { // Make sure another thread isn't attempting to show from // the back buffer. while(showing) { try { wait(); } catch (InterruptedException ie) { } } info = getBufferInfo(rootPane.getParent()); if (painting && bufferInfo == info) { // We're in the process of painting and the user grabbed // the Graphics. If we dispose now, endPaint will attempt // to show a bogus BufferStrategy. Set a flag so that // endPaint knows it needs to dispose this buffer. disposeBufferOnEnd = true; info = null; } else if (info != null) { bufferInfos.remove(info); } } if (info != null) { info.dispose(); } } /** * Calculates information common to paint/copyArea. *Lines 1–500 of 956. Load more
/* * Copyright (c) 2005, 2011, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ package javax.swing; import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.lang.reflect.*; import java.lang.ref.WeakReference; import java.security.AccessController; import java.util.*; import com.sun.java.swing.SwingUtilities3; import sun.awt.SubRegionShowable; import sun.java2d.SunGraphics2D; import sun.security.action.GetPropertyAction; import sun.java2d.pipe.hw.ExtendedBufferCapabilities; import sun.awt.SunToolkit; import sun.util.logging.PlatformLogger; /** * A PaintManager implementation that uses a BufferStrategy for * rendering. * * @author Scott Violet */ class BufferStrategyPaintManager extends RepaintManager.PaintManager { // // All drawing is done to a BufferStrategy. At the end of painting // (endPaint) the region that was painted is flushed to the screen // (using BufferStrategy.show). // // PaintManager.show is overriden to show directly from the // BufferStrategy (when using blit), if successful true is // returned and a paint event will not be generated. To avoid // showing from the buffer while painting a locking scheme is // implemented. When beginPaint is invoked the field painting is // set to true. If painting is true and show is invoked we // immediately return false. This is done to avoid blocking the // toolkit thread while painting happens. In a similar way when // show is invoked the field showing is set to true, beginPaint // will then block until showing is true. This scheme ensures we // only ever have one thread using the BufferStrategy and it also // ensures the toolkit thread remains as responsive as possible. // // If we're using a flip strategy the contents of the backbuffer may // have changed and so show only attempts to show from the backbuffer // if we get a blit strategy. // // // Methods used to create BufferStrategy for Applets. // private static Method COMPONENT_CREATE_BUFFER_STRATEGY_METHOD; private static Method COMPONENT_GET_BUFFER_STRATEGY_METHOD; private static final PlatformLogger LOGGER = PlatformLogger.getLogger( "javax.swing.BufferStrategyPaintManager"); /** * List of BufferInfos. We don't use a Map primarily because * there are typically only a handful of top level components making * a Map overkill. */ private ArrayList<BufferInfo> bufferInfos; /** * Indicates <code>beginPaint</code> has been invoked. This is * set to true for the life of beginPaint/endPaint pair. */ private boolean painting; /** * Indicates we're in the process of showing. All painting, on the EDT, * is blocked while this is true. */ private boolean showing; // // Region that we need to flush. When beginPaint is called these are // reset and any subsequent calls to paint/copyArea then update these // fields accordingly. When endPaint is called we then try and show // the accumulated region. // These fields are in the coordinate system of the root. // private int accumulatedX; private int accumulatedY; private int accumulatedMaxX; private int accumulatedMaxY; // // The following fields are set by prepare // /** * Farthest JComponent ancestor for the current paint/copyArea. */ private JComponent rootJ; /** * Parent Applet/Window for the current paint/copyArea */ private Container root; /** * Location of component being painted relative to root. */ private int xOffset; /** * Location of component being painted relative to root. */ private int yOffset; /** * Graphics from the BufferStrategy. */ private Graphics bsg; /** * BufferStrategy currently being used. */ private BufferStrategy bufferStrategy; /** * BufferInfo corresponding to root. */ private BufferInfo bufferInfo; /** * Set to true if the bufferInfo needs to be disposed when current * paint loop is done. */ private boolean disposeBufferOnEnd; private static Method getGetBufferStrategyMethod() { if (COMPONENT_GET_BUFFER_STRATEGY_METHOD == null) { getMethods(); } return COMPONENT_GET_BUFFER_STRATEGY_METHOD; } private static Method getCreateBufferStrategyMethod() { if (COMPONENT_CREATE_BUFFER_STRATEGY_METHOD == null) { getMethods(); } return COMPONENT_CREATE_BUFFER_STRATEGY_METHOD; } private static void getMethods() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Object>() { public Object run() { try { COMPONENT_CREATE_BUFFER_STRATEGY_METHOD = Component.class. getDeclaredMethod("createBufferStrategy", new Class[] { int.class, BufferCapabilities.class }); COMPONENT_CREATE_BUFFER_STRATEGY_METHOD. setAccessible(true); COMPONENT_GET_BUFFER_STRATEGY_METHOD = Component.class. getDeclaredMethod("getBufferStrategy"); COMPONENT_GET_BUFFER_STRATEGY_METHOD.setAccessible(true); } catch (SecurityException e) { assert false; } catch (NoSuchMethodException nsme) { assert false; } return null; } }); } BufferStrategyPaintManager() { bufferInfos = new ArrayList<BufferInfo>(1); } // // PaintManager methods // /** * Cleans up any created BufferStrategies. */ protected void dispose() { // dipose can be invoked at any random time. To avoid // threading dependancies we do the actual diposing via an // invokeLater. SwingUtilities.invokeLater(new Runnable() { public void run() { java.util.List<BufferInfo> bufferInfos; synchronized(BufferStrategyPaintManager.this) { while (showing) { try { BufferStrategyPaintManager.this.wait(); } catch (InterruptedException ie) { } } bufferInfos = BufferStrategyPaintManager.this.bufferInfos; BufferStrategyPaintManager.this.bufferInfos = null; } dispose(bufferInfos); } }); } private void dispose(java.util.List<BufferInfo> bufferInfos) { if (LOGGER.isLoggable(PlatformLogger.FINER)) { LOGGER.finer("BufferStrategyPaintManager disposed", new RuntimeException()); } if (bufferInfos != null) { for (BufferInfo bufferInfo : bufferInfos) { bufferInfo.dispose(); } } } /** * Shows the specified region of the back buffer. This will return * true if successful, false otherwise. This is invoked on the * toolkit thread in response to an expose event. */ public boolean show(Container c, int x, int y, int w, int h) { synchronized(this) { if (painting) { // Don't show from backbuffer while in the process of // painting. return false; } showing = true; } try { BufferInfo info = getBufferInfo(c); BufferStrategy bufferStrategy; if (info != null && info.isInSync() && (bufferStrategy = info.getBufferStrategy(false)) != null) { SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy; boolean paintAllOnExpose = info.getPaintAllOnExpose(); info.setPaintAllOnExpose(false); if (bsSubRegion.showIfNotLost(x, y, (x + w), (y + h))) { return !paintAllOnExpose; } // Mark the buffer as needing to be repainted. We don't // immediately do a repaint as this method will return false // indicating a PaintEvent should be generated which will // trigger a complete repaint. bufferInfo.setContentsLostDuringExpose(true); } } finally { synchronized(this) { showing = false; notifyAll(); } } return false; } public boolean paint(JComponent paintingComponent, JComponent bufferComponent, Graphics g, int x, int y, int w, int h) { if (prepare(paintingComponent, true, x, y, w, h)) { if ((g instanceof SunGraphics2D) && ((SunGraphics2D)g).getDestination() == root) { // BufferStrategy may have already constrained the Graphics. To // account for that we revert the constrain, then apply a // constrain for Swing on top of that. int cx = ((SunGraphics2D)bsg).constrainX; int cy = ((SunGraphics2D)bsg).constrainY; if (cx != 0 || cy != 0) { bsg.translate(-cx, -cy); } ((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy, x + w, y + h); bsg.setClip(x, y, w, h); paintingComponent.paintToOffscreen(bsg, x, y, w, h, x + w, y + h); accumulate(xOffset + x, yOffset + y, w, h); return true; } else { // Assume they are going to eventually render to the screen. // This disables showing from backbuffer until a complete // repaint occurs. bufferInfo.setInSync(false); // Fall through to old rendering. } } // Invalid root, do what Swing has always done. if (LOGGER.isLoggable(PlatformLogger.FINER)) { LOGGER.finer("prepare failed"); } return super.paint(paintingComponent, bufferComponent, g, x, y, w, h); } public void copyArea(JComponent c, Graphics g, int x, int y, int w, int h, int deltaX, int deltaY, boolean clip) { // Note: this method is only called internally and we know that // g is from a heavyweight Component, so no check is necessary as // it is in paint() above. // // If the buffer isn't in sync there is no point in doing a copyArea, // it has garbage. if (prepare(c, false, 0, 0, 0, 0) && bufferInfo.isInSync()) { if (clip) { Rectangle cBounds = c.getVisibleRect(); int relX = xOffset + x; int relY = yOffset + y; bsg.clipRect(xOffset + cBounds.x, yOffset + cBounds.y, cBounds.width, cBounds.height); bsg.copyArea(relX, relY, w, h, deltaX, deltaY); } else { bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX, deltaY); } accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h); } else { if (LOGGER.isLoggable(PlatformLogger.FINER)) { LOGGER.finer("copyArea: prepare failed or not in sync"); } // Prepare failed, or not in sync. By calling super.copyArea // we'll copy on screen. We need to flush any pending paint to // the screen otherwise we'll do a copyArea on the wrong thing. if (!flushAccumulatedRegion()) { // Flush failed, copyArea will be copying garbage, // force repaint of all. rootJ.repaint(); } else { super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip); } } } public void beginPaint() { synchronized(this) { painting = true; // Make sure another thread isn't attempting to show from // the back buffer. while(showing) { try { wait(); } catch (InterruptedException ie) { } } } if (LOGGER.isLoggable(PlatformLogger.FINEST)) { LOGGER.finest("beginPaint"); } // Reset the area that needs to be painted. resetAccumulated(); } public void endPaint() { if (LOGGER.isLoggable(PlatformLogger.FINEST)) { LOGGER.finest("endPaint: region " + accumulatedX + " " + accumulatedY + " " + accumulatedMaxX + " " + accumulatedMaxY); } if (painting) { if (!flushAccumulatedRegion()) { if (!isRepaintingRoot()) { repaintRoot(rootJ); } else { // Contents lost twice in a row, punt. resetDoubleBufferPerWindow(); // In case we've left junk on the screen, force a repaint. rootJ.repaint(); } } } BufferInfo toDispose = null; synchronized(this) { painting = false; if (disposeBufferOnEnd) { disposeBufferOnEnd = false; toDispose = bufferInfo; bufferInfos.remove(toDispose); } } if (toDispose != null) { toDispose.dispose(); } } /** * Renders the BufferStrategy to the screen. * * @return true if successful, false otherwise. */ private boolean flushAccumulatedRegion() { boolean success = true; if (accumulatedX != Integer.MAX_VALUE) { SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy; boolean contentsLost = bufferStrategy.contentsLost(); if (!contentsLost) { bsSubRegion.show(accumulatedX, accumulatedY, accumulatedMaxX, accumulatedMaxY); contentsLost = bufferStrategy.contentsLost(); } if (contentsLost) { if (LOGGER.isLoggable(PlatformLogger.FINER)) { LOGGER.finer("endPaint: contents lost"); } // Shown region was bogus, mark buffer as out of sync. bufferInfo.setInSync(false); success = false; } } resetAccumulated(); return success; } private void resetAccumulated() { accumulatedX = Integer.MAX_VALUE; accumulatedY = Integer.MAX_VALUE; accumulatedMaxX = 0; accumulatedMaxY = 0; } /** * Invoked when the double buffering or useTrueDoubleBuffering * changes for a JRootPane. If the rootpane is not double * buffered, or true double buffering changes we throw out any * cache we may have. */ public void doubleBufferingChanged(final JRootPane rootPane) { if ((!rootPane.isDoubleBuffered() || !rootPane.getUseTrueDoubleBuffering()) && rootPane.getParent() != null) { if (!SwingUtilities.isEventDispatchThread()) { Runnable updater = new Runnable() { public void run() { doubleBufferingChanged0(rootPane); } }; SwingUtilities.invokeLater(updater); } else { doubleBufferingChanged0(rootPane); } } } /** * Does the work for doubleBufferingChanged. */ private void doubleBufferingChanged0(JRootPane rootPane) { // This will only happen on the EDT. BufferInfo info; synchronized(this) { // Make sure another thread isn't attempting to show from // the back buffer. while(showing) { try { wait(); } catch (InterruptedException ie) { } } info = getBufferInfo(rootPane.getParent()); if (painting && bufferInfo == info) { // We're in the process of painting and the user grabbed // the Graphics. If we dispose now, endPaint will attempt // to show a bogus BufferStrategy. Set a flag so that // endPaint knows it needs to dispose this buffer. disposeBufferOnEnd = true; info = null; } else if (info != null) { bufferInfos.remove(info); } } if (info != null) { info.dispose(); } } /** * Calculates information common to paint/copyArea. *