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