Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/javax/swing/BufferStrategyPaintManager.java
41153 views
1
/*
2
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
package javax.swing;
26
27
import java.awt.*;
28
import java.awt.event.*;
29
import java.awt.image.*;
30
import java.lang.ref.WeakReference;
31
import java.util.*;
32
33
import com.sun.java.swing.SwingUtilities3;
34
import sun.awt.AWTAccessor;
35
36
import sun.awt.SubRegionShowable;
37
import sun.java2d.SunGraphics2D;
38
import sun.java2d.pipe.hw.ExtendedBufferCapabilities;
39
import sun.awt.SunToolkit;
40
import sun.util.logging.PlatformLogger;
41
42
/**
43
* A PaintManager implementation that uses a BufferStrategy for
44
* rendering.
45
*
46
* @author Scott Violet
47
*/
48
class BufferStrategyPaintManager extends RepaintManager.PaintManager {
49
//
50
// All drawing is done to a BufferStrategy. At the end of painting
51
// (endPaint) the region that was painted is flushed to the screen
52
// (using BufferStrategy.show).
53
//
54
// PaintManager.show is overriden to show directly from the
55
// BufferStrategy (when using blit), if successful true is
56
// returned and a paint event will not be generated. To avoid
57
// showing from the buffer while painting a locking scheme is
58
// implemented. When beginPaint is invoked the field painting is
59
// set to true. If painting is true and show is invoked we
60
// immediately return false. This is done to avoid blocking the
61
// toolkit thread while painting happens. In a similar way when
62
// show is invoked the field showing is set to true, beginPaint
63
// will then block until showing is true. This scheme ensures we
64
// only ever have one thread using the BufferStrategy and it also
65
// ensures the toolkit thread remains as responsive as possible.
66
//
67
// If we're using a flip strategy the contents of the backbuffer may
68
// have changed and so show only attempts to show from the backbuffer
69
// if we get a blit strategy.
70
//
71
72
private static final PlatformLogger LOGGER = PlatformLogger.getLogger(
73
"javax.swing.BufferStrategyPaintManager");
74
75
/**
76
* List of BufferInfos. We don't use a Map primarily because
77
* there are typically only a handful of top level components making
78
* a Map overkill.
79
*/
80
private ArrayList<BufferInfo> bufferInfos;
81
82
/**
83
* Indicates <code>beginPaint</code> has been invoked. This is
84
* set to true for the life of beginPaint/endPaint pair.
85
*/
86
private boolean painting;
87
/**
88
* Indicates we're in the process of showing. All painting, on the EDT,
89
* is blocked while this is true.
90
*/
91
private boolean showing;
92
93
//
94
// Region that we need to flush. When beginPaint is called these are
95
// reset and any subsequent calls to paint/copyArea then update these
96
// fields accordingly. When endPaint is called we then try and show
97
// the accumulated region.
98
// These fields are in the coordinate system of the root.
99
//
100
private int accumulatedX;
101
private int accumulatedY;
102
private int accumulatedMaxX;
103
private int accumulatedMaxY;
104
105
//
106
// The following fields are set by prepare
107
//
108
109
/**
110
* Farthest JComponent ancestor for the current paint/copyArea.
111
*/
112
private JComponent rootJ;
113
/**
114
* Location of component being painted relative to root.
115
*/
116
private int xOffset;
117
/**
118
* Location of component being painted relative to root.
119
*/
120
private int yOffset;
121
/**
122
* Graphics from the BufferStrategy.
123
*/
124
private Graphics bsg;
125
/**
126
* BufferStrategy currently being used.
127
*/
128
private BufferStrategy bufferStrategy;
129
/**
130
* BufferInfo corresponding to root.
131
*/
132
private BufferInfo bufferInfo;
133
134
/**
135
* Set to true if the bufferInfo needs to be disposed when current
136
* paint loop is done.
137
*/
138
private boolean disposeBufferOnEnd;
139
140
BufferStrategyPaintManager() {
141
bufferInfos = new ArrayList<BufferInfo>(1);
142
}
143
144
//
145
// PaintManager methods
146
//
147
148
/**
149
* Cleans up any created BufferStrategies.
150
*/
151
protected void dispose() {
152
// dipose can be invoked at any random time. To avoid
153
// threading dependancies we do the actual diposing via an
154
// invokeLater.
155
SwingUtilities.invokeLater(new Runnable() {
156
public void run() {
157
java.util.List<BufferInfo> bufferInfos;
158
synchronized(BufferStrategyPaintManager.this) {
159
while (showing) {
160
try {
161
BufferStrategyPaintManager.this.wait();
162
} catch (InterruptedException ie) {
163
}
164
}
165
bufferInfos = BufferStrategyPaintManager.this.bufferInfos;
166
BufferStrategyPaintManager.this.bufferInfos = null;
167
}
168
dispose(bufferInfos);
169
}
170
});
171
}
172
173
private void dispose(java.util.List<BufferInfo> bufferInfos) {
174
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
175
LOGGER.finer("BufferStrategyPaintManager disposed",
176
new RuntimeException());
177
}
178
if (bufferInfos != null) {
179
for (BufferInfo bufferInfo : bufferInfos) {
180
bufferInfo.dispose();
181
}
182
}
183
}
184
185
/**
186
* Shows the specified region of the back buffer. This will return
187
* true if successful, false otherwise. This is invoked on the
188
* toolkit thread in response to an expose event.
189
*/
190
public boolean show(Container c, int x, int y, int w, int h) {
191
synchronized(this) {
192
if (painting) {
193
// Don't show from backbuffer while in the process of
194
// painting.
195
return false;
196
}
197
showing = true;
198
}
199
try {
200
BufferInfo info = getBufferInfo(c);
201
BufferStrategy bufferStrategy;
202
if (info != null && info.isInSync() &&
203
(bufferStrategy = info.getBufferStrategy(false)) != null) {
204
SubRegionShowable bsSubRegion =
205
(SubRegionShowable)bufferStrategy;
206
boolean paintAllOnExpose = info.getPaintAllOnExpose();
207
info.setPaintAllOnExpose(false);
208
if (bsSubRegion.showIfNotLost(x, y, (x + w), (y + h))) {
209
return !paintAllOnExpose;
210
}
211
// Mark the buffer as needing to be repainted. We don't
212
// immediately do a repaint as this method will return false
213
// indicating a PaintEvent should be generated which will
214
// trigger a complete repaint.
215
bufferInfo.setContentsLostDuringExpose(true);
216
}
217
}
218
finally {
219
synchronized(this) {
220
showing = false;
221
notifyAll();
222
}
223
}
224
return false;
225
}
226
227
public boolean paint(JComponent paintingComponent,
228
JComponent bufferComponent, Graphics g,
229
int x, int y, int w, int h) {
230
Container root = fetchRoot(paintingComponent);
231
232
if (prepare(paintingComponent, root, true, x, y, w, h)) {
233
if ((g instanceof SunGraphics2D) &&
234
((SunGraphics2D)g).getDestination() == root) {
235
// BufferStrategy may have already constrained the Graphics. To
236
// account for that we revert the constrain, then apply a
237
// constrain for Swing on top of that.
238
int cx = ((SunGraphics2D)bsg).constrainX;
239
int cy = ((SunGraphics2D)bsg).constrainY;
240
if (cx != 0 || cy != 0) {
241
bsg.translate(-cx, -cy);
242
}
243
((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy,
244
x + w, y + h);
245
bsg.setClip(x, y, w, h);
246
paintingComponent.paintToOffscreen(bsg, x, y, w, h,
247
x + w, y + h);
248
accumulate(xOffset + x, yOffset + y, w, h);
249
return true;
250
} else {
251
// Assume they are going to eventually render to the screen.
252
// This disables showing from backbuffer until a complete
253
// repaint occurs.
254
bufferInfo.setInSync(false);
255
// Fall through to old rendering.
256
}
257
}
258
// Invalid root, do what Swing has always done.
259
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
260
LOGGER.finer("prepare failed");
261
}
262
return super.paint(paintingComponent, bufferComponent, g, x, y, w, h);
263
}
264
265
public void copyArea(JComponent c, Graphics g, int x, int y, int w, int h,
266
int deltaX, int deltaY, boolean clip) {
267
// Note: this method is only called internally and we know that
268
// g is from a heavyweight Component, so no check is necessary as
269
// it is in paint() above.
270
//
271
// If the buffer isn't in sync there is no point in doing a copyArea,
272
// it has garbage.
273
Container root = fetchRoot(c);
274
275
if (prepare(c, root, false, 0, 0, 0, 0) && bufferInfo.isInSync()) {
276
if (clip) {
277
Rectangle cBounds = c.getVisibleRect();
278
int relX = xOffset + x;
279
int relY = yOffset + y;
280
bsg.clipRect(xOffset + cBounds.x,
281
yOffset + cBounds.y,
282
cBounds.width, cBounds.height);
283
bsg.copyArea(relX, relY, w, h, deltaX, deltaY);
284
}
285
else {
286
bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX,
287
deltaY);
288
}
289
accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h);
290
} else {
291
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
292
LOGGER.finer("copyArea: prepare failed or not in sync");
293
}
294
// Prepare failed, or not in sync. By calling super.copyArea
295
// we'll copy on screen. We need to flush any pending paint to
296
// the screen otherwise we'll do a copyArea on the wrong thing.
297
if (!flushAccumulatedRegion()) {
298
// Flush failed, copyArea will be copying garbage,
299
// force repaint of all.
300
rootJ.repaint();
301
} else {
302
super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip);
303
}
304
}
305
}
306
307
public void beginPaint() {
308
synchronized(this) {
309
painting = true;
310
// Make sure another thread isn't attempting to show from
311
// the back buffer.
312
while(showing) {
313
try {
314
wait();
315
} catch (InterruptedException ie) {
316
}
317
}
318
}
319
if (LOGGER.isLoggable(PlatformLogger.Level.FINEST)) {
320
LOGGER.finest("beginPaint");
321
}
322
// Reset the area that needs to be painted.
323
resetAccumulated();
324
}
325
326
public void endPaint() {
327
if (LOGGER.isLoggable(PlatformLogger.Level.FINEST)) {
328
LOGGER.finest("endPaint: region " + accumulatedX + " " +
329
accumulatedY + " " + accumulatedMaxX + " " +
330
accumulatedMaxY);
331
}
332
if (painting) {
333
if (!flushAccumulatedRegion()) {
334
if (!isRepaintingRoot()) {
335
repaintRoot(rootJ);
336
}
337
else {
338
// Contents lost twice in a row, punt.
339
resetDoubleBufferPerWindow();
340
// In case we've left junk on the screen, force a repaint.
341
rootJ.repaint();
342
}
343
}
344
}
345
346
BufferInfo toDispose = null;
347
synchronized(this) {
348
painting = false;
349
if (disposeBufferOnEnd) {
350
disposeBufferOnEnd = false;
351
toDispose = bufferInfo;
352
bufferInfos.remove(toDispose);
353
}
354
}
355
if (toDispose != null) {
356
toDispose.dispose();
357
}
358
}
359
360
/**
361
* Renders the BufferStrategy to the screen.
362
*
363
* @return true if successful, false otherwise.
364
*/
365
private boolean flushAccumulatedRegion() {
366
boolean success = true;
367
if (accumulatedX != Integer.MAX_VALUE) {
368
SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy;
369
boolean contentsLost = bufferStrategy.contentsLost();
370
if (!contentsLost) {
371
bsSubRegion.show(accumulatedX, accumulatedY,
372
accumulatedMaxX, accumulatedMaxY);
373
contentsLost = bufferStrategy.contentsLost();
374
}
375
if (contentsLost) {
376
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
377
LOGGER.finer("endPaint: contents lost");
378
}
379
// Shown region was bogus, mark buffer as out of sync.
380
bufferInfo.setInSync(false);
381
success = false;
382
}
383
}
384
resetAccumulated();
385
return success;
386
}
387
388
private void resetAccumulated() {
389
accumulatedX = Integer.MAX_VALUE;
390
accumulatedY = Integer.MAX_VALUE;
391
accumulatedMaxX = 0;
392
accumulatedMaxY = 0;
393
}
394
395
/**
396
* Invoked when the double buffering or useTrueDoubleBuffering
397
* changes for a JRootPane. If the rootpane is not double
398
* buffered, or true double buffering changes we throw out any
399
* cache we may have.
400
*/
401
public void doubleBufferingChanged(final JRootPane rootPane) {
402
if ((!rootPane.isDoubleBuffered() ||
403
!rootPane.getUseTrueDoubleBuffering()) &&
404
rootPane.getParent() != null) {
405
if (!SwingUtilities.isEventDispatchThread()) {
406
Runnable updater = new Runnable() {
407
public void run() {
408
doubleBufferingChanged0(rootPane);
409
}
410
};
411
SwingUtilities.invokeLater(updater);
412
}
413
else {
414
doubleBufferingChanged0(rootPane);
415
}
416
}
417
}
418
419
/**
420
* Does the work for doubleBufferingChanged.
421
*/
422
private void doubleBufferingChanged0(JRootPane rootPane) {
423
// This will only happen on the EDT.
424
BufferInfo info;
425
synchronized(this) {
426
// Make sure another thread isn't attempting to show from
427
// the back buffer.
428
while(showing) {
429
try {
430
wait();
431
} catch (InterruptedException ie) {
432
}
433
}
434
info = getBufferInfo(rootPane.getParent());
435
if (painting && bufferInfo == info) {
436
// We're in the process of painting and the user grabbed
437
// the Graphics. If we dispose now, endPaint will attempt
438
// to show a bogus BufferStrategy. Set a flag so that
439
// endPaint knows it needs to dispose this buffer.
440
disposeBufferOnEnd = true;
441
info = null;
442
} else if (info != null) {
443
bufferInfos.remove(info);
444
}
445
}
446
if (info != null) {
447
info.dispose();
448
}
449
}
450
451
/**
452
* Calculates information common to paint/copyArea.
453
*
454
* @return true if should use buffering per window in painting.
455
*/
456
private boolean prepare(JComponent c, Container root, boolean isPaint, int x, int y,
457
int w, int h) {
458
if (bsg != null) {
459
bsg.dispose();
460
bsg = null;
461
}
462
bufferStrategy = null;
463
if (root != null) {
464
boolean contentsLost = false;
465
BufferInfo bufferInfo = getBufferInfo(root);
466
if (bufferInfo == null) {
467
contentsLost = true;
468
bufferInfo = new BufferInfo(root);
469
bufferInfos.add(bufferInfo);
470
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
471
LOGGER.finer("prepare: new BufferInfo: " + root);
472
}
473
}
474
this.bufferInfo = bufferInfo;
475
if (!bufferInfo.hasBufferStrategyChanged()) {
476
bufferStrategy = bufferInfo.getBufferStrategy(true);
477
if (bufferStrategy != null) {
478
bsg = bufferStrategy.getDrawGraphics();
479
if (bufferStrategy.contentsRestored()) {
480
contentsLost = true;
481
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
482
LOGGER.finer("prepare: contents restored in prepare");
483
}
484
}
485
}
486
else {
487
// Couldn't create BufferStrategy, fallback to normal
488
// painting.
489
return false;
490
}
491
if (bufferInfo.getContentsLostDuringExpose()) {
492
contentsLost = true;
493
bufferInfo.setContentsLostDuringExpose(false);
494
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
495
LOGGER.finer("prepare: contents lost on expose");
496
}
497
}
498
if (isPaint && c == rootJ && x == 0 && y == 0 &&
499
c.getWidth() == w && c.getHeight() == h) {
500
bufferInfo.setInSync(true);
501
}
502
else if (contentsLost) {
503
// We either recreated the BufferStrategy, or the contents
504
// of the buffer strategy were restored. We need to
505
// repaint the root pane so that the back buffer is in sync
506
// again.
507
bufferInfo.setInSync(false);
508
if (!isRepaintingRoot()) {
509
repaintRoot(rootJ);
510
}
511
else {
512
// Contents lost twice in a row, punt
513
resetDoubleBufferPerWindow();
514
}
515
}
516
return (bufferInfos != null);
517
}
518
}
519
return false;
520
}
521
522
private Container fetchRoot(JComponent c) {
523
boolean encounteredHW = false;
524
rootJ = c;
525
Container root = c;
526
xOffset = yOffset = 0;
527
while (root != null &&
528
(!(root instanceof Window) &&
529
!SunToolkit.isInstanceOf(root, "java.applet.Applet"))) {
530
xOffset += root.getX();
531
yOffset += root.getY();
532
root = root.getParent();
533
if (root != null) {
534
if (root instanceof JComponent) {
535
rootJ = (JComponent)root;
536
}
537
else if (!root.isLightweight()) {
538
if (!encounteredHW) {
539
encounteredHW = true;
540
}
541
else {
542
// We've encountered two hws now and may have
543
// a containment hierarchy with lightweights containing
544
// heavyweights containing other lightweights.
545
// Heavyweights poke holes in lightweight
546
// rendering so that if we call show on the BS
547
// (which is associated with the Window) you will
548
// not see the contents over any child
549
// heavyweights. If we didn't do this when we
550
// went to show the descendants of the nested hw
551
// you would see nothing, so, we bail out here.
552
return null;
553
}
554
}
555
}
556
}
557
if ((root instanceof RootPaneContainer) &&
558
(rootJ instanceof JRootPane)) {
559
// We're in a Swing heavyeight (JFrame/JWindow...), use double
560
// buffering if double buffering enabled on the JRootPane and
561
// the JRootPane wants true double buffering.
562
if (rootJ.isDoubleBuffered() &&
563
((JRootPane)rootJ).getUseTrueDoubleBuffering()) {
564
// Whether or not a component is double buffered is a
565
// bit tricky with Swing. This gives a good approximation
566
// of the various ways to turn on double buffering for
567
// components.
568
return root;
569
}
570
}
571
// Don't do true double buffering.
572
return null;
573
}
574
575
/**
576
* Turns off double buffering per window.
577
*/
578
private void resetDoubleBufferPerWindow() {
579
if (bufferInfos != null) {
580
dispose(bufferInfos);
581
bufferInfos = null;
582
repaintManager.setPaintManager(null);
583
}
584
}
585
586
/**
587
* Returns the BufferInfo for the specified root or null if one
588
* hasn't been created yet.
589
*/
590
private BufferInfo getBufferInfo(Container root) {
591
for (int counter = bufferInfos.size() - 1; counter >= 0; counter--) {
592
BufferInfo bufferInfo = bufferInfos.get(counter);
593
Container biRoot = bufferInfo.getRoot();
594
if (biRoot == null) {
595
// Window gc'ed
596
bufferInfos.remove(counter);
597
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
598
LOGGER.finer("BufferInfo pruned, root null");
599
}
600
}
601
else if (biRoot == root) {
602
return bufferInfo;
603
}
604
}
605
return null;
606
}
607
608
private void accumulate(int x, int y, int w, int h) {
609
accumulatedX = Math.min(x, accumulatedX);
610
accumulatedY = Math.min(y, accumulatedY);
611
accumulatedMaxX = Math.max(accumulatedMaxX, x + w);
612
accumulatedMaxY = Math.max(accumulatedMaxY, y + h);
613
}
614
615
616
617
/**
618
* BufferInfo is used to track the BufferStrategy being used for
619
* a particular Component. In addition to tracking the BufferStrategy
620
* it will install a WindowListener and ComponentListener. When the
621
* component is hidden/iconified the buffer is marked as needing to be
622
* completely repainted.
623
*/
624
private class BufferInfo extends ComponentAdapter implements
625
WindowListener {
626
// NOTE: This class does NOT hold a direct reference to the root, if it
627
// did there would be a cycle between the BufferPerWindowPaintManager
628
// and the Window so that it could never be GC'ed
629
//
630
// Reference to BufferStrategy is referenced via WeakReference for
631
// same reason.
632
private WeakReference<BufferStrategy> weakBS;
633
private WeakReference<Container> root;
634
// Indicates whether or not the backbuffer and display are in sync.
635
// This is set to true when a full repaint on the rootpane is done.
636
private boolean inSync;
637
// Indicates the contents were lost during and expose event.
638
private boolean contentsLostDuringExpose;
639
// Indicates we need to generate a paint event on expose.
640
private boolean paintAllOnExpose;
641
642
643
public BufferInfo(Container root) {
644
this.root = new WeakReference<Container>(root);
645
root.addComponentListener(this);
646
if (root instanceof Window) {
647
((Window)root).addWindowListener(this);
648
}
649
}
650
651
public void setPaintAllOnExpose(boolean paintAllOnExpose) {
652
this.paintAllOnExpose = paintAllOnExpose;
653
}
654
655
public boolean getPaintAllOnExpose() {
656
return paintAllOnExpose;
657
}
658
659
public void setContentsLostDuringExpose(boolean value) {
660
contentsLostDuringExpose = value;
661
}
662
663
public boolean getContentsLostDuringExpose() {
664
return contentsLostDuringExpose;
665
}
666
667
public void setInSync(boolean inSync) {
668
this.inSync = inSync;
669
}
670
671
/**
672
* Whether or not the contents of the buffer strategy
673
* is in sync with the window. This is set to true when the root
674
* pane paints all, and false when contents are lost/restored.
675
*/
676
public boolean isInSync() {
677
return inSync;
678
}
679
680
/**
681
* Returns the Root (Window or Applet) that this BufferInfo references.
682
*/
683
public Container getRoot() {
684
return (root == null) ? null : root.get();
685
}
686
687
/**
688
* Returns the BufferStartegy. This will return null if
689
* the BufferStartegy hasn't been created and <code>create</code> is
690
* false, or if there is a problem in creating the
691
* <code>BufferStartegy</code>.
692
*
693
* @param create If true, and the BufferStartegy is currently null,
694
* one will be created.
695
*/
696
public BufferStrategy getBufferStrategy(boolean create) {
697
BufferStrategy bs = (weakBS == null) ? null : weakBS.get();
698
if (bs == null && create) {
699
bs = createBufferStrategy();
700
if (bs != null) {
701
weakBS = new WeakReference<BufferStrategy>(bs);
702
}
703
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
704
LOGGER.finer("getBufferStrategy: created bs: " + bs);
705
}
706
}
707
return bs;
708
}
709
710
/**
711
* Returns true if the buffer strategy of the component differs
712
* from current buffer strategy.
713
*/
714
public boolean hasBufferStrategyChanged() {
715
Container root = getRoot();
716
if (root != null) {
717
BufferStrategy ourBS = null;
718
BufferStrategy componentBS = null;
719
720
ourBS = getBufferStrategy(false);
721
if (root instanceof Window) {
722
componentBS = ((Window)root).getBufferStrategy();
723
}
724
else {
725
componentBS = AWTAccessor.getComponentAccessor().getBufferStrategy(root);
726
}
727
if (componentBS != ourBS) {
728
// Component has a different BS, dispose ours.
729
if (ourBS != null) {
730
ourBS.dispose();
731
}
732
weakBS = null;
733
return true;
734
}
735
}
736
return false;
737
}
738
739
/**
740
* Creates the BufferStrategy. If the appropriate system property
741
* has been set we'll try for flip first and then we'll try for
742
* blit.
743
*/
744
private BufferStrategy createBufferStrategy() {
745
Container root = getRoot();
746
if (root == null) {
747
return null;
748
}
749
BufferStrategy bs = null;
750
if (SwingUtilities3.isVsyncRequested(root)) {
751
bs = createBufferStrategy(root, true);
752
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
753
LOGGER.finer("createBufferStrategy: using vsynced strategy");
754
}
755
}
756
if (bs == null) {
757
bs = createBufferStrategy(root, false);
758
}
759
if (!(bs instanceof SubRegionShowable)) {
760
// We do this for two reasons:
761
// 1. So that we know we can cast to SubRegionShowable and
762
// invoke show with the minimal region to update
763
// 2. To avoid the possibility of invoking client code
764
// on the toolkit thread.
765
bs = null;
766
}
767
return bs;
768
}
769
770
// Creates and returns a buffer strategy. If
771
// there is a problem creating the buffer strategy this will
772
// eat the exception and return null.
773
private BufferStrategy createBufferStrategy(Container root,
774
boolean isVsynced) {
775
BufferCapabilities caps;
776
if (isVsynced) {
777
caps = new ExtendedBufferCapabilities(
778
new ImageCapabilities(true), new ImageCapabilities(true),
779
BufferCapabilities.FlipContents.COPIED,
780
ExtendedBufferCapabilities.VSyncType.VSYNC_ON);
781
} else {
782
caps = new BufferCapabilities(
783
new ImageCapabilities(true), new ImageCapabilities(true),
784
null);
785
}
786
BufferStrategy bs = null;
787
if (SunToolkit.isInstanceOf(root, "java.applet.Applet")) {
788
try {
789
AWTAccessor.ComponentAccessor componentAccessor
790
= AWTAccessor.getComponentAccessor();
791
componentAccessor.createBufferStrategy(root, 2, caps);
792
bs = componentAccessor.getBufferStrategy(root);
793
} catch (AWTException e) {
794
// Type is not supported
795
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
796
LOGGER.finer("createBufferStratety failed",
797
e);
798
}
799
}
800
}
801
else {
802
try {
803
((Window)root).createBufferStrategy(2, caps);
804
bs = ((Window)root).getBufferStrategy();
805
} catch (AWTException e) {
806
// Type not supported
807
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
808
LOGGER.finer("createBufferStratety failed",
809
e);
810
}
811
}
812
}
813
return bs;
814
}
815
816
/**
817
* Cleans up and removes any references.
818
*/
819
public void dispose() {
820
Container root = getRoot();
821
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
822
LOGGER.finer("disposed BufferInfo for: " + root);
823
}
824
if (root != null) {
825
root.removeComponentListener(this);
826
if (root instanceof Window) {
827
((Window)root).removeWindowListener(this);
828
}
829
BufferStrategy bs = getBufferStrategy(false);
830
if (bs != null) {
831
bs.dispose();
832
}
833
}
834
this.root = null;
835
weakBS = null;
836
}
837
838
// We mark the buffer as needing to be painted on a hide/iconify
839
// because the developer may have conditionalized painting based on
840
// visibility.
841
// Ideally we would also move to having the BufferStrategy being
842
// a SoftReference in Component here, but that requires changes to
843
// Component and the like.
844
public void componentHidden(ComponentEvent e) {
845
Container root = getRoot();
846
if (root != null && root.isVisible()) {
847
// This case will only happen if a developer calls
848
// hide immediately followed by show. In this case
849
// the event is delivered after show and the window
850
// will still be visible. If a developer altered the
851
// contents of the window between the hide/show
852
// invocations we won't recognize we need to paint and
853
// the contents would be bogus. Calling repaint here
854
// fixs everything up.
855
root.repaint();
856
}
857
else {
858
setPaintAllOnExpose(true);
859
}
860
}
861
862
public void windowIconified(WindowEvent e) {
863
setPaintAllOnExpose(true);
864
}
865
866
// On a dispose we chuck everything.
867
public void windowClosed(WindowEvent e) {
868
// Make sure we're not showing.
869
synchronized(BufferStrategyPaintManager.this) {
870
while (showing) {
871
try {
872
BufferStrategyPaintManager.this.wait();
873
} catch (InterruptedException ie) {
874
}
875
}
876
bufferInfos.remove(this);
877
}
878
dispose();
879
}
880
881
public void windowOpened(WindowEvent e) {
882
}
883
884
public void windowClosing(WindowEvent e) {
885
}
886
887
public void windowDeiconified(WindowEvent e) {
888
}
889
890
public void windowActivated(WindowEvent e) {
891
}
892
893
public void windowDeactivated(WindowEvent e) {
894
}
895
}
896
}
897
898