KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > BufferStrategyPaintManager


1 /*
2  * @(#)BufferStrategyPaintManager.java 1.13 07/08/27
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing;
8
9 import java.applet.Applet JavaDoc;
10 import java.awt.*;
11 import java.awt.event.*;
12 import java.awt.image.*;
13 import java.lang.reflect.*;
14 import java.lang.ref.WeakReference JavaDoc;
15 import java.security.AccessController JavaDoc;
16 import java.util.*;
17 import java.util.logging.*;
18 import sun.awt.SubRegionShowable;
19 import sun.java2d.SunGraphics2D;
20 import sun.security.action.GetPropertyAction;
21
22 /**
23  * A PaintManager implementation that uses a BufferStrategy for
24  * rendering.
25  *
26  * @version 1.13, 08/27/07
27  * @author Scott Violet
28  */

29 class BufferStrategyPaintManager extends RepaintManager.PaintManager JavaDoc {
30     //
31
// All drawing is done to a BufferStrategy. At the end of painting
32
// (endPaint) the region that was painted is flushed to the screen
33
// (using BufferStrategy.show).
34
//
35
// PaintManager.show is overriden to show directly from the
36
// BufferStrategy (when using blit), if successful true is
37
// returned and a paint event will not be generated. To avoid
38
// showing from the buffer while painting a locking scheme is
39
// implemented. When beginPaint is invoked the field painting is
40
// set to true. If painting is true and show is invoked we
41
// immediately return false. This is done to avoid blocking the
42
// toolkit thread while painting happens. In a similar way when
43
// show is invoked the field showing is set to true, beginPaint
44
// will then block until showing is true. This scheme ensures we
45
// only ever have one thread using the BufferStrategy and it also
46
// ensures the toolkit thread remains as responsive as possible.
47
//
48
// If we're using a flip strategy the contents of the backbuffer may
49
// have changed and so show only attempts to show from the backbuffer
50
// if we get a blit strategy.
51
//
52

53     //
54
// Methods used to create BufferStrategy for Applets.
55
//
56
private static Method COMPONENT_CREATE_BUFFER_STRATEGY_METHOD;
57     private static Method COMPONENT_GET_BUFFER_STRATEGY_METHOD;
58
59     /**
60      * Indicates whether or not we should try and get a flip buffer strategy
61      * first, default is false.
62      */

63     private static boolean TRY_FLIP;
64
65     private static final Logger LOGGER = Logger.getLogger(
66                            "javax.swing.BufferStrategyPaintManager");
67
68     /**
69      * List of BufferInfos. We don't use a Map primarily because
70      * there are typically only a handful of top level components making
71      * a Map overkill.
72      */

73     private ArrayList<BufferInfo> bufferInfos;
74
75     /**
76      * Indicates <code>beginPaint</code> has been invoked. This is
77      * set to true for the life of beginPaint/endPaint pair.
78      */

79     private boolean painting;
80     /**
81      * Indicates we're in the process of showing. All painting, on the EDT,
82      * is blocked while this is true.
83      */

84     private boolean showing;
85
86     //
87
// Region that we need to flush. When beginPaint is called these are
88
// reset and any subsequent calls to paint/copyArea then update these
89
// fields accordingly. When endPaint is called we then try and show
90
// the accumulated region.
91
// These fields are in the coordinate system of the root.
92
//
93
private int accumulatedX;
94     private int accumulatedY;
95     private int accumulatedMaxX;
96     private int accumulatedMaxY;
97
98     //
99
// The following fields are set by prepare
100
//
101

102     /**
103      * Farthest JComponent ancestor for the current paint/copyArea.
104      */

105     private JComponent JavaDoc rootJ;
106     /**
107      * Parent Applet/Window for the current paint/copyArea
108      */

109     private Container root;
110     /**
111      * Location of component being painted relative to root.
112      */

113     private int xOffset;
114     /**
115      * Location of component being painted relative to root.
116      */

117     private int yOffset;
118     /**
119      * Graphics from the BufferStrategy.
120      */

121     private Graphics bsg;
122     /**
123      * BufferStrategy currently being used.
124      */

125     private BufferStrategy bufferStrategy;
126     /**
127      * BufferInfo corresponding to root.
128      */

129     private BufferInfo bufferInfo;
130
131     /**
132      * Set to true if the bufferInfo needs to be disposed when current
133      * paint loop is done.
134      */

135     private boolean disposeBufferOnEnd;
136
137
138     static {
139         TRY_FLIP = "true".equals(AccessController.doPrivileged(
140               new GetPropertyAction("swing.useFlipBufferStrategy", "false")));
141     }
142
143     private static Method getGetBufferStrategyMethod() {
144         if (COMPONENT_GET_BUFFER_STRATEGY_METHOD == null) {
145             getMethods();
146         }
147         return COMPONENT_GET_BUFFER_STRATEGY_METHOD;
148     }
149
150     private static Method getCreateBufferStrategyMethod() {
151         if (COMPONENT_CREATE_BUFFER_STRATEGY_METHOD == null) {
152             getMethods();
153         }
154         return COMPONENT_CREATE_BUFFER_STRATEGY_METHOD;
155     }
156
157     private static void getMethods() {
158         java.security.AccessController.doPrivileged(
159                             new java.security.PrivilegedAction JavaDoc<Object JavaDoc>() {
160             public Object JavaDoc run() {
161                 try {
162                     COMPONENT_CREATE_BUFFER_STRATEGY_METHOD = Component.class.
163                               getDeclaredMethod("createBufferStrategy",
164                                                 new Class JavaDoc[] { int.class,
165                                                 BufferCapabilities.class });
166                     COMPONENT_CREATE_BUFFER_STRATEGY_METHOD.
167                                             setAccessible(true);
168                     COMPONENT_GET_BUFFER_STRATEGY_METHOD = Component.class.
169                               getDeclaredMethod("getBufferStrategy");
170                     COMPONENT_GET_BUFFER_STRATEGY_METHOD.setAccessible(true);
171                 } catch (SecurityException JavaDoc e) {
172                     assert false;
173                 } catch (NoSuchMethodException JavaDoc nsme) {
174                     assert false;
175                 }
176                 return null;
177             }
178         });
179     }
180
181     BufferStrategyPaintManager() {
182         bufferInfos = new ArrayList<BufferInfo>(1);
183     }
184
185     //
186
// PaintManager methods
187
//
188

189     /**
190      * Cleans up any created BufferStrategies.
191      */

192     protected void dispose() {
193         // dipose can be invoked at any random time. To avoid
194
// threading dependancies we do the actual diposing via an
195
// invokeLater.
196
SwingUtilities.invokeLater(new Runnable JavaDoc() {
197             public void run() {
198                 java.util.List JavaDoc<BufferInfo> bufferInfos;
199                 synchronized(BufferStrategyPaintManager.this) {
200                     while (showing) {
201                         try {
202                             wait();
203                         } catch (InterruptedException JavaDoc ie) {
204                         }
205                     }
206                     bufferInfos = BufferStrategyPaintManager.this.bufferInfos;
207                     BufferStrategyPaintManager.this.bufferInfos = null;
208                 }
209                 dispose(bufferInfos);
210             }
211         });
212     }
213
214     private void dispose(java.util.List JavaDoc<BufferInfo> bufferInfos) {
215         if (LOGGER.isLoggable(Level.FINER)) {
216             LOGGER.log(Level.FINER, "BufferStrategyPaintManager disposed",
217                        new RuntimeException JavaDoc());
218         }
219         if (bufferInfos != null) {
220             for (BufferInfo bufferInfo : bufferInfos) {
221                 bufferInfo.dispose();
222             }
223         }
224     }
225
226     /**
227      * Shows the specified region of the back buffer. This will return
228      * true if successful, false otherwise. This is invoked on the
229      * toolkit thread in response to an expose event.
230      */

231     public boolean show(Container c, int x, int y, int w, int h) {
232         synchronized(this) {
233             if (painting) {
234                 // Don't show from backbuffer while in the process of
235
// painting.
236
return false;
237             }
238             showing = true;
239         }
240         try {
241             BufferInfo info = getBufferInfo(c);
242             BufferStrategy bufferStrategy;
243             if (info != null && !info.usingFlip && info.isInSync() &&
244                 (bufferStrategy = info.getBufferStrategy(false)) != null) {
245                 SubRegionShowable bsSubRegion =
246                         (SubRegionShowable)bufferStrategy;
247                 boolean paintAllOnExpose = info.getPaintAllOnExpose();
248                 info.setPaintAllOnExpose(false);
249                 if (bsSubRegion.showIfNotLost(x, y, (x + w), (y + h))) {
250                     return !paintAllOnExpose;
251                 }
252                 // Mark the buffer as needing to be repainted. We don't
253
// immediately do a repaint as this method will return false
254
// indicating a PaintEvent should be generated which will
255
// trigger a complete repaint.
256
bufferInfo.setContentsLostDuringExpose(true);
257             }
258         }
259         finally {
260             synchronized(this) {
261                 showing = false;
262                 notifyAll();
263             }
264         }
265         return false;
266     }
267
268     public boolean paint(JComponent JavaDoc paintingComponent,
269                          JComponent JavaDoc bufferComponent, Graphics g,
270                          int x, int y, int w, int h) {
271         if (prepare(paintingComponent, true, x, y, w, h)) {
272             if ((g instanceof SunGraphics2D) &&
273                     ((SunGraphics2D)g).getDestination() == root) {
274                 // BufferStrategy may have already constrained the Graphics. To
275
// account for that we revert the constrain, then apply a
276
// constrain for Swing on top of that.
277
int cx = ((SunGraphics2D)bsg).constrainX;
278                 int cy = ((SunGraphics2D)bsg).constrainY;
279                 if (cx != 0 || cy != 0) {
280                     bsg.translate(-cx, -cy);
281                 }
282                 ((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy,
283                                                x + w, y + h);
284                 bsg.setClip(x, y, w, h);
285                 paintingComponent.paintToOffscreen(bsg, x, y, w, h,
286                                                    x + w, y + h);
287                 accumulate(xOffset + x, yOffset + y, w, h);
288                 return true;
289             } else {
290                 // Assume they are going to eventually render to the screen.
291
// This disables showing from backbuffer until a complete
292
// repaint occurs.
293
bufferInfo.setInSync(false);
294                 // Fall through to old rendering.
295
}
296         }
297         // Invalid root, do what Swing has always done.
298
if (LOGGER.isLoggable(Level.FINER)) {
299             LOGGER.finer("prepare failed");
300         }
301         return super.paint(paintingComponent, bufferComponent, g, x, y, w, h);
302     }
303
304     public void copyArea(JComponent JavaDoc c, Graphics g, int x, int y, int w, int h,
305                          int deltaX, int deltaY, boolean clip) {
306     // Note: this method is only called internally and we know that
307
// g is from a heavyweight Component, so no check is necessary as
308
// it is in paint() above.
309
//
310
// If the buffer isn't in sync there is no point in doing a copyArea,
311
// it has garbage.
312
if (prepare(c, false, 0, 0, 0, 0) && bufferInfo.isInSync()) {
313             if (clip) {
314                 Rectangle cBounds = c.getVisibleRect();
315                 int relX = xOffset + x;
316                 int relY = yOffset + y;
317                 bsg.clipRect(xOffset + cBounds.x,
318                              yOffset + cBounds.y,
319                              cBounds.width, cBounds.height);
320                 bsg.copyArea(relX, relY, w, h, deltaX, deltaY);
321             }
322             else {
323                 bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX,
324                              deltaY);
325             }
326             accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h);
327         } else {
328             if (LOGGER.isLoggable(Level.FINER)) {
329                 LOGGER.finer("copyArea: prepare failed or not in sync");
330             }
331             // Prepare failed, or not in sync. By calling super.copyArea
332
// we'll copy on screen. We need to flush any pending paint to
333
// the screen otherwise we'll do a copyArea on the wrong thing.
334
if (!flushAccumulatedRegion()) {
335                 // Flush failed, copyArea will be copying garbage,
336
// force repaint of all.
337
rootJ.repaint();
338             } else {
339                 super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip);
340             }
341         }
342     }
343
344     public void beginPaint() {
345         synchronized(this) {
346             painting = true;
347             // Make sure another thread isn't attempting to show from
348
// the back buffer.
349
while(showing) {
350                 try {
351                     wait();
352                 } catch (InterruptedException JavaDoc ie) {
353                 }
354             }
355         }
356         if (LOGGER.isLoggable(Level.FINEST)) {
357             LOGGER.finest("beginPaint");
358         }
359         // Reset the area that needs to be painted.
360
resetAccumulated();
361     }
362
363     public void endPaint() {
364         if (LOGGER.isLoggable(Level.FINEST)) {
365             LOGGER.finest("endPaint: region " + accumulatedX + " " +
366                        accumulatedY + " " + accumulatedMaxX + " " +
367                        accumulatedMaxY);
368         }
369         if (painting) {
370             if (!flushAccumulatedRegion()) {
371                 if (!isRepaintingRoot()) {
372                     repaintRoot(rootJ);
373                 }
374                 else {
375                     // Contents lost twice in a row, punt.
376
resetDoubleBufferPerWindow();
377                     // In case we've left junk on the screen, force a repaint.
378
rootJ.repaint();
379                 }
380             }
381         }
382     
383         BufferInfo toDispose = null;
384         synchronized(this) {
385             painting = false;
386             if (disposeBufferOnEnd) {
387                 disposeBufferOnEnd = false;
388                 toDispose = bufferInfo;
389                 bufferInfos.remove(toDispose);
390             }
391         }
392         if (toDispose != null) {
393             toDispose.dispose();
394         }
395     }
396
397     /**
398      * Renders the BufferStrategy to the screen.
399      *
400      * @return true if successful, false otherwise.
401      */

402     private boolean flushAccumulatedRegion() {
403         boolean success = true;
404         if (accumulatedX != Integer.MAX_VALUE) {
405             SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy;
406             boolean contentsLost = bufferStrategy.contentsLost();
407             if (!contentsLost) {
408                 bsSubRegion.show(accumulatedX, accumulatedY,
409                                  accumulatedMaxX, accumulatedMaxY);
410                 contentsLost = bufferStrategy.contentsLost();
411             }
412             if (contentsLost) {
413                 if (LOGGER.isLoggable(Level.FINER)) {
414                     LOGGER.finer("endPaint: contents lost");
415                 }
416                 // Shown region was bogus, mark buffer as out of sync.
417
bufferInfo.setInSync(false);
418                 success = false;
419             }
420         }
421         resetAccumulated();
422         return success;
423     }
424
425     private void resetAccumulated() {
426         accumulatedX = Integer.MAX_VALUE;
427         accumulatedY = Integer.MAX_VALUE;
428         accumulatedMaxX = 0;
429         accumulatedMaxY = 0;
430     }
431
432     /**
433      * Invoked when the double buffering or useTrueDoubleBuffering
434      * changes for a JRootPane. If the rootpane is not double
435      * buffered, or true double buffering changes we throw out any
436      * cache we may have.
437      */

438     public void doubleBufferingChanged(final JRootPane JavaDoc rootPane) {
439         if ((!rootPane.isDoubleBuffered() ||
440                 !rootPane.getUseTrueDoubleBuffering()) &&
441                 rootPane.getParent() != null) {
442             if (!SwingUtilities.isEventDispatchThread()) {
443                 Runnable JavaDoc updater = new Runnable JavaDoc() {
444                     public void run() {
445                         doubleBufferingChanged0(rootPane);
446                     }
447                 };
448                 SwingUtilities.invokeLater(updater);
449             }
450             else {
451                 doubleBufferingChanged0(rootPane);
452             }
453         }
454     }
455
456     /**
457      * Does the work for doubleBufferingChanged.
458      */

459     private void doubleBufferingChanged0(JRootPane JavaDoc rootPane) {
460         // This will only happen on the EDT.
461
BufferInfo info;
462         synchronized(this) {
463             // Make sure another thread isn't attempting to show from
464
// the back buffer.
465
while(showing) {
466                 try {
467                     wait();
468                 } catch (InterruptedException JavaDoc ie) {
469                 }
470             }
471             info = getBufferInfo(rootPane.getParent());
472             if (painting && bufferInfo == info) {
473                 // We're in the process of painting and the user grabbed
474
// the Graphics. If we dispose now, endPaint will attempt
475
// to show a bogus BufferStrategy. Set a flag so that
476
// endPaint knows it needs to dispose this buffer.
477
disposeBufferOnEnd = true;
478                 info = null;
479             } else if (info != null) {
480                 bufferInfos.remove(info);
481             }
482         }
483         if (info != null) {
484             info.dispose();
485         }
486     }
487
488     /**
489      * Calculates information common to paint/copyArea.
490      *
491      * @return true if should use buffering per window in painting.
492      */

493     private boolean prepare(JComponent JavaDoc c, boolean isPaint, int x, int y,
494                             int w, int h) {
495         if (bsg != null) {
496             bsg.dispose();
497             bsg = null;
498         }
499         bufferStrategy = null;
500         if (fetchRoot(c)) {
501             boolean contentsLost = false;
502             BufferInfo bufferInfo = getBufferInfo(root);
503             if (bufferInfo == null) {
504                 contentsLost = true;
505                 bufferInfo = new BufferInfo(root);
506                 bufferInfos.add(bufferInfo);
507                 if (LOGGER.isLoggable(Level.FINER)) {
508                     LOGGER.finer("prepare: new BufferInfo: " + root);
509                 }
510             }
511             this.bufferInfo = bufferInfo;
512             if (!bufferInfo.hasBufferStrategyChanged()) {
513                 bufferStrategy = bufferInfo.getBufferStrategy(true);
514                 if (bufferStrategy != null) {
515                     bsg = bufferStrategy.getDrawGraphics();
516                     if (bufferStrategy.contentsRestored()) {
517                         contentsLost = true;
518                         if (LOGGER.isLoggable(Level.FINER)) {
519                             LOGGER.finer(
520                                 "prepare: contents restored in prepare");
521                         }
522                     }
523                 }
524                 else {
525                     // Couldn't create BufferStrategy, fallback to normal
526
// painting.
527
return false;
528                 }
529                 if (bufferInfo.getContentsLostDuringExpose()) {
530                     contentsLost = true;
531                     bufferInfo.setContentsLostDuringExpose(false);
532                     if (LOGGER.isLoggable(Level.FINER)) {
533                         LOGGER.finer("prepare: contents lost on expose");
534                     }
535                 }
536                 if (isPaint && c == rootJ && x == 0 && y == 0 &&
537                       c.getWidth() == w && c.getHeight() == h) {
538                     bufferInfo.setInSync(true);
539                 }
540                 else if (contentsLost) {
541                     // We either recreated the BufferStrategy, or the contents
542
// of the buffer strategy were restored. We need to
543
// repaint the root pane so that the back buffer is in sync
544
// again.
545
bufferInfo.setInSync(false);
546                     if (!isRepaintingRoot()) {
547                         repaintRoot(rootJ);
548                     }
549                     else {
550                         // Contents lost twice in a row, punt
551
resetDoubleBufferPerWindow();
552                     }
553                 }
554                 return (bufferInfos != null);
555             }
556         }
557         return false;
558     }
559
560     private boolean fetchRoot(JComponent JavaDoc c) {
561         boolean encounteredHW = false;
562         rootJ = c;
563         root = c;
564         xOffset = yOffset = 0;
565         while (root != null && (!(root instanceof Window) &&
566                                 !(root instanceof Applet JavaDoc))) {
567             xOffset += root.getX();
568             yOffset += root.getY();
569             root = root.getParent();
570             if (root != null) {
571                 if (root instanceof JComponent JavaDoc) {
572                     rootJ = (JComponent JavaDoc)root;
573                 }
574                 else if (!root.isLightweight()) {
575                     if (!encounteredHW) {
576                         encounteredHW = true;
577                     }
578                     else {
579                         // We've encountered two hws now and may have
580
// a containment hierarchy with lightweights containing
581
// heavyweights containing other lightweights.
582
// Heavyweights poke holes in lightweight
583
// rendering so that if we call show on the BS
584
// (which is associated with the Window) you will
585
// not see the contents over any child
586
// heavyweights. If we didn't do this when we
587
// went to show the descendants of the nested hw
588
// you would see nothing, so, we bail out here.
589
return false;
590                     }
591                 }
592             }
593         }
594         if ((root instanceof RootPaneContainer JavaDoc) &&
595             (rootJ instanceof JRootPane JavaDoc)) {
596             // We're in a Swing heavyeight (JFrame/JWindow...), use double
597
// buffering if double buffering enabled on the JRootPane and
598
// the JRootPane wants true double buffering.
599
if (rootJ.isDoubleBuffered() &&
600                     ((JRootPane JavaDoc)rootJ).getUseTrueDoubleBuffering()) {
601                 // Whether or not a component is double buffered is a
602
// bit tricky with Swing. This gives a good approximation
603
// of the various ways to turn on double buffering for
604
// components.
605
return true;
606             }
607         }
608         // Don't do true double buffering.
609
return false;
610     }
611
612     /**
613      * Turns off double buffering per window.
614      */

615     private void resetDoubleBufferPerWindow() {
616         if (bufferInfos != null) {
617             dispose(bufferInfos);
618             bufferInfos = null;
619             repaintManager.setPaintManager(null);
620         }
621     }
622
623     /**
624      * Returns the BufferInfo for the specified root or null if one
625      * hasn't been created yet.
626      */

627     private BufferInfo getBufferInfo(Container root) {
628         for (int counter = bufferInfos.size() - 1; counter >= 0; counter--) {
629             BufferInfo bufferInfo = bufferInfos.get(counter);
630             Container biRoot = bufferInfo.getRoot();
631             if (biRoot == null) {
632                 // Window gc'ed
633
bufferInfos.remove(counter);
634                 if (LOGGER.isLoggable(Level.FINER)) {
635                     LOGGER.finer("BufferInfo pruned, root null");
636                 }
637             }
638             else if (biRoot == root) {
639                 return bufferInfo;
640             }
641         }
642         return null;
643     }
644
645     private void accumulate(int x, int y, int w, int h) {
646         accumulatedX = Math.min(x, accumulatedX);
647         accumulatedY = Math.min(y, accumulatedY);
648         accumulatedMaxX = Math.max(accumulatedMaxX, x + w);
649         accumulatedMaxY = Math.max(accumulatedMaxY, y + h);
650     }
651
652
653
654     /**
655      * BufferInfo is used to track the BufferStrategy being used for
656      * a particular Component. In addition to tracking the BufferStrategy
657      * it will install a WindowListener and ComponentListener. When the
658      * component is hidden/iconified the buffer is marked as needing to be
659      * completely repainted.
660      */

661     private class BufferInfo extends ComponentAdapter implements
662                                WindowListener {
663         // NOTE: This class does NOT hold a direct reference to the root, if it
664
// did there would be a cycle between the BufferPerWindowPaintManager
665
// and the Window so that it could never be GC'ed
666
//
667
// Reference to BufferStrategy is referenced via WeakReference for
668
// same reason.
669
private WeakReference JavaDoc<BufferStrategy> weakBS;
670         private WeakReference JavaDoc<Container> root;
671         // Whether or not we're using flip bs or blit.
672
private boolean usingFlip;
673         // Indicates whether or not the backbuffer and display are in sync.
674
// This is set to true when a full repaint on the rootpane is done.
675
private boolean inSync;
676         // Indicates the contents were lost during and expose event.
677
private boolean contentsLostDuringExpose;
678         // Indicates we need to generate a paint event on expose.
679
private boolean paintAllOnExpose;
680
681
682         public BufferInfo(Container root) {
683             this.root = new WeakReference JavaDoc<Container>(root);
684             root.addComponentListener(this);
685             if (root instanceof Window) {
686                 ((Window)root).addWindowListener(this);
687             }
688         }
689
690         public void setPaintAllOnExpose(boolean paintAllOnExpose) {
691             this.paintAllOnExpose = paintAllOnExpose;
692         }
693
694         public boolean getPaintAllOnExpose() {
695             return paintAllOnExpose;
696         }
697
698         public void setContentsLostDuringExpose(boolean value) {
699             contentsLostDuringExpose = value;
700         }
701
702         public boolean getContentsLostDuringExpose() {
703             return contentsLostDuringExpose;
704         }
705
706         public void setInSync(boolean inSync) {
707             this.inSync = inSync;
708         }
709
710         /**
711          * Whether or not the contents of the buffer strategy
712          * is in sync with the window. This is set to true when the root
713          * pane paints all, and false when contents are lost/restored.
714          */

715         public boolean isInSync() {
716             return inSync;
717         }
718
719         /**
720          * Returns the Root (Window or Applet) that this BufferInfo references.
721          */

722         public Container getRoot() {
723             return (root == null) ? null : root.get();
724         }
725
726         /**
727          * Returns the BufferStartegy. This will return null if
728          * the BufferStartegy hasn't been created and <code>create</code> is
729          * false, or if there is a problem in creating the
730          * <code>BufferStartegy</code>.
731          *
732          * @param create If true, and the BufferStartegy is currently null,
733          * one will be created.
734          */

735         public BufferStrategy getBufferStrategy(boolean create) {
736             BufferStrategy bs = (weakBS == null) ? null : weakBS.get();
737             if (bs == null && create) {
738                 bs = createBufferStrategy();
739                 if (bs != null) {
740                     weakBS = new WeakReference JavaDoc<BufferStrategy>(bs);
741                 }
742                 if (LOGGER.isLoggable(Level.FINER)) {
743                     LOGGER.finer("getBufferStrategy: created bs: " + bs);
744                 }
745             }
746             return bs;
747         }
748
749         /**
750          * Returns true if using a flip buffer strategy.
751          */

752         public boolean usingFlip() {
753             return usingFlip;
754         }
755
756         /**
757          * Returns true if the buffer strategy of the component differs
758          * from current buffer strategy.
759          */

760         public boolean hasBufferStrategyChanged() {
761             Container root = getRoot();
762             if (root != null) {
763                 BufferStrategy ourBS = null;
764                 BufferStrategy componentBS = null;
765
766                 ourBS = getBufferStrategy(false);
767                 if (root instanceof Window) {
768                     componentBS = ((Window)root).getBufferStrategy();
769                 }
770                 else {
771                     try {
772                         componentBS = (BufferStrategy)
773                                  getGetBufferStrategyMethod().invoke(root);
774                     } catch (InvocationTargetException ite) {
775                         assert false;
776                     } catch (IllegalArgumentException JavaDoc iae) {
777                         assert false;
778                     } catch (IllegalAccessException JavaDoc iae2) {
779                         assert false;
780                     }
781                 }
782                 if (componentBS != ourBS) {
783                     // Component has a different BS, dispose ours.
784
if (ourBS != null) {
785                         ourBS.dispose();
786                     }
787                     weakBS = null;
788                     return true;
789                 }
790             }
791             return false;
792         }
793
794         /**
795          * Creates the BufferStrategy. If the appropriate system property
796          * has been set we'll try for flip first and then we'll try for
797          * blit.
798          */

799         private BufferStrategy createBufferStrategy() {
800         BufferCapabilities caps;
801             Container root = getRoot();
802             if (root == null) {
803                 return null;
804             }
805             BufferStrategy bs = null;
806             if (TRY_FLIP) {
807                 bs = createBufferStrategy(root,BufferCapabilities.FlipContents.
808                                           COPIED);
809                 usingFlip = true;
810                 if (LOGGER.isLoggable(Level.FINER)) {
811                     LOGGER.finer("createBufferStrategy: using flip strategy");
812                 }
813             }
814             if (bs == null) {
815                 bs = createBufferStrategy(root, null);
816                 usingFlip = false;
817             }
818             if (!(bs instanceof SubRegionShowable)) {
819                 // We do this for two reasons:
820
// 1. So that we know we can cast to SubRegionShowable and
821
// invoke show with the minimal region to update
822
// 2. To avoid the possibility of invoking client code
823
// on the toolkit thread.
824
bs = null;
825             }
826             return bs;
827         }
828
829         // Creates and returns a buffer strategy of the requested type. If
830
// there is a problem creating the buffer strategy this will
831
// eat the exception and return null.
832
private BufferStrategy createBufferStrategy(Container root,
833                                      BufferCapabilities.FlipContents type) {
834             BufferCapabilities caps = new BufferCapabilities(
835             new ImageCapabilities(true),
836                     new ImageCapabilities(true),
837                     type);
838             BufferStrategy bs = null;
839             if (root instanceof Applet JavaDoc) {
840                 try {
841                     getCreateBufferStrategyMethod().invoke(root, 2, caps);
842                     bs = (BufferStrategy)getGetBufferStrategyMethod().
843                                             invoke(root);
844                 } catch (InvocationTargetException ite) {
845                     // Type is not supported
846
if (LOGGER.isLoggable(Level.FINER)) {
847                         LOGGER.log(Level.FINER, "createBufferStratety failed",
848                                    ite);
849                     }
850                 } catch (IllegalArgumentException JavaDoc iae) {
851                     assert false;
852                 } catch (IllegalAccessException JavaDoc iae2) {
853                     assert false;
854                 }
855             }
856             else {
857                 try {
858                     ((Window)root).createBufferStrategy(2, caps);
859                     bs = ((Window)root).getBufferStrategy();
860                 } catch (AWTException e) {
861                     // Type not supported
862
if (LOGGER.isLoggable(Level.FINER)) {
863                         LOGGER.log(Level.FINER, "createBufferStratety failed",
864                                    e);
865                     }
866                 }
867             }
868             return bs;
869         }
870
871         /**
872          * Cleans up and removes any references.
873          */

874         public void dispose() {
875             Container root = getRoot();
876             if (LOGGER.isLoggable(Level.FINER)) {
877                 LOGGER.log(Level.FINER, "disposed BufferInfo for: " + root);
878             }
879             if (root != null) {
880                 root.removeComponentListener(this);
881                 if (root instanceof Window) {
882                     ((Window)root).removeWindowListener(this);
883                 }
884                 BufferStrategy bs = getBufferStrategy(false);
885                 if (bs != null) {
886                     bs.dispose();
887                 }
888             }
889             this.root = null;
890             weakBS = null;
891         }
892
893         // We mark the buffer as needing to be painted on a hide/iconify
894
// because the developer may have conditionalized painting based on
895
// visibility.
896
// Ideally we would also move to having the BufferStrategy being
897
// a SoftReference in Component here, but that requires changes to
898
// Component and the like.
899
public void componentHidden(ComponentEvent e) {
900             Container root = getRoot();
901             if (root != null && root.isVisible()) {
902                 // This case will only happen if a developer calls
903
// hide immediately followed by show. In this case
904
// the event is delivered after show and the window
905
// will still be visible. If a developer altered the
906
// contents of the window between the hide/show
907
// invocations we won't recognize we need to paint and
908
// the contents would be bogus. Calling repaint here
909
// fixs everything up.
910
root.repaint();
911             }
912             else {
913                 setPaintAllOnExpose(true);
914             }
915         }
916
917         public void windowIconified(WindowEvent e) {
918             setPaintAllOnExpose(true);
919         }
920
921         // On a dispose we chuck everything.
922
public void windowClosed(WindowEvent e) {
923             // Make sure we're not showing.
924
synchronized(BufferStrategyPaintManager.this) {
925                 while (showing) {
926                     try {
927                         BufferStrategyPaintManager.this.wait();
928                     } catch (InterruptedException JavaDoc ie) {
929                     }
930                 }
931                 bufferInfos.remove(this);
932             }
933             dispose();
934         }
935
936         public void windowOpened(WindowEvent e) {
937         }
938
939         public void windowClosing(WindowEvent e) {
940         }
941
942         public void windowDeiconified(WindowEvent e) {
943         }
944
945         public void windowActivated(WindowEvent e) {
946         }
947
948         public void windowDeactivated(WindowEvent e) {
949         }
950     }
951 }
952
Popular Tags