< prev index next >

src/java.desktop/share/classes/javax/swing/RepaintManager.java

Print this page




  36 import java.applet.*;
  37 
  38 import jdk.internal.misc.JavaSecurityAccess;
  39 import jdk.internal.misc.SharedSecrets;
  40 import sun.awt.AWTAccessor;
  41 import sun.awt.AppContext;
  42 import sun.awt.DisplayChangedListener;
  43 import sun.awt.SunToolkit;
  44 import sun.java2d.SunGraphicsEnvironment;
  45 import sun.security.action.GetPropertyAction;
  46 
  47 import com.sun.java.swing.SwingUtilities3;
  48 import sun.swing.SwingAccessor;
  49 import sun.swing.SwingUtilities2.RepaintListener;
  50 
  51 /**
  52  * This class manages repaint requests, allowing the number
  53  * of repaints to be minimized, for example by collapsing multiple
  54  * requests into a single repaint for members of a component tree.
  55  * <p>
  56  * As of 1.6 <code>RepaintManager</code> handles repaint requests
  57  * for Swing's top level components (<code>JApplet</code>,
  58  * <code>JWindow</code>, <code>JFrame</code> and <code>JDialog</code>).
  59  * Any calls to <code>repaint</code> on one of these will call into the
  60  * appropriate <code>addDirtyRegion</code> method.
  61  *
  62  * @author Arnaud Weber
  63  * @since 1.2
  64  */
  65 public class RepaintManager
  66 {
  67     /**
  68      * Whether or not the RepaintManager should handle paint requests
  69      * for top levels.
  70      */
  71     static final boolean HANDLE_TOP_LEVEL_PAINT;
  72 
  73     private static final short BUFFER_STRATEGY_NOT_SPECIFIED = 0;
  74     private static final short BUFFER_STRATEGY_SPECIFIED_ON = 1;
  75     private static final short BUFFER_STRATEGY_SPECIFIED_OFF = 2;
  76 
  77     private static final short BUFFER_STRATEGY_TYPE;
  78 
  79     /**
  80      * Maps from GraphicsConfiguration to VolatileImage.


 122 
 123     private static final Object repaintManagerKey = RepaintManager.class;
 124 
 125     // Whether or not a VolatileImage should be used for double-buffered painting
 126     static boolean volatileImageBufferEnabled = true;
 127     /**
 128      * Type of VolatileImage which should be used for double-buffered
 129      * painting.
 130      */
 131     private static final int volatileBufferType;
 132     /**
 133      * Value of the system property awt.nativeDoubleBuffering.
 134      */
 135     private static boolean nativeDoubleBuffering;
 136 
 137     // The maximum number of times Swing will attempt to use the VolatileImage
 138     // buffer during a paint operation.
 139     private static final int VOLATILE_LOOP_MAX = 2;
 140 
 141     /**
 142      * Number of <code>beginPaint</code> that have been invoked.
 143      */
 144     private int paintDepth = 0;
 145 
 146     /**
 147      * Type of buffer strategy to use.  Will be one of the BUFFER_STRATEGY_
 148      * constants.
 149      */
 150     private short bufferStrategyType;
 151 
 152     //
 153     // BufferStrategyPaintManager has the unique characteristic that it
 154     // must deal with the buffer being lost while painting to it.  For
 155     // example, if we paint a component and show it and the buffer has
 156     // become lost we must repaint the whole window.  To deal with that
 157     // the PaintManager calls into repaintRoot, and if we're still in
 158     // the process of painting the repaintRoot field is set to the JRootPane
 159     // and after the current JComponent.paintImmediately call finishes
 160     // paintImmediately will be invoked on the repaintRoot.  In this
 161     // way we don't try to show garbage to the screen.
 162     //
 163     /**
 164      * True if we're in the process of painting the dirty regions.  This is
 165      * set to true in <code>paintDirtyRegions</code>.
 166      */
 167     private boolean painting;
 168     /**
 169      * If the PaintManager calls into repaintRoot during painting this field
 170      * will be set to the root.
 171      */
 172     private JComponent repaintRoot;
 173 
 174     /**
 175      * The Thread that has initiated painting.  If null it
 176      * indicates painting is not currently in progress.
 177      */
 178     private Thread paintThread;
 179 
 180     /**
 181      * Runnable used to process all repaint/revalidate requests.
 182      */
 183     private final ProcessingRunnable processingRunnable;
 184 
 185     private static final JavaSecurityAccess javaSecurityAccess =


 475      * will be unioned with the region that should be redrawn.
 476      *
 477      * @param c Component to repaint, null results in nothing happening.
 478      * @param x X coordinate of the region to repaint
 479      * @param y Y coordinate of the region to repaint
 480      * @param w Width of the region to repaint
 481      * @param h Height of the region to repaint
 482      * @see JComponent#repaint
 483      */
 484     public void addDirtyRegion(JComponent c, int x, int y, int w, int h)
 485     {
 486         RepaintManager delegate = getDelegate(c);
 487         if (delegate != null) {
 488             delegate.addDirtyRegion(c, x, y, w, h);
 489             return;
 490         }
 491         addDirtyRegion0(c, x, y, w, h);
 492     }
 493 
 494     /**
 495      * Adds <code>window</code> to the list of <code>Component</code>s that
 496      * need to be repainted.
 497      *
 498      * @param window Window to repaint, null results in nothing happening.
 499      * @param x X coordinate of the region to repaint
 500      * @param y Y coordinate of the region to repaint
 501      * @param w Width of the region to repaint
 502      * @param h Height of the region to repaint
 503      * @see JFrame#repaint
 504      * @see JWindow#repaint
 505      * @see JDialog#repaint
 506      * @since 1.6
 507      */
 508     public void addDirtyRegion(Window window, int x, int y, int w, int h) {
 509         addDirtyRegion0(window, x, y, w, h);
 510     }
 511 
 512     /**
 513      * Adds <code>applet</code> to the list of <code>Component</code>s that
 514      * need to be repainted.
 515      *
 516      * @param applet Applet to repaint, null results in nothing happening.
 517      * @param x X coordinate of the region to repaint
 518      * @param y Y coordinate of the region to repaint
 519      * @param w Width of the region to repaint
 520      * @param h Height of the region to repaint
 521      * @see JApplet#repaint
 522      * @since 1.6
 523      */
 524     public void addDirtyRegion(Applet applet, int x, int y, int w, int h) {
 525         addDirtyRegion0(applet, x, y, w, h);
 526     }
 527 
 528     void scheduleHeavyWeightPaints() {
 529         Map<Container,Rectangle> hws;
 530 
 531         synchronized(this) {
 532             if (hwDirtyComponents.size() == 0) {
 533                 return;


 588                 public void run() {
 589                     AccessControlContext stack = AccessController.getContext();
 590                     AccessControlContext acc =
 591                         AWTAccessor.getComponentAccessor().getAccessControlContext(c);
 592                     javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Void>() {
 593                         public Void run() {
 594                             r.run();
 595                             return null;
 596                         }
 597                     }, stack, acc);
 598                 }
 599             });
 600         }
 601         scheduleProcessingRunnable(appContext);
 602     }
 603 
 604     /**
 605      * Extends the dirty region for the specified component to include
 606      * the new region.
 607      *
 608      * @return false if <code>c</code> is not yet marked dirty.
 609      */
 610     private synchronized boolean extendDirtyRegion(
 611         Component c, int x, int y, int w, int h) {
 612         Rectangle r = dirtyComponents.get(c);
 613         if (r != null) {
 614             // A non-null r implies c is already marked as dirty,
 615             // and that the parent is valid. Therefore we can
 616             // just union the rect and bail.
 617             SwingUtilities.computeUnion(x, y, w, h, r);
 618             return true;
 619         }
 620         return false;
 621     }
 622 
 623     /**
 624      * Return the current dirty region for a component.
 625      * Return an empty rectangle if the component is not
 626      * dirty.
 627      *
 628      * @param aComponent a component


 989             roots.add(rootDirtyComponent);
 990     }
 991 
 992 
 993     /**
 994      * Returns a string that displays and identifies this
 995      * object's properties.
 996      *
 997      * @return a String representation of this object
 998      */
 999     public synchronized String toString() {
1000         StringBuilder sb = new StringBuilder();
1001         if(dirtyComponents != null)
1002             sb.append("" + dirtyComponents);
1003         return sb.toString();
1004     }
1005 
1006 
1007     /**
1008      * Return the offscreen buffer that should be used as a double buffer with
1009      * the component <code>c</code>.
1010      * By default there is a double buffer per RepaintManager.
1011      * The buffer might be smaller than <code>(proposedWidth,proposedHeight)</code>
1012      * This happens when the maximum double buffer size as been set for the receiving
1013      * repaint manager.
1014      *
1015      * @param c the component
1016      * @param proposedWidth the width of the buffer
1017      * @param proposedHeight the height of the buffer
1018      *
1019      * @return the image
1020      */
1021     public Image getOffscreenBuffer(Component c,int proposedWidth,int proposedHeight) {
1022         RepaintManager delegate = getDelegate(c);
1023         if (delegate != null) {
1024             return delegate.getOffscreenBuffer(c, proposedWidth, proposedHeight);
1025         }
1026         return _getOffscreenBuffer(c, proposedWidth, proposedHeight);
1027     }
1028 
1029     /**
1030      * Return a volatile offscreen buffer that should be used as a
1031      * double buffer with the specified component <code>c</code>.
1032      * The image returned will be an instance of VolatileImage, or null
1033      * if a VolatileImage object could not be instantiated.
1034      * This buffer might be smaller than <code>(proposedWidth,proposedHeight)</code>.
1035      * This happens when the maximum double buffer size has been set for this
1036      * repaint manager.
1037      *
1038      * @param c the component
1039      * @param proposedWidth the width of the buffer
1040      * @param proposedHeight the height of the buffer
1041      *
1042      * @return the volatile image
1043      * @see java.awt.image.VolatileImage
1044      * @since 1.4
1045      */
1046     public Image getVolatileOffscreenBuffer(Component c,
1047                                             int proposedWidth,int proposedHeight) {
1048         RepaintManager delegate = getDelegate(c);
1049         if (delegate != null) {
1050             return delegate.getVolatileOffscreenBuffer(c, proposedWidth,
1051                                                         proposedHeight);
1052         }
1053 
1054         // If the window is non-opaque, it's double-buffered at peer's level


1203      * Enables or disables double buffering in this RepaintManager.
1204      * CAUTION: The default value for this property is set for optimal
1205      * paint performance on the given platform and it is not recommended
1206      * that programs modify this property directly.
1207      *
1208      * @param aFlag  true to activate double buffering
1209      * @see #isDoubleBufferingEnabled
1210      */
1211     public void setDoubleBufferingEnabled(boolean aFlag) {
1212         doubleBufferingEnabled = aFlag;
1213         PaintManager paintManager = getPaintManager();
1214         if (!aFlag && paintManager.getClass() != PaintManager.class) {
1215             setPaintManager(new PaintManager());
1216         }
1217     }
1218 
1219     /**
1220      * Returns true if this RepaintManager is double buffered.
1221      * The default value for this property may vary from platform
1222      * to platform.  On platforms where native double buffering
1223      * is supported in the AWT, the default value will be <code>false</code>
1224      * to avoid unnecessary buffering in Swing.
1225      * On platforms where native double buffering is not supported,
1226      * the default value will be <code>true</code>.
1227      *
1228      * @return true if this object is double buffered
1229      */
1230     public boolean isDoubleBufferingEnabled() {
1231         return doubleBufferingEnabled;
1232     }
1233 
1234     /**
1235      * This resets the double buffer. Actually, it marks the double buffer
1236      * as invalid, the double buffer will then be recreated on the next
1237      * invocation of getOffscreenBuffer.
1238      */
1239     void resetDoubleBuffer() {
1240         if (standardDoubleBuffer != null) {
1241             standardDoubleBuffer.needsReset = true;
1242         }
1243     }
1244 
1245     /**
1246      * This resets the volatile double buffer.
1247      */
1248     void resetVolatileDoubleBuffer(GraphicsConfiguration gc) {
1249         Image image = volatileMap.remove(gc);
1250         if (image != null) {
1251             image.flush();
1252         }
1253     }
1254 
1255     /**
1256      * Returns true if we should use the <code>Image</code> returned
1257      * from <code>getVolatileOffscreenBuffer</code> to do double buffering.
1258      */
1259     boolean useVolatileDoubleBuffer() {
1260         return volatileImageBufferEnabled;
1261     }
1262 
1263     /**
1264      * Returns true if the current thread is the thread painting.  This
1265      * will return false if no threads are painting.
1266      */
1267     private synchronized boolean isPaintingThread() {
1268         return (Thread.currentThread() == paintThread);
1269     }
1270     //
1271     // Paint methods.  You very, VERY rarely need to invoke these.
1272     // They are invoked directly from JComponent's painting code and
1273     // when painting happens outside the normal flow: DefaultDesktopManager
1274     // and JViewport.  If you end up needing these methods in other places be
1275     // careful that you don't get stuck in a paint loop.
1276     //
1277 


1329 
1330     /**
1331      * Notify the attached repaint listeners that an area of the {@code c} component
1332      * has been immediately repainted, that is without scheduling a repaint runnable,
1333      * due to performing a "blit" (via calling the {@code copyArea} method).
1334      *
1335      * @param c the component
1336      * @param x the x coordinate of the area
1337      * @param y the y coordinate of the area
1338      * @param w the width of the area
1339      * @param h the height of the area
1340      */
1341     void notifyRepaintPerformed(JComponent c, int x, int y, int w, int h) {
1342         for (RepaintListener l : repaintListeners) {
1343             l.repaintPerformed(c, x, y, w, h);
1344         }
1345     }
1346 
1347     /**
1348      * Invoked prior to any paint/copyArea method calls.  This will
1349      * be followed by an invocation of <code>endPaint</code>.
1350      * <b>WARNING</b>: Callers of this method need to wrap the call
1351      * in a <code>try/finally</code>, otherwise if an exception is thrown
1352      * during the course of painting the RepaintManager may
1353      * be left in a state in which the screen is not updated, eg:
1354      * <pre>
1355      * repaintManager.beginPaint();
1356      * try {
1357      *   repaintManager.paint(...);
1358      * } finally {
1359      *   repaintManager.endPaint();
1360      * }
1361      * </pre>
1362      */
1363     void beginPaint() {
1364         boolean multiThreadedPaint = false;
1365         int paintDepth;
1366         Thread currentThread = Thread.currentThread();
1367         synchronized(this) {
1368             paintDepth = this.paintDepth;
1369             if (paintThread == null || currentThread == paintThread) {
1370                 paintThread = currentThread;
1371                 this.paintDepth++;
1372             } else {
1373                 multiThreadedPaint = true;
1374             }
1375         }
1376         if (!multiThreadedPaint && paintDepth == 0) {
1377             getPaintManager().beginPaint();
1378         }
1379     }
1380 
1381     /**
1382      * Invoked after <code>beginPaint</code> has been invoked.
1383      */
1384     void endPaint() {
1385         if (isPaintingThread()) {
1386             PaintManager paintManager = null;
1387             synchronized(this) {
1388                 if (--paintDepth == 0) {
1389                     paintManager = getPaintManager();
1390                 }
1391             }
1392             if (paintManager != null) {
1393                 paintManager.endPaint();
1394                 synchronized(this) {
1395                     paintThread = null;
1396                 }
1397             }
1398         }
1399     }
1400 
1401     /**
1402      * If possible this will show a previously rendered portion of
1403      * a Component.  If successful, this will return true, otherwise false.
1404      * <p>
1405      * WARNING: This method is invoked from the native toolkit thread, be
1406      * very careful as to what methods this invokes!
1407      */
1408     boolean show(Container c, int x, int y, int w, int h) {
1409         return getPaintManager().show(c, x, y, w, h);
1410     }
1411 
1412     /**
1413      * Invoked when the doubleBuffered or useTrueDoubleBuffering
1414      * properties of a JRootPane change.  This may come in on any thread.
1415      */
1416     void doubleBufferingChanged(JRootPane rootPane) {
1417         getPaintManager().doubleBufferingChanged(rootPane);
1418     }
1419 
1420     /**
1421      * Sets the <code>PaintManager</code> that is used to handle all
1422      * double buffered painting.
1423      *
1424      * @param paintManager The PaintManager to use.  Passing in null indicates
1425      *        the fallback PaintManager should be used.
1426      */
1427     void setPaintManager(PaintManager paintManager) {
1428         if (paintManager == null) {
1429             paintManager = new PaintManager();
1430         }
1431         PaintManager oldPaintManager;
1432         synchronized(this) {
1433             oldPaintManager = this.paintManager;
1434             this.paintManager = paintManager;
1435             paintManager.repaintManager = this;
1436         }
1437         if (oldPaintManager != null) {
1438             oldPaintManager.dispose();
1439         }
1440     }
1441 


1468 
1469     private void scheduleProcessingRunnable(AppContext context) {
1470         if (processingRunnable.markPending()) {
1471             Toolkit tk = Toolkit.getDefaultToolkit();
1472             if (tk instanceof SunToolkit) {
1473                 SunToolkit.getSystemEventQueueImplPP(context).
1474                   postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
1475                                                 processingRunnable));
1476             } else {
1477                 Toolkit.getDefaultToolkit().getSystemEventQueue().
1478                       postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
1479                                                     processingRunnable));
1480             }
1481         }
1482     }
1483 
1484 
1485     /**
1486      * PaintManager is used to handle all double buffered painting for
1487      * Swing.  Subclasses should call back into the JComponent method
1488      * <code>paintToOffscreen</code> to handle the actual painting.
1489      */
1490     static class PaintManager {
1491         /**
1492          * RepaintManager the PaintManager has been installed on.
1493          */
1494         protected RepaintManager repaintManager;
1495         boolean isRepaintingRoot;
1496 
1497         /**
1498          * Paints a region of a component
1499          *
1500          * @param paintingComponent Component to paint
1501          * @param bufferComponent Component to obtain buffer for
1502          * @param g Graphics to paint to
1503          * @param x X-coordinate
1504          * @param y Y-coordinate
1505          * @param w Width
1506          * @param h Height
1507          * @return true if painting was successful.
1508          */


1610                         g.setClip(x, y, bw, bh);
1611                         if (volatileBufferType != Transparency.OPAQUE
1612                                 && g instanceof Graphics2D) {
1613                             final Graphics2D g2d = (Graphics2D) g;
1614                             final Composite oldComposite = g2d.getComposite();
1615                             g2d.setComposite(AlphaComposite.Src);
1616                             g2d.drawImage(image, x, y, c);
1617                             g2d.setComposite(oldComposite);
1618                         } else {
1619                             g.drawImage(image, x, y, c);
1620                         }
1621                         osg.translate(x, y);
1622                     }
1623                 }
1624             } finally {
1625                 osg.dispose();
1626             }
1627         }
1628 
1629         /**
1630          * If <code>image</code> is non-null with a positive size it
1631          * is returned, otherwise null is returned.
1632          */
1633         private Image getValidImage(Image image) {
1634             if (image != null && image.getWidth(null) > 0 &&
1635                                  image.getHeight(null) > 0) {
1636                 return image;
1637             }
1638             return null;
1639         }
1640 
1641         /**
1642          * Schedules a repaint for the specified component.  This differs
1643          * from <code>root.repaint</code> in that if the RepaintManager is
1644          * currently processing paint requests it'll process this request
1645          * with the current set of requests.
1646          */
1647         protected void repaintRoot(JComponent root) {
1648             assert (repaintManager.repaintRoot == null);
1649             if (repaintManager.painting) {
1650                 repaintManager.repaintRoot = root;
1651             }
1652             else {
1653                 root.repaint();
1654             }
1655         }
1656 
1657         /**
1658          * Returns true if the component being painted is the root component
1659          * that was previously passed to <code>repaintRoot</code>.
1660          */
1661         protected boolean isRepaintingRoot() {
1662             return isRepaintingRoot;
1663         }
1664 
1665         /**
1666          * Cleans up any state.  After invoked the PaintManager will no
1667          * longer be used anymore.
1668          */
1669         protected void dispose() {
1670         }
1671     }
1672 
1673 
1674     private class DoubleBufferInfo {
1675         public Image image;
1676         public Dimension size;
1677         public boolean needsReset = false;
1678     }
1679 




  36 import java.applet.*;
  37 
  38 import jdk.internal.misc.JavaSecurityAccess;
  39 import jdk.internal.misc.SharedSecrets;
  40 import sun.awt.AWTAccessor;
  41 import sun.awt.AppContext;
  42 import sun.awt.DisplayChangedListener;
  43 import sun.awt.SunToolkit;
  44 import sun.java2d.SunGraphicsEnvironment;
  45 import sun.security.action.GetPropertyAction;
  46 
  47 import com.sun.java.swing.SwingUtilities3;
  48 import sun.swing.SwingAccessor;
  49 import sun.swing.SwingUtilities2.RepaintListener;
  50 
  51 /**
  52  * This class manages repaint requests, allowing the number
  53  * of repaints to be minimized, for example by collapsing multiple
  54  * requests into a single repaint for members of a component tree.
  55  * <p>
  56  * As of 1.6 {@code RepaintManager} handles repaint requests
  57  * for Swing's top level components ({@code JApplet},
  58  * {@code JWindow}, {@code JFrame} and {@code JDialog}).
  59  * Any calls to {@code repaint} on one of these will call into the
  60  * appropriate {@code addDirtyRegion} method.
  61  *
  62  * @author Arnaud Weber
  63  * @since 1.2
  64  */
  65 public class RepaintManager
  66 {
  67     /**
  68      * Whether or not the RepaintManager should handle paint requests
  69      * for top levels.
  70      */
  71     static final boolean HANDLE_TOP_LEVEL_PAINT;
  72 
  73     private static final short BUFFER_STRATEGY_NOT_SPECIFIED = 0;
  74     private static final short BUFFER_STRATEGY_SPECIFIED_ON = 1;
  75     private static final short BUFFER_STRATEGY_SPECIFIED_OFF = 2;
  76 
  77     private static final short BUFFER_STRATEGY_TYPE;
  78 
  79     /**
  80      * Maps from GraphicsConfiguration to VolatileImage.


 122 
 123     private static final Object repaintManagerKey = RepaintManager.class;
 124 
 125     // Whether or not a VolatileImage should be used for double-buffered painting
 126     static boolean volatileImageBufferEnabled = true;
 127     /**
 128      * Type of VolatileImage which should be used for double-buffered
 129      * painting.
 130      */
 131     private static final int volatileBufferType;
 132     /**
 133      * Value of the system property awt.nativeDoubleBuffering.
 134      */
 135     private static boolean nativeDoubleBuffering;
 136 
 137     // The maximum number of times Swing will attempt to use the VolatileImage
 138     // buffer during a paint operation.
 139     private static final int VOLATILE_LOOP_MAX = 2;
 140 
 141     /**
 142      * Number of {@code beginPaint} that have been invoked.
 143      */
 144     private int paintDepth = 0;
 145 
 146     /**
 147      * Type of buffer strategy to use.  Will be one of the BUFFER_STRATEGY_
 148      * constants.
 149      */
 150     private short bufferStrategyType;
 151 
 152     //
 153     // BufferStrategyPaintManager has the unique characteristic that it
 154     // must deal with the buffer being lost while painting to it.  For
 155     // example, if we paint a component and show it and the buffer has
 156     // become lost we must repaint the whole window.  To deal with that
 157     // the PaintManager calls into repaintRoot, and if we're still in
 158     // the process of painting the repaintRoot field is set to the JRootPane
 159     // and after the current JComponent.paintImmediately call finishes
 160     // paintImmediately will be invoked on the repaintRoot.  In this
 161     // way we don't try to show garbage to the screen.
 162     //
 163     /**
 164      * True if we're in the process of painting the dirty regions.  This is
 165      * set to true in {@code paintDirtyRegions}.
 166      */
 167     private boolean painting;
 168     /**
 169      * If the PaintManager calls into repaintRoot during painting this field
 170      * will be set to the root.
 171      */
 172     private JComponent repaintRoot;
 173 
 174     /**
 175      * The Thread that has initiated painting.  If null it
 176      * indicates painting is not currently in progress.
 177      */
 178     private Thread paintThread;
 179 
 180     /**
 181      * Runnable used to process all repaint/revalidate requests.
 182      */
 183     private final ProcessingRunnable processingRunnable;
 184 
 185     private static final JavaSecurityAccess javaSecurityAccess =


 475      * will be unioned with the region that should be redrawn.
 476      *
 477      * @param c Component to repaint, null results in nothing happening.
 478      * @param x X coordinate of the region to repaint
 479      * @param y Y coordinate of the region to repaint
 480      * @param w Width of the region to repaint
 481      * @param h Height of the region to repaint
 482      * @see JComponent#repaint
 483      */
 484     public void addDirtyRegion(JComponent c, int x, int y, int w, int h)
 485     {
 486         RepaintManager delegate = getDelegate(c);
 487         if (delegate != null) {
 488             delegate.addDirtyRegion(c, x, y, w, h);
 489             return;
 490         }
 491         addDirtyRegion0(c, x, y, w, h);
 492     }
 493 
 494     /**
 495      * Adds {@code window} to the list of {@code Component}s that
 496      * need to be repainted.
 497      *
 498      * @param window Window to repaint, null results in nothing happening.
 499      * @param x X coordinate of the region to repaint
 500      * @param y Y coordinate of the region to repaint
 501      * @param w Width of the region to repaint
 502      * @param h Height of the region to repaint
 503      * @see JFrame#repaint
 504      * @see JWindow#repaint
 505      * @see JDialog#repaint
 506      * @since 1.6
 507      */
 508     public void addDirtyRegion(Window window, int x, int y, int w, int h) {
 509         addDirtyRegion0(window, x, y, w, h);
 510     }
 511 
 512     /**
 513      * Adds {@code applet} to the list of {@code Component}s that
 514      * need to be repainted.
 515      *
 516      * @param applet Applet to repaint, null results in nothing happening.
 517      * @param x X coordinate of the region to repaint
 518      * @param y Y coordinate of the region to repaint
 519      * @param w Width of the region to repaint
 520      * @param h Height of the region to repaint
 521      * @see JApplet#repaint
 522      * @since 1.6
 523      */
 524     public void addDirtyRegion(Applet applet, int x, int y, int w, int h) {
 525         addDirtyRegion0(applet, x, y, w, h);
 526     }
 527 
 528     void scheduleHeavyWeightPaints() {
 529         Map<Container,Rectangle> hws;
 530 
 531         synchronized(this) {
 532             if (hwDirtyComponents.size() == 0) {
 533                 return;


 588                 public void run() {
 589                     AccessControlContext stack = AccessController.getContext();
 590                     AccessControlContext acc =
 591                         AWTAccessor.getComponentAccessor().getAccessControlContext(c);
 592                     javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Void>() {
 593                         public Void run() {
 594                             r.run();
 595                             return null;
 596                         }
 597                     }, stack, acc);
 598                 }
 599             });
 600         }
 601         scheduleProcessingRunnable(appContext);
 602     }
 603 
 604     /**
 605      * Extends the dirty region for the specified component to include
 606      * the new region.
 607      *
 608      * @return false if {@code c} is not yet marked dirty.
 609      */
 610     private synchronized boolean extendDirtyRegion(
 611         Component c, int x, int y, int w, int h) {
 612         Rectangle r = dirtyComponents.get(c);
 613         if (r != null) {
 614             // A non-null r implies c is already marked as dirty,
 615             // and that the parent is valid. Therefore we can
 616             // just union the rect and bail.
 617             SwingUtilities.computeUnion(x, y, w, h, r);
 618             return true;
 619         }
 620         return false;
 621     }
 622 
 623     /**
 624      * Return the current dirty region for a component.
 625      * Return an empty rectangle if the component is not
 626      * dirty.
 627      *
 628      * @param aComponent a component


 989             roots.add(rootDirtyComponent);
 990     }
 991 
 992 
 993     /**
 994      * Returns a string that displays and identifies this
 995      * object's properties.
 996      *
 997      * @return a String representation of this object
 998      */
 999     public synchronized String toString() {
1000         StringBuilder sb = new StringBuilder();
1001         if(dirtyComponents != null)
1002             sb.append("" + dirtyComponents);
1003         return sb.toString();
1004     }
1005 
1006 
1007     /**
1008      * Return the offscreen buffer that should be used as a double buffer with
1009      * the component {@code c}.
1010      * By default there is a double buffer per RepaintManager.
1011      * The buffer might be smaller than {@code (proposedWidth,proposedHeight)}
1012      * This happens when the maximum double buffer size as been set for the receiving
1013      * repaint manager.
1014      *
1015      * @param c the component
1016      * @param proposedWidth the width of the buffer
1017      * @param proposedHeight the height of the buffer
1018      *
1019      * @return the image
1020      */
1021     public Image getOffscreenBuffer(Component c,int proposedWidth,int proposedHeight) {
1022         RepaintManager delegate = getDelegate(c);
1023         if (delegate != null) {
1024             return delegate.getOffscreenBuffer(c, proposedWidth, proposedHeight);
1025         }
1026         return _getOffscreenBuffer(c, proposedWidth, proposedHeight);
1027     }
1028 
1029     /**
1030      * Return a volatile offscreen buffer that should be used as a
1031      * double buffer with the specified component {@code c}.
1032      * The image returned will be an instance of VolatileImage, or null
1033      * if a VolatileImage object could not be instantiated.
1034      * This buffer might be smaller than {@code (proposedWidth,proposedHeight)}.
1035      * This happens when the maximum double buffer size has been set for this
1036      * repaint manager.
1037      *
1038      * @param c the component
1039      * @param proposedWidth the width of the buffer
1040      * @param proposedHeight the height of the buffer
1041      *
1042      * @return the volatile image
1043      * @see java.awt.image.VolatileImage
1044      * @since 1.4
1045      */
1046     public Image getVolatileOffscreenBuffer(Component c,
1047                                             int proposedWidth,int proposedHeight) {
1048         RepaintManager delegate = getDelegate(c);
1049         if (delegate != null) {
1050             return delegate.getVolatileOffscreenBuffer(c, proposedWidth,
1051                                                         proposedHeight);
1052         }
1053 
1054         // If the window is non-opaque, it's double-buffered at peer's level


1203      * Enables or disables double buffering in this RepaintManager.
1204      * CAUTION: The default value for this property is set for optimal
1205      * paint performance on the given platform and it is not recommended
1206      * that programs modify this property directly.
1207      *
1208      * @param aFlag  true to activate double buffering
1209      * @see #isDoubleBufferingEnabled
1210      */
1211     public void setDoubleBufferingEnabled(boolean aFlag) {
1212         doubleBufferingEnabled = aFlag;
1213         PaintManager paintManager = getPaintManager();
1214         if (!aFlag && paintManager.getClass() != PaintManager.class) {
1215             setPaintManager(new PaintManager());
1216         }
1217     }
1218 
1219     /**
1220      * Returns true if this RepaintManager is double buffered.
1221      * The default value for this property may vary from platform
1222      * to platform.  On platforms where native double buffering
1223      * is supported in the AWT, the default value will be {@code false}
1224      * to avoid unnecessary buffering in Swing.
1225      * On platforms where native double buffering is not supported,
1226      * the default value will be {@code true}.
1227      *
1228      * @return true if this object is double buffered
1229      */
1230     public boolean isDoubleBufferingEnabled() {
1231         return doubleBufferingEnabled;
1232     }
1233 
1234     /**
1235      * This resets the double buffer. Actually, it marks the double buffer
1236      * as invalid, the double buffer will then be recreated on the next
1237      * invocation of getOffscreenBuffer.
1238      */
1239     void resetDoubleBuffer() {
1240         if (standardDoubleBuffer != null) {
1241             standardDoubleBuffer.needsReset = true;
1242         }
1243     }
1244 
1245     /**
1246      * This resets the volatile double buffer.
1247      */
1248     void resetVolatileDoubleBuffer(GraphicsConfiguration gc) {
1249         Image image = volatileMap.remove(gc);
1250         if (image != null) {
1251             image.flush();
1252         }
1253     }
1254 
1255     /**
1256      * Returns true if we should use the {@code Image} returned
1257      * from {@code getVolatileOffscreenBuffer} to do double buffering.
1258      */
1259     boolean useVolatileDoubleBuffer() {
1260         return volatileImageBufferEnabled;
1261     }
1262 
1263     /**
1264      * Returns true if the current thread is the thread painting.  This
1265      * will return false if no threads are painting.
1266      */
1267     private synchronized boolean isPaintingThread() {
1268         return (Thread.currentThread() == paintThread);
1269     }
1270     //
1271     // Paint methods.  You very, VERY rarely need to invoke these.
1272     // They are invoked directly from JComponent's painting code and
1273     // when painting happens outside the normal flow: DefaultDesktopManager
1274     // and JViewport.  If you end up needing these methods in other places be
1275     // careful that you don't get stuck in a paint loop.
1276     //
1277 


1329 
1330     /**
1331      * Notify the attached repaint listeners that an area of the {@code c} component
1332      * has been immediately repainted, that is without scheduling a repaint runnable,
1333      * due to performing a "blit" (via calling the {@code copyArea} method).
1334      *
1335      * @param c the component
1336      * @param x the x coordinate of the area
1337      * @param y the y coordinate of the area
1338      * @param w the width of the area
1339      * @param h the height of the area
1340      */
1341     void notifyRepaintPerformed(JComponent c, int x, int y, int w, int h) {
1342         for (RepaintListener l : repaintListeners) {
1343             l.repaintPerformed(c, x, y, w, h);
1344         }
1345     }
1346 
1347     /**
1348      * Invoked prior to any paint/copyArea method calls.  This will
1349      * be followed by an invocation of {@code endPaint}.
1350      * <b>WARNING</b>: Callers of this method need to wrap the call
1351      * in a {@code try/finally}, otherwise if an exception is thrown
1352      * during the course of painting the RepaintManager may
1353      * be left in a state in which the screen is not updated, eg:
1354      * <pre>
1355      * repaintManager.beginPaint();
1356      * try {
1357      *   repaintManager.paint(...);
1358      * } finally {
1359      *   repaintManager.endPaint();
1360      * }
1361      * </pre>
1362      */
1363     void beginPaint() {
1364         boolean multiThreadedPaint = false;
1365         int paintDepth;
1366         Thread currentThread = Thread.currentThread();
1367         synchronized(this) {
1368             paintDepth = this.paintDepth;
1369             if (paintThread == null || currentThread == paintThread) {
1370                 paintThread = currentThread;
1371                 this.paintDepth++;
1372             } else {
1373                 multiThreadedPaint = true;
1374             }
1375         }
1376         if (!multiThreadedPaint && paintDepth == 0) {
1377             getPaintManager().beginPaint();
1378         }
1379     }
1380 
1381     /**
1382      * Invoked after {@code beginPaint} has been invoked.
1383      */
1384     void endPaint() {
1385         if (isPaintingThread()) {
1386             PaintManager paintManager = null;
1387             synchronized(this) {
1388                 if (--paintDepth == 0) {
1389                     paintManager = getPaintManager();
1390                 }
1391             }
1392             if (paintManager != null) {
1393                 paintManager.endPaint();
1394                 synchronized(this) {
1395                     paintThread = null;
1396                 }
1397             }
1398         }
1399     }
1400 
1401     /**
1402      * If possible this will show a previously rendered portion of
1403      * a Component.  If successful, this will return true, otherwise false.
1404      * <p>
1405      * WARNING: This method is invoked from the native toolkit thread, be
1406      * very careful as to what methods this invokes!
1407      */
1408     boolean show(Container c, int x, int y, int w, int h) {
1409         return getPaintManager().show(c, x, y, w, h);
1410     }
1411 
1412     /**
1413      * Invoked when the doubleBuffered or useTrueDoubleBuffering
1414      * properties of a JRootPane change.  This may come in on any thread.
1415      */
1416     void doubleBufferingChanged(JRootPane rootPane) {
1417         getPaintManager().doubleBufferingChanged(rootPane);
1418     }
1419 
1420     /**
1421      * Sets the {@code PaintManager} that is used to handle all
1422      * double buffered painting.
1423      *
1424      * @param paintManager The PaintManager to use.  Passing in null indicates
1425      *        the fallback PaintManager should be used.
1426      */
1427     void setPaintManager(PaintManager paintManager) {
1428         if (paintManager == null) {
1429             paintManager = new PaintManager();
1430         }
1431         PaintManager oldPaintManager;
1432         synchronized(this) {
1433             oldPaintManager = this.paintManager;
1434             this.paintManager = paintManager;
1435             paintManager.repaintManager = this;
1436         }
1437         if (oldPaintManager != null) {
1438             oldPaintManager.dispose();
1439         }
1440     }
1441 


1468 
1469     private void scheduleProcessingRunnable(AppContext context) {
1470         if (processingRunnable.markPending()) {
1471             Toolkit tk = Toolkit.getDefaultToolkit();
1472             if (tk instanceof SunToolkit) {
1473                 SunToolkit.getSystemEventQueueImplPP(context).
1474                   postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
1475                                                 processingRunnable));
1476             } else {
1477                 Toolkit.getDefaultToolkit().getSystemEventQueue().
1478                       postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
1479                                                     processingRunnable));
1480             }
1481         }
1482     }
1483 
1484 
1485     /**
1486      * PaintManager is used to handle all double buffered painting for
1487      * Swing.  Subclasses should call back into the JComponent method
1488      * {@code paintToOffscreen} to handle the actual painting.
1489      */
1490     static class PaintManager {
1491         /**
1492          * RepaintManager the PaintManager has been installed on.
1493          */
1494         protected RepaintManager repaintManager;
1495         boolean isRepaintingRoot;
1496 
1497         /**
1498          * Paints a region of a component
1499          *
1500          * @param paintingComponent Component to paint
1501          * @param bufferComponent Component to obtain buffer for
1502          * @param g Graphics to paint to
1503          * @param x X-coordinate
1504          * @param y Y-coordinate
1505          * @param w Width
1506          * @param h Height
1507          * @return true if painting was successful.
1508          */


1610                         g.setClip(x, y, bw, bh);
1611                         if (volatileBufferType != Transparency.OPAQUE
1612                                 && g instanceof Graphics2D) {
1613                             final Graphics2D g2d = (Graphics2D) g;
1614                             final Composite oldComposite = g2d.getComposite();
1615                             g2d.setComposite(AlphaComposite.Src);
1616                             g2d.drawImage(image, x, y, c);
1617                             g2d.setComposite(oldComposite);
1618                         } else {
1619                             g.drawImage(image, x, y, c);
1620                         }
1621                         osg.translate(x, y);
1622                     }
1623                 }
1624             } finally {
1625                 osg.dispose();
1626             }
1627         }
1628 
1629         /**
1630          * If {@code image} is non-null with a positive size it
1631          * is returned, otherwise null is returned.
1632          */
1633         private Image getValidImage(Image image) {
1634             if (image != null && image.getWidth(null) > 0 &&
1635                                  image.getHeight(null) > 0) {
1636                 return image;
1637             }
1638             return null;
1639         }
1640 
1641         /**
1642          * Schedules a repaint for the specified component.  This differs
1643          * from {@code root.repaint} in that if the RepaintManager is
1644          * currently processing paint requests it'll process this request
1645          * with the current set of requests.
1646          */
1647         protected void repaintRoot(JComponent root) {
1648             assert (repaintManager.repaintRoot == null);
1649             if (repaintManager.painting) {
1650                 repaintManager.repaintRoot = root;
1651             }
1652             else {
1653                 root.repaint();
1654             }
1655         }
1656 
1657         /**
1658          * Returns true if the component being painted is the root component
1659          * that was previously passed to {@code repaintRoot}.
1660          */
1661         protected boolean isRepaintingRoot() {
1662             return isRepaintingRoot;
1663         }
1664 
1665         /**
1666          * Cleans up any state.  After invoked the PaintManager will no
1667          * longer be used anymore.
1668          */
1669         protected void dispose() {
1670         }
1671     }
1672 
1673 
1674     private class DoubleBufferInfo {
1675         public Image image;
1676         public Dimension size;
1677         public boolean needsReset = false;
1678     }
1679 


< prev index next >