Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/swing/BufferStrategyPaintManager.java
38829 views
/*1* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package javax.swing;2526import java.awt.*;27import java.awt.event.*;28import java.awt.image.*;29import java.lang.reflect.*;30import java.lang.ref.WeakReference;31import java.util.*;3233import com.sun.java.swing.SwingUtilities3;3435import sun.awt.SubRegionShowable;36import sun.java2d.SunGraphics2D;37import sun.java2d.pipe.hw.ExtendedBufferCapabilities;38import sun.awt.SunToolkit;39import sun.util.logging.PlatformLogger;4041/**42* A PaintManager implementation that uses a BufferStrategy for43* rendering.44*45* @author Scott Violet46*/47class BufferStrategyPaintManager extends RepaintManager.PaintManager {48//49// All drawing is done to a BufferStrategy. At the end of painting50// (endPaint) the region that was painted is flushed to the screen51// (using BufferStrategy.show).52//53// PaintManager.show is overriden to show directly from the54// BufferStrategy (when using blit), if successful true is55// returned and a paint event will not be generated. To avoid56// showing from the buffer while painting a locking scheme is57// implemented. When beginPaint is invoked the field painting is58// set to true. If painting is true and show is invoked we59// immediately return false. This is done to avoid blocking the60// toolkit thread while painting happens. In a similar way when61// show is invoked the field showing is set to true, beginPaint62// will then block until showing is true. This scheme ensures we63// only ever have one thread using the BufferStrategy and it also64// ensures the toolkit thread remains as responsive as possible.65//66// If we're using a flip strategy the contents of the backbuffer may67// have changed and so show only attempts to show from the backbuffer68// if we get a blit strategy.69//7071//72// Methods used to create BufferStrategy for Applets.73//74private static Method COMPONENT_CREATE_BUFFER_STRATEGY_METHOD;75private static Method COMPONENT_GET_BUFFER_STRATEGY_METHOD;7677private static final PlatformLogger LOGGER = PlatformLogger.getLogger(78"javax.swing.BufferStrategyPaintManager");7980/**81* List of BufferInfos. We don't use a Map primarily because82* there are typically only a handful of top level components making83* a Map overkill.84*/85private ArrayList<BufferInfo> bufferInfos;8687/**88* Indicates <code>beginPaint</code> has been invoked. This is89* set to true for the life of beginPaint/endPaint pair.90*/91private boolean painting;92/**93* Indicates we're in the process of showing. All painting, on the EDT,94* is blocked while this is true.95*/96private boolean showing;9798//99// Region that we need to flush. When beginPaint is called these are100// reset and any subsequent calls to paint/copyArea then update these101// fields accordingly. When endPaint is called we then try and show102// the accumulated region.103// These fields are in the coordinate system of the root.104//105private int accumulatedX;106private int accumulatedY;107private int accumulatedMaxX;108private int accumulatedMaxY;109110//111// The following fields are set by prepare112//113114/**115* Farthest JComponent ancestor for the current paint/copyArea.116*/117private JComponent rootJ;118/**119* Location of component being painted relative to root.120*/121private int xOffset;122/**123* Location of component being painted relative to root.124*/125private int yOffset;126/**127* Graphics from the BufferStrategy.128*/129private Graphics bsg;130/**131* BufferStrategy currently being used.132*/133private BufferStrategy bufferStrategy;134/**135* BufferInfo corresponding to root.136*/137private BufferInfo bufferInfo;138139/**140* Set to true if the bufferInfo needs to be disposed when current141* paint loop is done.142*/143private boolean disposeBufferOnEnd;144145private static Method getGetBufferStrategyMethod() {146if (COMPONENT_GET_BUFFER_STRATEGY_METHOD == null) {147getMethods();148}149return COMPONENT_GET_BUFFER_STRATEGY_METHOD;150}151152private static Method getCreateBufferStrategyMethod() {153if (COMPONENT_CREATE_BUFFER_STRATEGY_METHOD == null) {154getMethods();155}156return COMPONENT_CREATE_BUFFER_STRATEGY_METHOD;157}158159private static void getMethods() {160java.security.AccessController.doPrivileged(161new java.security.PrivilegedAction<Object>() {162public Object run() {163try {164COMPONENT_CREATE_BUFFER_STRATEGY_METHOD = Component.class.165getDeclaredMethod("createBufferStrategy",166new Class[] { int.class,167BufferCapabilities.class });168COMPONENT_CREATE_BUFFER_STRATEGY_METHOD.169setAccessible(true);170COMPONENT_GET_BUFFER_STRATEGY_METHOD = Component.class.171getDeclaredMethod("getBufferStrategy");172COMPONENT_GET_BUFFER_STRATEGY_METHOD.setAccessible(true);173} catch (SecurityException e) {174assert false;175} catch (NoSuchMethodException nsme) {176assert false;177}178return null;179}180});181}182183BufferStrategyPaintManager() {184bufferInfos = new ArrayList<BufferInfo>(1);185}186187//188// PaintManager methods189//190191/**192* Cleans up any created BufferStrategies.193*/194protected void dispose() {195// dipose can be invoked at any random time. To avoid196// threading dependancies we do the actual diposing via an197// invokeLater.198SwingUtilities.invokeLater(new Runnable() {199public void run() {200java.util.List<BufferInfo> bufferInfos;201synchronized(BufferStrategyPaintManager.this) {202while (showing) {203try {204BufferStrategyPaintManager.this.wait();205} catch (InterruptedException ie) {206}207}208bufferInfos = BufferStrategyPaintManager.this.bufferInfos;209BufferStrategyPaintManager.this.bufferInfos = null;210}211dispose(bufferInfos);212}213});214}215216private void dispose(java.util.List<BufferInfo> bufferInfos) {217if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {218LOGGER.finer("BufferStrategyPaintManager disposed",219new RuntimeException());220}221if (bufferInfos != null) {222for (BufferInfo bufferInfo : bufferInfos) {223bufferInfo.dispose();224}225}226}227228/**229* Shows the specified region of the back buffer. This will return230* true if successful, false otherwise. This is invoked on the231* toolkit thread in response to an expose event.232*/233public boolean show(Container c, int x, int y, int w, int h) {234synchronized(this) {235if (painting) {236// Don't show from backbuffer while in the process of237// painting.238return false;239}240showing = true;241}242try {243BufferInfo info = getBufferInfo(c);244BufferStrategy bufferStrategy;245if (info != null && info.isInSync() &&246(bufferStrategy = info.getBufferStrategy(false)) != null) {247SubRegionShowable bsSubRegion =248(SubRegionShowable)bufferStrategy;249boolean paintAllOnExpose = info.getPaintAllOnExpose();250info.setPaintAllOnExpose(false);251if (bsSubRegion.showIfNotLost(x, y, (x + w), (y + h))) {252return !paintAllOnExpose;253}254// Mark the buffer as needing to be repainted. We don't255// immediately do a repaint as this method will return false256// indicating a PaintEvent should be generated which will257// trigger a complete repaint.258bufferInfo.setContentsLostDuringExpose(true);259}260}261finally {262synchronized(this) {263showing = false;264notifyAll();265}266}267return false;268}269270public boolean paint(JComponent paintingComponent,271JComponent bufferComponent, Graphics g,272int x, int y, int w, int h) {273Container root = fetchRoot(paintingComponent);274275if (prepare(paintingComponent, root, true, x, y, w, h)) {276if ((g instanceof SunGraphics2D) &&277((SunGraphics2D)g).getDestination() == root) {278// BufferStrategy may have already constrained the Graphics. To279// account for that we revert the constrain, then apply a280// constrain for Swing on top of that.281int cx = ((SunGraphics2D)bsg).constrainX;282int cy = ((SunGraphics2D)bsg).constrainY;283if (cx != 0 || cy != 0) {284bsg.translate(-cx, -cy);285}286((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy,287x + w, y + h);288bsg.setClip(x, y, w, h);289paintingComponent.paintToOffscreen(bsg, x, y, w, h,290x + w, y + h);291accumulate(xOffset + x, yOffset + y, w, h);292return true;293} else {294// Assume they are going to eventually render to the screen.295// This disables showing from backbuffer until a complete296// repaint occurs.297bufferInfo.setInSync(false);298// Fall through to old rendering.299}300}301// Invalid root, do what Swing has always done.302if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {303LOGGER.finer("prepare failed");304}305return super.paint(paintingComponent, bufferComponent, g, x, y, w, h);306}307308public void copyArea(JComponent c, Graphics g, int x, int y, int w, int h,309int deltaX, int deltaY, boolean clip) {310// Note: this method is only called internally and we know that311// g is from a heavyweight Component, so no check is necessary as312// it is in paint() above.313//314// If the buffer isn't in sync there is no point in doing a copyArea,315// it has garbage.316Container root = fetchRoot(c);317318if (prepare(c, root, false, 0, 0, 0, 0) && bufferInfo.isInSync()) {319if (clip) {320Rectangle cBounds = c.getVisibleRect();321int relX = xOffset + x;322int relY = yOffset + y;323bsg.clipRect(xOffset + cBounds.x,324yOffset + cBounds.y,325cBounds.width, cBounds.height);326bsg.copyArea(relX, relY, w, h, deltaX, deltaY);327}328else {329bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX,330deltaY);331}332accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h);333} else {334if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {335LOGGER.finer("copyArea: prepare failed or not in sync");336}337// Prepare failed, or not in sync. By calling super.copyArea338// we'll copy on screen. We need to flush any pending paint to339// the screen otherwise we'll do a copyArea on the wrong thing.340if (!flushAccumulatedRegion()) {341// Flush failed, copyArea will be copying garbage,342// force repaint of all.343rootJ.repaint();344} else {345super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip);346}347}348}349350public void beginPaint() {351synchronized(this) {352painting = true;353// Make sure another thread isn't attempting to show from354// the back buffer.355while(showing) {356try {357wait();358} catch (InterruptedException ie) {359}360}361}362if (LOGGER.isLoggable(PlatformLogger.Level.FINEST)) {363LOGGER.finest("beginPaint");364}365// Reset the area that needs to be painted.366resetAccumulated();367}368369public void endPaint() {370if (LOGGER.isLoggable(PlatformLogger.Level.FINEST)) {371LOGGER.finest("endPaint: region " + accumulatedX + " " +372accumulatedY + " " + accumulatedMaxX + " " +373accumulatedMaxY);374}375if (painting) {376if (!flushAccumulatedRegion()) {377if (!isRepaintingRoot()) {378repaintRoot(rootJ);379}380else {381// Contents lost twice in a row, punt.382resetDoubleBufferPerWindow();383// In case we've left junk on the screen, force a repaint.384rootJ.repaint();385}386}387}388389BufferInfo toDispose = null;390synchronized(this) {391painting = false;392if (disposeBufferOnEnd) {393disposeBufferOnEnd = false;394toDispose = bufferInfo;395bufferInfos.remove(toDispose);396}397}398if (toDispose != null) {399toDispose.dispose();400}401}402403/**404* Renders the BufferStrategy to the screen.405*406* @return true if successful, false otherwise.407*/408private boolean flushAccumulatedRegion() {409boolean success = true;410if (accumulatedX != Integer.MAX_VALUE) {411SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy;412boolean contentsLost = bufferStrategy.contentsLost();413if (!contentsLost) {414bsSubRegion.show(accumulatedX, accumulatedY,415accumulatedMaxX, accumulatedMaxY);416contentsLost = bufferStrategy.contentsLost();417}418if (contentsLost) {419if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {420LOGGER.finer("endPaint: contents lost");421}422// Shown region was bogus, mark buffer as out of sync.423bufferInfo.setInSync(false);424success = false;425}426}427resetAccumulated();428return success;429}430431private void resetAccumulated() {432accumulatedX = Integer.MAX_VALUE;433accumulatedY = Integer.MAX_VALUE;434accumulatedMaxX = 0;435accumulatedMaxY = 0;436}437438/**439* Invoked when the double buffering or useTrueDoubleBuffering440* changes for a JRootPane. If the rootpane is not double441* buffered, or true double buffering changes we throw out any442* cache we may have.443*/444public void doubleBufferingChanged(final JRootPane rootPane) {445if ((!rootPane.isDoubleBuffered() ||446!rootPane.getUseTrueDoubleBuffering()) &&447rootPane.getParent() != null) {448if (!SwingUtilities.isEventDispatchThread()) {449Runnable updater = new Runnable() {450public void run() {451doubleBufferingChanged0(rootPane);452}453};454SwingUtilities.invokeLater(updater);455}456else {457doubleBufferingChanged0(rootPane);458}459}460}461462/**463* Does the work for doubleBufferingChanged.464*/465private void doubleBufferingChanged0(JRootPane rootPane) {466// This will only happen on the EDT.467BufferInfo info;468synchronized(this) {469// Make sure another thread isn't attempting to show from470// the back buffer.471while(showing) {472try {473wait();474} catch (InterruptedException ie) {475}476}477info = getBufferInfo(rootPane.getParent());478if (painting && bufferInfo == info) {479// We're in the process of painting and the user grabbed480// the Graphics. If we dispose now, endPaint will attempt481// to show a bogus BufferStrategy. Set a flag so that482// endPaint knows it needs to dispose this buffer.483disposeBufferOnEnd = true;484info = null;485} else if (info != null) {486bufferInfos.remove(info);487}488}489if (info != null) {490info.dispose();491}492}493494/**495* Calculates information common to paint/copyArea.496*497* @return true if should use buffering per window in painting.498*/499private boolean prepare(JComponent c, Container root, boolean isPaint, int x, int y,500int w, int h) {501if (bsg != null) {502bsg.dispose();503bsg = null;504}505bufferStrategy = null;506if (root != null) {507boolean contentsLost = false;508BufferInfo bufferInfo = getBufferInfo(root);509if (bufferInfo == null) {510contentsLost = true;511bufferInfo = new BufferInfo(root);512bufferInfos.add(bufferInfo);513if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {514LOGGER.finer("prepare: new BufferInfo: " + root);515}516}517this.bufferInfo = bufferInfo;518if (!bufferInfo.hasBufferStrategyChanged()) {519bufferStrategy = bufferInfo.getBufferStrategy(true);520if (bufferStrategy != null) {521bsg = bufferStrategy.getDrawGraphics();522if (bufferStrategy.contentsRestored()) {523contentsLost = true;524if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {525LOGGER.finer("prepare: contents restored in prepare");526}527}528}529else {530// Couldn't create BufferStrategy, fallback to normal531// painting.532return false;533}534if (bufferInfo.getContentsLostDuringExpose()) {535contentsLost = true;536bufferInfo.setContentsLostDuringExpose(false);537if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {538LOGGER.finer("prepare: contents lost on expose");539}540}541if (isPaint && c == rootJ && x == 0 && y == 0 &&542c.getWidth() == w && c.getHeight() == h) {543bufferInfo.setInSync(true);544}545else if (contentsLost) {546// We either recreated the BufferStrategy, or the contents547// of the buffer strategy were restored. We need to548// repaint the root pane so that the back buffer is in sync549// again.550bufferInfo.setInSync(false);551if (!isRepaintingRoot()) {552repaintRoot(rootJ);553}554else {555// Contents lost twice in a row, punt556resetDoubleBufferPerWindow();557}558}559return (bufferInfos != null);560}561}562return false;563}564565private Container fetchRoot(JComponent c) {566boolean encounteredHW = false;567rootJ = c;568Container root = c;569xOffset = yOffset = 0;570while (root != null &&571(!(root instanceof Window) &&572!SunToolkit.isInstanceOf(root, "java.applet.Applet"))) {573xOffset += root.getX();574yOffset += root.getY();575root = root.getParent();576if (root != null) {577if (root instanceof JComponent) {578rootJ = (JComponent)root;579}580else if (!root.isLightweight()) {581if (!encounteredHW) {582encounteredHW = true;583}584else {585// We've encountered two hws now and may have586// a containment hierarchy with lightweights containing587// heavyweights containing other lightweights.588// Heavyweights poke holes in lightweight589// rendering so that if we call show on the BS590// (which is associated with the Window) you will591// not see the contents over any child592// heavyweights. If we didn't do this when we593// went to show the descendants of the nested hw594// you would see nothing, so, we bail out here.595return null;596}597}598}599}600if ((root instanceof RootPaneContainer) &&601(rootJ instanceof JRootPane)) {602// We're in a Swing heavyeight (JFrame/JWindow...), use double603// buffering if double buffering enabled on the JRootPane and604// the JRootPane wants true double buffering.605if (rootJ.isDoubleBuffered() &&606((JRootPane)rootJ).getUseTrueDoubleBuffering()) {607// Whether or not a component is double buffered is a608// bit tricky with Swing. This gives a good approximation609// of the various ways to turn on double buffering for610// components.611return root;612}613}614// Don't do true double buffering.615return null;616}617618/**619* Turns off double buffering per window.620*/621private void resetDoubleBufferPerWindow() {622if (bufferInfos != null) {623dispose(bufferInfos);624bufferInfos = null;625repaintManager.setPaintManager(null);626}627}628629/**630* Returns the BufferInfo for the specified root or null if one631* hasn't been created yet.632*/633private BufferInfo getBufferInfo(Container root) {634for (int counter = bufferInfos.size() - 1; counter >= 0; counter--) {635BufferInfo bufferInfo = bufferInfos.get(counter);636Container biRoot = bufferInfo.getRoot();637if (biRoot == null) {638// Window gc'ed639bufferInfos.remove(counter);640if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {641LOGGER.finer("BufferInfo pruned, root null");642}643}644else if (biRoot == root) {645return bufferInfo;646}647}648return null;649}650651private void accumulate(int x, int y, int w, int h) {652accumulatedX = Math.min(x, accumulatedX);653accumulatedY = Math.min(y, accumulatedY);654accumulatedMaxX = Math.max(accumulatedMaxX, x + w);655accumulatedMaxY = Math.max(accumulatedMaxY, y + h);656}657658659660/**661* BufferInfo is used to track the BufferStrategy being used for662* a particular Component. In addition to tracking the BufferStrategy663* it will install a WindowListener and ComponentListener. When the664* component is hidden/iconified the buffer is marked as needing to be665* completely repainted.666*/667private class BufferInfo extends ComponentAdapter implements668WindowListener {669// NOTE: This class does NOT hold a direct reference to the root, if it670// did there would be a cycle between the BufferPerWindowPaintManager671// and the Window so that it could never be GC'ed672//673// Reference to BufferStrategy is referenced via WeakReference for674// same reason.675private WeakReference<BufferStrategy> weakBS;676private WeakReference<Container> root;677// Indicates whether or not the backbuffer and display are in sync.678// This is set to true when a full repaint on the rootpane is done.679private boolean inSync;680// Indicates the contents were lost during and expose event.681private boolean contentsLostDuringExpose;682// Indicates we need to generate a paint event on expose.683private boolean paintAllOnExpose;684685686public BufferInfo(Container root) {687this.root = new WeakReference<Container>(root);688root.addComponentListener(this);689if (root instanceof Window) {690((Window)root).addWindowListener(this);691}692}693694public void setPaintAllOnExpose(boolean paintAllOnExpose) {695this.paintAllOnExpose = paintAllOnExpose;696}697698public boolean getPaintAllOnExpose() {699return paintAllOnExpose;700}701702public void setContentsLostDuringExpose(boolean value) {703contentsLostDuringExpose = value;704}705706public boolean getContentsLostDuringExpose() {707return contentsLostDuringExpose;708}709710public void setInSync(boolean inSync) {711this.inSync = inSync;712}713714/**715* Whether or not the contents of the buffer strategy716* is in sync with the window. This is set to true when the root717* pane paints all, and false when contents are lost/restored.718*/719public boolean isInSync() {720return inSync;721}722723/**724* Returns the Root (Window or Applet) that this BufferInfo references.725*/726public Container getRoot() {727return (root == null) ? null : root.get();728}729730/**731* Returns the BufferStartegy. This will return null if732* the BufferStartegy hasn't been created and <code>create</code> is733* false, or if there is a problem in creating the734* <code>BufferStartegy</code>.735*736* @param create If true, and the BufferStartegy is currently null,737* one will be created.738*/739public BufferStrategy getBufferStrategy(boolean create) {740BufferStrategy bs = (weakBS == null) ? null : weakBS.get();741if (bs == null && create) {742bs = createBufferStrategy();743if (bs != null) {744weakBS = new WeakReference<BufferStrategy>(bs);745}746if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {747LOGGER.finer("getBufferStrategy: created bs: " + bs);748}749}750return bs;751}752753/**754* Returns true if the buffer strategy of the component differs755* from current buffer strategy.756*/757public boolean hasBufferStrategyChanged() {758Container root = getRoot();759if (root != null) {760BufferStrategy ourBS = null;761BufferStrategy componentBS = null;762763ourBS = getBufferStrategy(false);764if (root instanceof Window) {765componentBS = ((Window)root).getBufferStrategy();766}767else {768try {769componentBS = (BufferStrategy)770getGetBufferStrategyMethod().invoke(root);771} catch (InvocationTargetException ite) {772assert false;773} catch (IllegalArgumentException iae) {774assert false;775} catch (IllegalAccessException iae2) {776assert false;777}778}779if (componentBS != ourBS) {780// Component has a different BS, dispose ours.781if (ourBS != null) {782ourBS.dispose();783}784weakBS = null;785return true;786}787}788return false;789}790791/**792* Creates the BufferStrategy. If the appropriate system property793* has been set we'll try for flip first and then we'll try for794* blit.795*/796private BufferStrategy createBufferStrategy() {797Container root = getRoot();798if (root == null) {799return null;800}801BufferStrategy bs = null;802if (SwingUtilities3.isVsyncRequested(root)) {803bs = createBufferStrategy(root, true);804if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {805LOGGER.finer("createBufferStrategy: using vsynced strategy");806}807}808if (bs == null) {809bs = createBufferStrategy(root, false);810}811if (!(bs instanceof SubRegionShowable)) {812// We do this for two reasons:813// 1. So that we know we can cast to SubRegionShowable and814// invoke show with the minimal region to update815// 2. To avoid the possibility of invoking client code816// on the toolkit thread.817bs = null;818}819return bs;820}821822// Creates and returns a buffer strategy. If823// there is a problem creating the buffer strategy this will824// eat the exception and return null.825private BufferStrategy createBufferStrategy(Container root,826boolean isVsynced) {827BufferCapabilities caps;828if (isVsynced) {829caps = new ExtendedBufferCapabilities(830new ImageCapabilities(true), new ImageCapabilities(true),831BufferCapabilities.FlipContents.COPIED,832ExtendedBufferCapabilities.VSyncType.VSYNC_ON);833} else {834caps = new BufferCapabilities(835new ImageCapabilities(true), new ImageCapabilities(true),836null);837}838BufferStrategy bs = null;839if (SunToolkit.isInstanceOf(root, "java.applet.Applet")) {840try {841getCreateBufferStrategyMethod().invoke(root, 2, caps);842bs = (BufferStrategy)getGetBufferStrategyMethod().843invoke(root);844} catch (InvocationTargetException ite) {845// Type is not supported846if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {847LOGGER.finer("createBufferStratety failed",848ite);849}850} catch (IllegalArgumentException iae) {851assert false;852} catch (IllegalAccessException iae2) {853assert false;854}855}856else {857try {858((Window)root).createBufferStrategy(2, caps);859bs = ((Window)root).getBufferStrategy();860} catch (AWTException e) {861// Type not supported862if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {863LOGGER.finer("createBufferStratety failed",864e);865}866}867}868return bs;869}870871/**872* Cleans up and removes any references.873*/874public void dispose() {875Container root = getRoot();876if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {877LOGGER.finer("disposed BufferInfo for: " + root);878}879if (root != null) {880root.removeComponentListener(this);881if (root instanceof Window) {882((Window)root).removeWindowListener(this);883}884BufferStrategy bs = getBufferStrategy(false);885if (bs != null) {886bs.dispose();887}888}889this.root = null;890weakBS = null;891}892893// We mark the buffer as needing to be painted on a hide/iconify894// because the developer may have conditionalized painting based on895// visibility.896// Ideally we would also move to having the BufferStrategy being897// a SoftReference in Component here, but that requires changes to898// Component and the like.899public void componentHidden(ComponentEvent e) {900Container root = getRoot();901if (root != null && root.isVisible()) {902// This case will only happen if a developer calls903// hide immediately followed by show. In this case904// the event is delivered after show and the window905// will still be visible. If a developer altered the906// contents of the window between the hide/show907// invocations we won't recognize we need to paint and908// the contents would be bogus. Calling repaint here909// fixs everything up.910root.repaint();911}912else {913setPaintAllOnExpose(true);914}915}916917public void windowIconified(WindowEvent e) {918setPaintAllOnExpose(true);919}920921// On a dispose we chuck everything.922public void windowClosed(WindowEvent e) {923// Make sure we're not showing.924synchronized(BufferStrategyPaintManager.this) {925while (showing) {926try {927BufferStrategyPaintManager.this.wait();928} catch (InterruptedException ie) {929}930}931bufferInfos.remove(this);932}933dispose();934}935936public void windowOpened(WindowEvent e) {937}938939public void windowClosing(WindowEvent e) {940}941942public void windowDeiconified(WindowEvent e) {943}944945public void windowActivated(WindowEvent e) {946}947948public void windowDeactivated(WindowEvent e) {949}950}951}952953954