Source Code Cross Referenced for RepaintManager.java in  » 6.0-JDK-Core » swing » javax » swing » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        package javax.swing;
0026
0027        import java.awt.*;
0028        import java.awt.event.*;
0029        import java.awt.peer.ComponentPeer;
0030        import java.awt.peer.ContainerPeer;
0031        import java.awt.image.VolatileImage;
0032        import java.security.AccessController;
0033        import java.util.*;
0034        import java.applet.*;
0035
0036        import sun.awt.AppContext;
0037        import sun.awt.DisplayChangedListener;
0038        import sun.awt.SunToolkit;
0039        import sun.java2d.SunGraphicsEnvironment;
0040        import sun.security.action.GetPropertyAction;
0041
0042        /**
0043         * This class manages repaint requests, allowing the number
0044         * of repaints to be minimized, for example by collapsing multiple 
0045         * requests into a single repaint for members of a component tree.
0046         * <p>
0047         * As of 1.6 <code>RepaintManager</code> handles repaint requests
0048         * for Swing's top level components (<code>JApplet</code>,
0049         * <code>JWindow</code>, <code>JFrame</code> and <code>JDialog</code>). 
0050         * Any calls to <code>repaint</code> on one of these will call into the
0051         * appropriate <code>addDirtyRegion</code> method.
0052         *
0053         * @version 1.76 05/09/07
0054         * @author Arnaud Weber
0055         */
0056        public class RepaintManager {
0057            /**
0058             * Whether or not the RepaintManager should handle paint requests
0059             * for top levels.
0060             */
0061            static final boolean HANDLE_TOP_LEVEL_PAINT;
0062
0063            private static final short BUFFER_STRATEGY_NOT_SPECIFIED = 0;
0064            private static final short BUFFER_STRATEGY_SPECIFIED_ON = 1;
0065            private static final short BUFFER_STRATEGY_SPECIFIED_OFF = 2;
0066
0067            private static final short BUFFER_STRATEGY_TYPE;
0068
0069            /**
0070             * Maps from GraphicsConfiguration to VolatileImage.
0071             */
0072            private Map<GraphicsConfiguration, VolatileImage> volatileMap = new HashMap<GraphicsConfiguration, VolatileImage>(
0073                    1);
0074
0075            //
0076            // As of 1.6 Swing handles scheduling of paint events from native code.
0077            // That is, SwingPaintEventDispatcher is invoked on the toolkit thread,
0078            // which in turn invokes nativeAddDirtyRegion.  Because this is invoked
0079            // from the native thread we can not invoke any public methods and so
0080            // we introduce these added maps.  So, any time nativeAddDirtyRegion is
0081            // invoked the region is added to hwDirtyComponents and a work request
0082            // is scheduled.  When the work request is processed all entries in
0083            // this map are pushed to the real map (dirtyComponents) and then
0084            // painted with the rest of the components.
0085            //
0086            private Map<Container, Rectangle> hwDirtyComponents;
0087
0088            private Map<Component, Rectangle> dirtyComponents;
0089            private Map<Component, Rectangle> tmpDirtyComponents;
0090            private java.util.List<Component> invalidComponents;
0091
0092            // List of Runnables that need to be processed before painting from AWT.
0093            private java.util.List<Runnable> runnableList;
0094
0095            boolean doubleBufferingEnabled = true;
0096
0097            private Dimension doubleBufferMaxSize;
0098
0099            // Support for both the standard and volatile offscreen buffers exists to
0100            // provide backwards compatibility for the [rare] programs which may be
0101            // calling getOffScreenBuffer() and not expecting to get a VolatileImage.
0102            // Swing internally is migrating to use *only* the volatile image buffer.
0103
0104            // Support for standard offscreen buffer
0105            //
0106            DoubleBufferInfo standardDoubleBuffer;
0107
0108            /**
0109             * Object responsible for hanlding core paint functionality.
0110             */
0111            private PaintManager paintManager;
0112
0113            private static final Object repaintManagerKey = RepaintManager.class;
0114
0115            // Whether or not a VolatileImage should be used for double-buffered painting
0116            static boolean volatileImageBufferEnabled = true;
0117            /**
0118             * Value of the system property awt.nativeDoubleBuffering.
0119             */
0120            private static boolean nativeDoubleBuffering;
0121
0122            // The maximum number of times Swing will attempt to use the VolatileImage
0123            // buffer during a paint operation.
0124            private static final int VOLATILE_LOOP_MAX = 2;
0125
0126            /**
0127             * Number of <code>beginPaint</code> that have been invoked.
0128             */
0129            private int paintDepth = 0;
0130
0131            /**
0132             * Type of buffer strategy to use.  Will be one of the BUFFER_STRATEGY_
0133             * constants.
0134             */
0135            private short bufferStrategyType;
0136
0137            //
0138            // BufferStrategyPaintManager has the unique characteristic that it
0139            // must deal with the buffer being lost while painting to it.  For 
0140            // example, if we paint a component and show it and the buffer has
0141            // become lost we must repaint the whole window.  To deal with that
0142            // the PaintManager calls into repaintRoot, and if we're still in
0143            // the process of painting the repaintRoot field is set to the JRootPane
0144            // and after the current JComponent.paintImmediately call finishes
0145            // paintImmediately will be invoked on the repaintRoot.  In this
0146            // way we don't try to show garbage to the screen.
0147            // 
0148            /**
0149             * True if we're in the process of painting the dirty regions.  This is
0150             * set to true in <code>paintDirtyRegions</code>.
0151             */
0152            private boolean painting;
0153            /**
0154             * If the PaintManager calls into repaintRoot during painting this field
0155             * will be set to the root.
0156             */
0157            private JComponent repaintRoot;
0158
0159            /**
0160             * The Thread that has initiated painting.  If null it
0161             * indicates painting is not currently in progress.
0162             */
0163            private Thread paintThread;
0164
0165            /**
0166             * Runnable used to process all repaint/revalidate requests.
0167             */
0168            private final ProcessingRunnable processingRunnable;
0169
0170            static {
0171                volatileImageBufferEnabled = "true".equals(AccessController
0172                        .doPrivileged(new GetPropertyAction(
0173                                "swing.volatileImageBufferEnabled", "true")));
0174                boolean headless = GraphicsEnvironment.isHeadless();
0175                if (volatileImageBufferEnabled && headless) {
0176                    volatileImageBufferEnabled = false;
0177                }
0178                nativeDoubleBuffering = "true".equals(AccessController
0179                        .doPrivileged(new GetPropertyAction(
0180                                "awt.nativeDoubleBuffering")));
0181                String bs = AccessController
0182                        .doPrivileged(new GetPropertyAction(
0183                                "swing.bufferPerWindow"));
0184                if (headless) {
0185                    BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_SPECIFIED_OFF;
0186                } else if (bs == null) {
0187                    BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_NOT_SPECIFIED;
0188                } else if ("true".equals(bs)) {
0189                    BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_SPECIFIED_ON;
0190                } else {
0191                    BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_SPECIFIED_OFF;
0192                }
0193                HANDLE_TOP_LEVEL_PAINT = "true".equals(AccessController
0194                        .doPrivileged(new GetPropertyAction(
0195                                "swing.handleTopLevelPaint", "true")));
0196                GraphicsEnvironment ge = GraphicsEnvironment
0197                        .getLocalGraphicsEnvironment();
0198                if (ge instanceof  SunGraphicsEnvironment) {
0199                    ((SunGraphicsEnvironment) ge)
0200                            .addDisplayChangedListener(new DisplayChangedHandler());
0201                }
0202            }
0203
0204            /** 
0205             * Return the RepaintManager for the calling thread given a Component.
0206             * 
0207             * @param c a Component -- unused in the default implementation, but could
0208             *          be used by an overridden version to return a different RepaintManager
0209             *          depending on the Component
0210             * @return the RepaintManager object
0211             */
0212            public static RepaintManager currentManager(Component c) {
0213                // Note: DisplayChangedRunnable passes in null as the component, so if
0214                // component is ever used to determine the current
0215                // RepaintManager, DisplayChangedRunnable will need to be modified
0216                // accordingly.
0217                return currentManager(AppContext.getAppContext());
0218            }
0219
0220            /**
0221             * Returns the RepaintManager for the specified AppContext.  If
0222             * a RepaintManager has not been created for the specified
0223             * AppContext this will return null.
0224             */
0225            static RepaintManager currentManager(AppContext appContext) {
0226                RepaintManager rm = (RepaintManager) appContext
0227                        .get(repaintManagerKey);
0228                if (rm == null) {
0229                    rm = new RepaintManager(BUFFER_STRATEGY_TYPE);
0230                    appContext.put(repaintManagerKey, rm);
0231                }
0232                return rm;
0233            }
0234
0235            /**
0236             * Return the RepaintManager for the calling thread given a JComponent.
0237             * <p>
0238             * Note: This method exists for backward binary compatibility with earlier
0239             * versions of the Swing library. It simply returns the result returned by
0240             * {@link #currentManager(Component)}. 
0241             *
0242             * @param c a JComponent -- unused
0243             * @return the RepaintManager object
0244             */
0245            public static RepaintManager currentManager(JComponent c) {
0246                return currentManager((Component) c);
0247            }
0248
0249            /**
0250             * Set the RepaintManager that should be used for the calling 
0251             * thread. <b>aRepaintManager</b> will become the current RepaintManager
0252             * for the calling thread's thread group.
0253             * @param aRepaintManager  the RepaintManager object to use
0254             */
0255            public static void setCurrentManager(RepaintManager aRepaintManager) {
0256                if (aRepaintManager != null) {
0257                    SwingUtilities.appContextPut(repaintManagerKey,
0258                            aRepaintManager);
0259                } else {
0260                    SwingUtilities.appContextRemove(repaintManagerKey);
0261                }
0262            }
0263
0264            /** 
0265             * Create a new RepaintManager instance. You rarely call this constructor.
0266             * directly. To get the default RepaintManager, use 
0267             * RepaintManager.currentManager(JComponent) (normally "this").
0268             */
0269            public RepaintManager() {
0270                // Because we can't know what a subclass is doing with the
0271                // volatile image we immediately punt in subclasses.  If this
0272                // poses a problem we'll need a more sophisticated detection algorithm,
0273                // or API.
0274                this (BUFFER_STRATEGY_SPECIFIED_OFF);
0275            }
0276
0277            private RepaintManager(short bufferStrategyType) {
0278                // If native doublebuffering is being used, do NOT use
0279                // Swing doublebuffering.
0280                doubleBufferingEnabled = !nativeDoubleBuffering;
0281                synchronized (this ) {
0282                    dirtyComponents = new IdentityHashMap<Component, Rectangle>();
0283                    tmpDirtyComponents = new IdentityHashMap<Component, Rectangle>();
0284                    this .bufferStrategyType = bufferStrategyType;
0285                    hwDirtyComponents = new IdentityHashMap<Container, Rectangle>();
0286                }
0287                processingRunnable = new ProcessingRunnable();
0288            }
0289
0290            private void displayChanged() {
0291                clearImages();
0292            }
0293
0294            /**
0295             * Mark the component as in need of layout and queue a runnable
0296             * for the event dispatching thread that will validate the components
0297             * first isValidateRoot() ancestor. 
0298             * 
0299             * @see JComponent#isValidateRoot
0300             * @see #removeInvalidComponent
0301             */
0302            public synchronized void addInvalidComponent(
0303                    JComponent invalidComponent) {
0304                Component validateRoot = null;
0305
0306                /* Find the first JComponent ancestor of this component whose
0307                 * isValidateRoot() method returns true.  
0308                 */
0309                for (Component c = invalidComponent; c != null; c = c
0310                        .getParent()) {
0311                    if ((c instanceof  CellRendererPane)
0312                            || (c.getPeer() == null)) {
0313                        return;
0314                    }
0315                    if ((c instanceof  JComponent)
0316                            && (((JComponent) c).isValidateRoot())) {
0317                        validateRoot = c;
0318                        break;
0319                    }
0320                }
0321
0322                /* There's no validateRoot to apply validate to, so we're done.
0323                 */
0324                if (validateRoot == null) {
0325                    return;
0326                }
0327
0328                /* If the validateRoot and all of its ancestors aren't visible
0329                 * then we don't do anything.  While we're walking up the tree
0330                 * we find the root Window or Applet.
0331                 */
0332                Component root = null;
0333
0334                for (Component c = validateRoot; c != null; c = c.getParent()) {
0335                    if (!c.isVisible() || (c.getPeer() == null)) {
0336                        return;
0337                    }
0338                    if ((c instanceof  Window) || (c instanceof  Applet)) {
0339                        root = c;
0340                        break;
0341                    }
0342                }
0343
0344                if (root == null) {
0345                    return;
0346                }
0347
0348                /* Lazily create the invalidateComponents vector and add the
0349                 * validateRoot if it's not there already.  If this validateRoot
0350                 * is already in the vector, we're done.
0351                 */
0352                if (invalidComponents == null) {
0353                    invalidComponents = new ArrayList<Component>();
0354                } else {
0355                    int n = invalidComponents.size();
0356                    for (int i = 0; i < n; i++) {
0357                        if (validateRoot == invalidComponents.get(i)) {
0358                            return;
0359                        }
0360                    }
0361                }
0362                invalidComponents.add(validateRoot);
0363
0364                // Queue a Runnable to invoke paintDirtyRegions and
0365                // validateInvalidComponents.
0366                scheduleProcessingRunnable();
0367            }
0368
0369            /** 
0370             * Remove a component from the list of invalid components.
0371             * 
0372             * @see #addInvalidComponent
0373             */
0374            public synchronized void removeInvalidComponent(JComponent component) {
0375                if (invalidComponents != null) {
0376                    int index = invalidComponents.indexOf(component);
0377                    if (index != -1) {
0378                        invalidComponents.remove(index);
0379                    }
0380                }
0381            }
0382
0383            /** 
0384             * Add a component in the list of components that should be refreshed.
0385             * If <i>c</i> already has a dirty region, the rectangle <i>(x,y,w,h)</i> 
0386             * will be unioned with the region that should be redrawn. 
0387             * 
0388             * @see JComponent#repaint
0389             */
0390            private void addDirtyRegion0(Container c, int x, int y, int w, int h) {
0391                /* Special cases we don't have to bother with.
0392                 */
0393                if ((w <= 0) || (h <= 0) || (c == null)) {
0394                    return;
0395                }
0396
0397                if ((c.getWidth() <= 0) || (c.getHeight() <= 0)) {
0398                    return;
0399                }
0400
0401                if (extendDirtyRegion(c, x, y, w, h)) {
0402                    // Component was already marked as dirty, region has been
0403                    // extended, no need to continue.
0404                    return;
0405                }
0406
0407                /* Make sure that c and all it ancestors (up to an Applet or
0408                 * Window) are visible.  This loop has the same effect as 
0409                 * checking c.isShowing() (and note that it's still possible 
0410                 * that c is completely obscured by an opaque ancestor in 
0411                 * the specified rectangle).
0412                 */
0413                Component root = null;
0414
0415                // Note: We can't synchronize around this, Frame.getExtendedState
0416                // is synchronized so that if we were to synchronize around this
0417                // it could lead to the possibility of getting locks out
0418                // of order and deadlocking.
0419                for (Container p = c; p != null; p = p.getParent()) {
0420                    if (!p.isVisible() || (p.getPeer() == null)) {
0421                        return;
0422                    }
0423                    if ((p instanceof  Window) || (p instanceof  Applet)) {
0424                        // Iconified frames are still visible!
0425                        if (p instanceof  Frame
0426                                && (((Frame) p).getExtendedState() & Frame.ICONIFIED) == Frame.ICONIFIED) {
0427                            return;
0428                        }
0429                        root = p;
0430                        break;
0431                    }
0432                }
0433
0434                if (root == null)
0435                    return;
0436
0437                synchronized (this ) {
0438                    if (extendDirtyRegion(c, x, y, w, h)) {
0439                        // In between last check and this check another thread
0440                        // queued up runnable, can bail here.
0441                        return;
0442                    }
0443                    dirtyComponents.put(c, new Rectangle(x, y, w, h));
0444                }
0445
0446                // Queue a Runnable to invoke paintDirtyRegions and
0447                // validateInvalidComponents.
0448                scheduleProcessingRunnable();
0449            }
0450
0451            /** 
0452             * Add a component in the list of components that should be refreshed.
0453             * If <i>c</i> already has a dirty region, the rectangle <i>(x,y,w,h)</i> 
0454             * will be unioned with the region that should be redrawn. 
0455             * 
0456             * @param c Component to repaint, null results in nothing happening.
0457             * @param x X coordinate of the region to repaint
0458             * @param y Y coordinate of the region to repaint
0459             * @param w Width of the region to repaint
0460             * @param h Height of the region to repaint
0461             * @see JComponent#repaint
0462             */
0463            public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
0464                addDirtyRegion0(c, x, y, w, h);
0465            }
0466
0467            /** 
0468             * Adds <code>window</code> to the list of <code>Component</code>s that
0469             * need to be repainted.
0470             * 
0471             * @param window Window to repaint, null results in nothing happening.
0472             * @param x X coordinate of the region to repaint
0473             * @param y Y coordinate of the region to repaint
0474             * @param w Width of the region to repaint
0475             * @param h Height of the region to repaint
0476             * @see JFrame#repaint
0477             * @see JWindow#repaint
0478             * @see JDialog#repaint
0479             * @since 1.6
0480             */
0481            public void addDirtyRegion(Window window, int x, int y, int w, int h) {
0482                addDirtyRegion0(window, x, y, w, h);
0483            }
0484
0485            /** 
0486             * Adds <code>applet</code> to the list of <code>Component</code>s that
0487             * need to be repainted.
0488             * 
0489             * @param applet Applet to repaint, null results in nothing happening.
0490             * @param x X coordinate of the region to repaint
0491             * @param y Y coordinate of the region to repaint
0492             * @param w Width of the region to repaint
0493             * @param h Height of the region to repaint
0494             * @see JApplet#repaint
0495             * @since 1.6
0496             */
0497            public void addDirtyRegion(Applet applet, int x, int y, int w, int h) {
0498                addDirtyRegion0(applet, x, y, w, h);
0499            }
0500
0501            void scheduleHeavyWeightPaints() {
0502                Map<Container, Rectangle> hws;
0503
0504                synchronized (this ) {
0505                    if (hwDirtyComponents.size() == 0) {
0506                        return;
0507                    }
0508                    hws = hwDirtyComponents;
0509                    hwDirtyComponents = new IdentityHashMap<Container, Rectangle>();
0510                }
0511                for (Container hw : hws.keySet()) {
0512                    Rectangle dirty = hws.get(hw);
0513                    if (hw instanceof  Window) {
0514                        addDirtyRegion((Window) hw, dirty.x, dirty.y,
0515                                dirty.width, dirty.height);
0516                    } else if (hw instanceof  Applet) {
0517                        addDirtyRegion((Applet) hw, dirty.x, dirty.y,
0518                                dirty.width, dirty.height);
0519                    } else { // SwingHeavyWeight
0520                        addDirtyRegion0(hw, dirty.x, dirty.y, dirty.width,
0521                                dirty.height);
0522                    }
0523                }
0524            }
0525
0526            //
0527            // This is called from the toolkit thread when a native expose is
0528            // received.
0529            // 
0530            void nativeAddDirtyRegion(AppContext appContext, Container c,
0531                    int x, int y, int w, int h) {
0532                if (w > 0 && h > 0) {
0533                    synchronized (this ) {
0534                        Rectangle dirty = hwDirtyComponents.get(c);
0535                        if (dirty == null) {
0536                            hwDirtyComponents.put(c, new Rectangle(x, y, w, h));
0537                        } else {
0538                            hwDirtyComponents.put(c, SwingUtilities
0539                                    .computeUnion(x, y, w, h, dirty));
0540                        }
0541                    }
0542                    scheduleProcessingRunnable(appContext);
0543                }
0544            }
0545
0546            //
0547            // This is called from the toolkit thread when awt needs to run a
0548            // Runnable before we paint.
0549            // 
0550            void nativeQueueSurfaceDataRunnable(AppContext appContext,
0551                    Component c, Runnable r) {
0552                synchronized (this ) {
0553                    if (runnableList == null) {
0554                        runnableList = new LinkedList<Runnable>();
0555                    }
0556                    runnableList.add(r);
0557                }
0558                scheduleProcessingRunnable(appContext);
0559            }
0560
0561            /**
0562             * Extends the dirty region for the specified component to include
0563             * the new region.
0564             *
0565             * @return false if <code>c</code> is not yet marked dirty.
0566             */
0567            private synchronized boolean extendDirtyRegion(Component c, int x,
0568                    int y, int w, int h) {
0569                Rectangle r = (Rectangle) dirtyComponents.get(c);
0570                if (r != null) {
0571                    // A non-null r implies c is already marked as dirty,
0572                    // and that the parent is valid. Therefore we can
0573                    // just union the rect and bail.
0574                    SwingUtilities.computeUnion(x, y, w, h, r);
0575                    return true;
0576                }
0577                return false;
0578            }
0579
0580            /** Return the current dirty region for a component.
0581             *  Return an empty rectangle if the component is not
0582             *  dirty.
0583             */
0584            public Rectangle getDirtyRegion(JComponent aComponent) {
0585                Rectangle r = null;
0586                synchronized (this ) {
0587                    r = (Rectangle) dirtyComponents.get(aComponent);
0588                }
0589                if (r == null)
0590                    return new Rectangle(0, 0, 0, 0);
0591                else
0592                    return new Rectangle(r);
0593            }
0594
0595            /** 
0596             * Mark a component completely dirty. <b>aComponent</b> will be
0597             * completely painted during the next paintDirtyRegions() call.
0598             */
0599            public void markCompletelyDirty(JComponent aComponent) {
0600                addDirtyRegion(aComponent, 0, 0, Integer.MAX_VALUE,
0601                        Integer.MAX_VALUE);
0602            }
0603
0604            /** 
0605             * Mark a component completely clean. <b>aComponent</b> will not
0606             * get painted during the next paintDirtyRegions() call.
0607             */
0608            public void markCompletelyClean(JComponent aComponent) {
0609                synchronized (this ) {
0610                    dirtyComponents.remove(aComponent);
0611                }
0612            }
0613
0614            /** 
0615             * Convenience method that returns true if <b>aComponent</b> will be completely
0616             * painted during the next paintDirtyRegions(). If computing dirty regions is
0617             * expensive for your component, use this method and avoid computing dirty region
0618             * if it return true.
0619             */
0620            public boolean isCompletelyDirty(JComponent aComponent) {
0621                Rectangle r;
0622
0623                r = getDirtyRegion(aComponent);
0624                if (r.width == Integer.MAX_VALUE
0625                        && r.height == Integer.MAX_VALUE)
0626                    return true;
0627                else
0628                    return false;
0629            }
0630
0631            /** 
0632             * Validate all of the components that have been marked invalid.
0633             * @see #addInvalidComponent
0634             */
0635            public void validateInvalidComponents() {
0636                java.util.List<Component> ic;
0637                synchronized (this ) {
0638                    if (invalidComponents == null) {
0639                        return;
0640                    }
0641                    ic = invalidComponents;
0642                    invalidComponents = null;
0643                }
0644                int n = ic.size();
0645                for (int i = 0; i < n; i++) {
0646                    ic.get(i).validate();
0647                }
0648            }
0649
0650            /**
0651             * This is invoked to process paint requests.  It's needed
0652             * for backward compatability in so far as RepaintManager would previously
0653             * not see paint requests for top levels, so, we have to make sure
0654             * a subclass correctly paints any dirty top levels.
0655             */
0656            private void prePaintDirtyRegions() {
0657                Map<Component, Rectangle> dirtyComponents;
0658                java.util.List<Runnable> runnableList;
0659                synchronized (this ) {
0660                    dirtyComponents = this .dirtyComponents;
0661                    runnableList = this .runnableList;
0662                    this .runnableList = null;
0663                }
0664                if (runnableList != null) {
0665                    for (Runnable runnable : runnableList) {
0666                        runnable.run();
0667                    }
0668                }
0669                paintDirtyRegions();
0670                if (dirtyComponents.size() > 0) {
0671                    // This'll only happen if a subclass isn't correctly dealing
0672                    // with toplevels.
0673                    paintDirtyRegions(dirtyComponents);
0674                }
0675            }
0676
0677            /**
0678             * Paint all of the components that have been marked dirty.
0679             * 
0680             * @see #addDirtyRegion
0681             */
0682            public void paintDirtyRegions() {
0683                synchronized (this ) { // swap for thread safety
0684                    Map<Component, Rectangle> tmp = tmpDirtyComponents;
0685                    tmpDirtyComponents = dirtyComponents;
0686                    dirtyComponents = tmp;
0687                    dirtyComponents.clear();
0688                }
0689                paintDirtyRegions(tmpDirtyComponents);
0690            }
0691
0692            private void paintDirtyRegions(
0693                    Map<Component, Rectangle> tmpDirtyComponents) {
0694                int i, count;
0695                java.util.List<Component> roots;
0696                Component dirtyComponent;
0697
0698                count = tmpDirtyComponents.size();
0699                if (count == 0) {
0700                    return;
0701                }
0702
0703                Rectangle rect;
0704                int localBoundsX = 0;
0705                int localBoundsY = 0;
0706                int localBoundsH = 0;
0707                int localBoundsW = 0;
0708                Enumeration keys;
0709
0710                roots = new ArrayList<Component>(count);
0711
0712                for (Component dirty : tmpDirtyComponents.keySet()) {
0713                    collectDirtyComponents(tmpDirtyComponents, dirty, roots);
0714                }
0715
0716                count = roots.size();
0717                //        System.out.println("roots size is " + count);
0718                painting = true;
0719                try {
0720                    for (i = 0; i < count; i++) {
0721                        dirtyComponent = roots.get(i);
0722                        rect = tmpDirtyComponents.get(dirtyComponent);
0723                        //            System.out.println("Should refresh :" + rect);
0724                        localBoundsH = dirtyComponent.getHeight();
0725                        localBoundsW = dirtyComponent.getWidth();
0726
0727                        SwingUtilities.computeIntersection(localBoundsX,
0728                                localBoundsY, localBoundsW, localBoundsH, rect);
0729                        if (dirtyComponent instanceof  JComponent) {
0730                            ((JComponent) dirtyComponent).paintImmediately(
0731                                    rect.x, rect.y, rect.width, rect.height);
0732                        } else if (dirtyComponent.isShowing()) {
0733                            Graphics g = JComponent.safelyGetGraphics(
0734                                    dirtyComponent, dirtyComponent);
0735                            // If the Graphics goes away, it means someone disposed of
0736                            // the window, don't do anything.
0737                            if (g != null) {
0738                                g.setClip(rect.x, rect.y, rect.width,
0739                                        rect.height);
0740                                try {
0741                                    dirtyComponent.paint(g);
0742                                } finally {
0743                                    g.dispose();
0744                                }
0745                            }
0746                        }
0747                        // If the repaintRoot has been set, service it now and
0748                        // remove any components that are children of repaintRoot.
0749                        if (repaintRoot != null) {
0750                            adjustRoots(repaintRoot, roots, i + 1);
0751                            count = roots.size();
0752                            paintManager.isRepaintingRoot = true;
0753                            repaintRoot.paintImmediately(0, 0, repaintRoot
0754                                    .getWidth(), repaintRoot.getHeight());
0755                            paintManager.isRepaintingRoot = false;
0756                            // Only service repaintRoot once.
0757                            repaintRoot = null;
0758                        }
0759                    }
0760                } finally {
0761                    painting = false;
0762                }
0763                tmpDirtyComponents.clear();
0764            }
0765
0766            /**
0767             * Removes any components from roots that are children of
0768             * root.
0769             */
0770            private void adjustRoots(JComponent root,
0771                    java.util.List<Component> roots, int index) {
0772                for (int i = roots.size() - 1; i >= index; i--) {
0773                    Component c = roots.get(i);
0774                    for (;;) {
0775                        if (c == root || c == null
0776                                || !(c instanceof  JComponent)) {
0777                            break;
0778                        }
0779                        c = c.getParent();
0780                    }
0781                    if (c == root) {
0782                        roots.remove(i);
0783                    }
0784                }
0785            }
0786
0787            Rectangle tmp = new Rectangle();
0788
0789            void collectDirtyComponents(
0790                    Map<Component, Rectangle> dirtyComponents,
0791                    Component dirtyComponent, java.util.List<Component> roots) {
0792                int dx, dy, rootDx, rootDy;
0793                Component component, rootDirtyComponent, parent;
0794                Rectangle cBounds;
0795
0796                // Find the highest parent which is dirty.  When we get out of this
0797                // rootDx and rootDy will contain the translation from the
0798                // rootDirtyComponent's coordinate system to the coordinates of the
0799                // original dirty component.  The tmp Rect is also used to compute the
0800                // visible portion of the dirtyRect.
0801
0802                component = rootDirtyComponent = dirtyComponent;
0803
0804                int x = dirtyComponent.getX();
0805                int y = dirtyComponent.getY();
0806                int w = dirtyComponent.getWidth();
0807                int h = dirtyComponent.getHeight();
0808
0809                dx = rootDx = 0;
0810                dy = rootDy = 0;
0811                tmp.setBounds((Rectangle) dirtyComponents.get(dirtyComponent));
0812
0813                // System.out.println("Collect dirty component for bound " + tmp + 
0814                //                                   "component bounds is " + cBounds);;
0815                SwingUtilities.computeIntersection(0, 0, w, h, tmp);
0816
0817                if (tmp.isEmpty()) {
0818                    // System.out.println("Empty 1");
0819                    return;
0820                }
0821
0822                for (;;) {
0823                    if (!(component instanceof  JComponent))
0824                        break;
0825
0826                    parent = component.getParent();
0827                    if (parent == null)
0828                        break;
0829
0830                    component = parent;
0831
0832                    dx += x;
0833                    dy += y;
0834                    tmp.setLocation(tmp.x + x, tmp.y + y);
0835
0836                    x = component.getX();
0837                    y = component.getY();
0838                    w = component.getWidth();
0839                    h = component.getHeight();
0840                    tmp = SwingUtilities.computeIntersection(0, 0, w, h, tmp);
0841
0842                    if (tmp.isEmpty()) {
0843                        // System.out.println("Empty 2");
0844                        return;
0845                    }
0846
0847                    if (dirtyComponents.get(component) != null) {
0848                        rootDirtyComponent = component;
0849                        rootDx = dx;
0850                        rootDy = dy;
0851                    }
0852                }
0853
0854                if (dirtyComponent != rootDirtyComponent) {
0855                    Rectangle r;
0856                    tmp.setLocation(tmp.x + rootDx - dx, tmp.y + rootDy - dy);
0857                    r = (Rectangle) dirtyComponents.get(rootDirtyComponent);
0858                    SwingUtilities.computeUnion(tmp.x, tmp.y, tmp.width,
0859                            tmp.height, r);
0860                }
0861
0862                // If we haven't seen this root before, then we need to add it to the
0863                // list of root dirty Views.
0864
0865                if (!roots.contains(rootDirtyComponent))
0866                    roots.add(rootDirtyComponent);
0867            }
0868
0869            /**
0870             * Returns a string that displays and identifies this
0871             * object's properties.
0872             *
0873             * @return a String representation of this object
0874             */
0875            public synchronized String toString() {
0876                StringBuffer sb = new StringBuffer();
0877                if (dirtyComponents != null)
0878                    sb.append("" + dirtyComponents);
0879                return sb.toString();
0880            }
0881
0882            /**
0883             * Return the offscreen buffer that should be used as a double buffer with 
0884             * the component <code>c</code>.
0885             * By default there is a double buffer per RepaintManager.
0886             * The buffer might be smaller than <code>(proposedWidth,proposedHeight)</code>
0887             * This happens when the maximum double buffer size as been set for the receiving
0888             * repaint manager.
0889             */
0890            public Image getOffscreenBuffer(Component c, int proposedWidth,
0891                    int proposedHeight) {
0892                return _getOffscreenBuffer(c, proposedWidth, proposedHeight);
0893            }
0894
0895            /**
0896             * Return a volatile offscreen buffer that should be used as a
0897             * double buffer with the specified component <code>c</code>.
0898             * The image returned will be an instance of VolatileImage, or null
0899             * if a VolatileImage object could not be instantiated.
0900             * This buffer might be smaller than <code>(proposedWidth,proposedHeight)</code>.
0901             * This happens when the maximum double buffer size has been set for this
0902             * repaint manager.
0903             *
0904             * @see java.awt.image.VolatileImage
0905             * @since 1.4
0906             */
0907            public Image getVolatileOffscreenBuffer(Component c,
0908                    int proposedWidth, int proposedHeight) {
0909                GraphicsConfiguration config = c.getGraphicsConfiguration();
0910                if (config == null) {
0911                    config = GraphicsEnvironment.getLocalGraphicsEnvironment()
0912                            .getDefaultScreenDevice().getDefaultConfiguration();
0913                }
0914                Dimension maxSize = getDoubleBufferMaximumSize();
0915                int width = proposedWidth < 1 ? 1
0916                        : (proposedWidth > maxSize.width ? maxSize.width
0917                                : proposedWidth);
0918                int height = proposedHeight < 1 ? 1
0919                        : (proposedHeight > maxSize.height ? maxSize.height
0920                                : proposedHeight);
0921                VolatileImage image = volatileMap.get(config);
0922                if (image == null || image.getWidth() < width
0923                        || image.getHeight() < height) {
0924                    if (image != null) {
0925                        image.flush();
0926                    }
0927                    image = config.createCompatibleVolatileImage(width, height);
0928                    volatileMap.put(config, image);
0929                }
0930                return image;
0931            }
0932
0933            private Image _getOffscreenBuffer(Component c, int proposedWidth,
0934                    int proposedHeight) {
0935                Dimension maxSize = getDoubleBufferMaximumSize();
0936                DoubleBufferInfo doubleBuffer = null;
0937                int width, height;
0938
0939                if (standardDoubleBuffer == null) {
0940                    standardDoubleBuffer = new DoubleBufferInfo();
0941                }
0942                doubleBuffer = standardDoubleBuffer;
0943
0944                width = proposedWidth < 1 ? 1
0945                        : (proposedWidth > maxSize.width ? maxSize.width
0946                                : proposedWidth);
0947                height = proposedHeight < 1 ? 1
0948                        : (proposedHeight > maxSize.height ? maxSize.height
0949                                : proposedHeight);
0950
0951                if (doubleBuffer.needsReset
0952                        || (doubleBuffer.image != null && (doubleBuffer.size.width < width || doubleBuffer.size.height < height))) {
0953                    doubleBuffer.needsReset = false;
0954                    if (doubleBuffer.image != null) {
0955                        doubleBuffer.image.flush();
0956                        doubleBuffer.image = null;
0957                    }
0958                    width = Math.max(doubleBuffer.size.width, width);
0959                    height = Math.max(doubleBuffer.size.height, height);
0960                }
0961
0962                Image result = doubleBuffer.image;
0963
0964                if (doubleBuffer.image == null) {
0965                    result = c.createImage(width, height);
0966                    doubleBuffer.size = new Dimension(width, height);
0967                    if (c instanceof  JComponent) {
0968                        ((JComponent) c).setCreatedDoubleBuffer(true);
0969                        doubleBuffer.image = result;
0970                    }
0971                    // JComponent will inform us when it is no longer valid
0972                    // (via removeNotify) we have no such hook to other components,
0973                    // therefore we don't keep a ref to the Component
0974                    // (indirectly through the Image) by stashing the image.
0975                }
0976                return result;
0977            }
0978
0979            /** Set the maximum double buffer size. **/
0980            public void setDoubleBufferMaximumSize(Dimension d) {
0981                doubleBufferMaxSize = d;
0982                if (doubleBufferMaxSize == null) {
0983                    clearImages();
0984                } else {
0985                    clearImages(d.width, d.height);
0986                }
0987            }
0988
0989            private void clearImages() {
0990                clearImages(0, 0);
0991            }
0992
0993            private void clearImages(int width, int height) {
0994                if (standardDoubleBuffer != null
0995                        && standardDoubleBuffer.image != null) {
0996                    if (standardDoubleBuffer.image.getWidth(null) > width
0997                            || standardDoubleBuffer.image.getHeight(null) > height) {
0998                        standardDoubleBuffer.image.flush();
0999                        standardDoubleBuffer.image = null;
1000                    }
1001                }
1002                // Clear out the VolatileImages
1003                Iterator gcs = volatileMap.keySet().iterator();
1004                while (gcs.hasNext()) {
1005                    GraphicsConfiguration gc = (GraphicsConfiguration) gcs
1006                            .next();
1007                    VolatileImage image = (VolatileImage) volatileMap.get(gc);
1008                    if (image.getWidth() > width || image.getHeight() > height) {
1009                        image.flush();
1010                        gcs.remove();
1011                    }
1012                }
1013            }
1014
1015            /**
1016             * Returns the maximum double buffer size.
1017             *
1018             * @return a Dimension object representing the maximum size
1019             */
1020            public Dimension getDoubleBufferMaximumSize() {
1021                if (doubleBufferMaxSize == null) {
1022                    try {
1023                        Rectangle virtualBounds = new Rectangle();
1024                        GraphicsEnvironment ge = GraphicsEnvironment
1025                                .getLocalGraphicsEnvironment();
1026                        for (GraphicsDevice gd : ge.getScreenDevices()) {
1027                            GraphicsConfiguration gc = gd
1028                                    .getDefaultConfiguration();
1029                            virtualBounds = virtualBounds.union(gc.getBounds());
1030                        }
1031                        doubleBufferMaxSize = new Dimension(
1032                                virtualBounds.width, virtualBounds.height);
1033                    } catch (HeadlessException e) {
1034                        doubleBufferMaxSize = new Dimension(Integer.MAX_VALUE,
1035                                Integer.MAX_VALUE);
1036                    }
1037                }
1038                return doubleBufferMaxSize;
1039            }
1040
1041            /**
1042             * Enables or disables double buffering in this RepaintManager.
1043             * CAUTION: The default value for this property is set for optimal
1044             * paint performance on the given platform and it is not recommended
1045             * that programs modify this property directly.
1046             *
1047             * @param aFlag  true to activate double buffering
1048             * @see #isDoubleBufferingEnabled
1049             */
1050            public void setDoubleBufferingEnabled(boolean aFlag) {
1051                doubleBufferingEnabled = aFlag;
1052                PaintManager paintManager = getPaintManager();
1053                if (!aFlag && paintManager.getClass() != PaintManager.class) {
1054                    setPaintManager(new PaintManager());
1055                }
1056            }
1057
1058            /**
1059             * Returns true if this RepaintManager is double buffered.
1060             * The default value for this property may vary from platform
1061             * to platform.  On platforms where native double buffering
1062             * is supported in the AWT, the default value will be <code>false</code>
1063             * to avoid unnecessary buffering in Swing.
1064             * On platforms where native double buffering is not supported,
1065             * the default value will be <code>true</code>.
1066             *
1067             * @return true if this object is double buffered
1068             */
1069            public boolean isDoubleBufferingEnabled() {
1070                return doubleBufferingEnabled;
1071            }
1072
1073            /**
1074             * This resets the double buffer. Actually, it marks the double buffer
1075             * as invalid, the double buffer will then be recreated on the next
1076             * invocation of getOffscreenBuffer.
1077             */
1078            void resetDoubleBuffer() {
1079                if (standardDoubleBuffer != null) {
1080                    standardDoubleBuffer.needsReset = true;
1081                }
1082            }
1083
1084            /**
1085             * This resets the volatile double buffer. 
1086             */
1087            void resetVolatileDoubleBuffer(GraphicsConfiguration gc) {
1088                Image image = volatileMap.remove(gc);
1089                if (image != null) {
1090                    image.flush();
1091                }
1092            }
1093
1094            /**
1095             * Returns true if we should use the <code>Image</code> returned
1096             * from <code>getVolatileOffscreenBuffer</code> to do double buffering.
1097             */
1098            boolean useVolatileDoubleBuffer() {
1099                return volatileImageBufferEnabled;
1100            }
1101
1102            /**
1103             * Returns true if the current thread is the thread painting.  This
1104             * will return false if no threads are painting.
1105             */
1106            private synchronized boolean isPaintingThread() {
1107                return (Thread.currentThread() == paintThread);
1108            }
1109
1110            //
1111            // Paint methods.  You very, VERY rarely need to invoke these.
1112            // They are invoked directly from JComponent's painting code and
1113            // when painting happens outside the normal flow: DefaultDesktopManager
1114            // and JViewport.  If you end up needing these methods in other places be
1115            // careful that you don't get stuck in a paint loop.
1116            // 
1117
1118            /**
1119             * Paints a region of a component
1120             *
1121             * @param paintingComponent Component to paint
1122             * @param bufferComponent Component to obtain buffer for
1123             * @param g Graphics to paint to
1124             * @param x X-coordinate
1125             * @param y Y-coordinate
1126             * @param w Width
1127             * @param h Height
1128             */
1129            void paint(JComponent paintingComponent,
1130                    JComponent bufferComponent, Graphics g, int x, int y,
1131                    int w, int h) {
1132                PaintManager paintManager = getPaintManager();
1133                if (!isPaintingThread()) {
1134                    // We're painting to two threads at once.  PaintManager deals
1135                    // with this a bit better than BufferStrategyPaintManager, use
1136                    // it to avoid possible exceptions/corruption.
1137                    if (paintManager.getClass() != PaintManager.class) {
1138                        paintManager = new PaintManager();
1139                        paintManager.repaintManager = this ;
1140                    }
1141                }
1142                if (!paintManager.paint(paintingComponent, bufferComponent, g,
1143                        x, y, w, h)) {
1144                    g.setClip(x, y, w, h);
1145                    paintingComponent.paintToOffscreen(g, x, y, w, h, x + w, y
1146                            + h);
1147                }
1148            }
1149
1150            /**
1151             * Does a copy area on the specified region.
1152             *
1153             * @param clip Whether or not the copyArea needs to be clipped to the
1154             *             Component's bounds.
1155             */
1156            void copyArea(JComponent c, Graphics g, int x, int y, int w, int h,
1157                    int deltaX, int deltaY, boolean clip) {
1158                getPaintManager().copyArea(c, g, x, y, w, h, deltaX, deltaY,
1159                        clip);
1160            }
1161
1162            /**
1163             * Invoked prior to any paint/copyArea method calls.  This will
1164             * be followed by an invocation of <code>endPaint</code>.
1165             * <b>WARNING</b>: Callers of this method need to wrap the call
1166             * in a <code>try/finally</code>, otherwise if an exception is thrown
1167             * during the course of painting the RepaintManager may
1168             * be left in a state in which the screen is not updated, eg:
1169             * <pre>
1170             * repaintManager.beginPaint();
1171             * try {
1172             *   repaintManager.paint(...);
1173             * } finally {
1174             *   repaintManager.endPaint();
1175             * }
1176             * </pre>
1177             */
1178            void beginPaint() {
1179                boolean multiThreadedPaint = false;
1180                int paintDepth = 0;
1181                Thread currentThread = Thread.currentThread();
1182                synchronized (this ) {
1183                    paintDepth = this .paintDepth;
1184                    if (paintThread == null || currentThread == paintThread) {
1185                        paintThread = currentThread;
1186                        this .paintDepth++;
1187                    } else {
1188                        multiThreadedPaint = true;
1189                    }
1190                }
1191                if (!multiThreadedPaint && paintDepth == 0) {
1192                    getPaintManager().beginPaint();
1193                }
1194            }
1195
1196            /**
1197             * Invoked after <code>beginPaint</code> has been invoked.
1198             */
1199            void endPaint() {
1200                if (isPaintingThread()) {
1201                    PaintManager paintManager = null;
1202                    synchronized (this ) {
1203                        if (--paintDepth == 0) {
1204                            paintManager = getPaintManager();
1205                        }
1206                    }
1207                    if (paintManager != null) {
1208                        paintManager.endPaint();
1209                        synchronized (this ) {
1210                            paintThread = null;
1211                        }
1212                    }
1213                }
1214            }
1215
1216            /**
1217             * If possible this will show a previously rendered portion of
1218             * a Component.  If successful, this will return true, otherwise false.
1219             * <p>
1220             * WARNING: This method is invoked from the native toolkit thread, be
1221             * very careful as to what methods this invokes!
1222             */
1223            boolean show(Container c, int x, int y, int w, int h) {
1224                return getPaintManager().show(c, x, y, w, h);
1225            }
1226
1227            /**
1228             * Invoked when the doubleBuffered or useTrueDoubleBuffering
1229             * properties of a JRootPane change.  This may come in on any thread.
1230             */
1231            void doubleBufferingChanged(JRootPane rootPane) {
1232                getPaintManager().doubleBufferingChanged(rootPane);
1233            }
1234
1235            /**
1236             * Sets the <code>PaintManager</code> that is used to handle all
1237             * double buffered painting.
1238             *
1239             * @param paintManager The PaintManager to use.  Passing in null indicates
1240             *        the fallback PaintManager should be used.
1241             */
1242            void setPaintManager(PaintManager paintManager) {
1243                if (paintManager == null) {
1244                    paintManager = new PaintManager();
1245                }
1246                PaintManager oldPaintManager;
1247                synchronized (this ) {
1248                    oldPaintManager = this .paintManager;
1249                    this .paintManager = paintManager;
1250                    paintManager.repaintManager = this ;
1251                }
1252                if (oldPaintManager != null) {
1253                    oldPaintManager.dispose();
1254                }
1255            }
1256
1257            private synchronized PaintManager getPaintManager() {
1258                if (paintManager == null) {
1259                    PaintManager paintManager = null;
1260                    if (doubleBufferingEnabled && !nativeDoubleBuffering) {
1261                        switch (bufferStrategyType) {
1262                        case BUFFER_STRATEGY_NOT_SPECIFIED:
1263                            if (((SunToolkit) Toolkit.getDefaultToolkit())
1264                                    .useBufferPerWindow()) {
1265                                paintManager = new BufferStrategyPaintManager();
1266                            }
1267                            break;
1268                        case BUFFER_STRATEGY_SPECIFIED_ON:
1269                            paintManager = new BufferStrategyPaintManager();
1270                            break;
1271                        default:
1272                            break;
1273                        }
1274                    }
1275                    // null case handled in setPaintManager
1276                    setPaintManager(paintManager);
1277                }
1278                return paintManager;
1279            }
1280
1281            private void scheduleProcessingRunnable() {
1282                scheduleProcessingRunnable(AppContext.getAppContext());
1283            }
1284
1285            private void scheduleProcessingRunnable(AppContext context) {
1286                if (processingRunnable.markPending()) {
1287                    SunToolkit.getSystemEventQueueImplPP(context).postEvent(
1288                            new InvocationEvent(Toolkit.getDefaultToolkit(),
1289                                    processingRunnable));
1290                }
1291            }
1292
1293            /**
1294             * PaintManager is used to handle all double buffered painting for
1295             * Swing.  Subclasses should call back into the JComponent method
1296             * <code>paintToOffscreen</code> to handle the actual painting.
1297             */
1298            static class PaintManager {
1299                /**
1300                 * RepaintManager the PaintManager has been installed on.
1301                 */
1302                protected RepaintManager repaintManager;
1303                boolean isRepaintingRoot;
1304
1305                /**
1306                 * Paints a region of a component
1307                 *
1308                 * @param paintingComponent Component to paint
1309                 * @param bufferComponent Component to obtain buffer for
1310                 * @param g Graphics to paint to
1311                 * @param x X-coordinate
1312                 * @param y Y-coordinate
1313                 * @param w Width
1314                 * @param h Height
1315                 * @return true if painting was successful.
1316                 */
1317                public boolean paint(JComponent paintingComponent,
1318                        JComponent bufferComponent, Graphics g, int x, int y,
1319                        int w, int h) {
1320                    // First attempt to use VolatileImage buffer for performance.
1321                    // If this fails (which should rarely occur), fallback to a
1322                    // standard Image buffer.
1323                    boolean paintCompleted = false;
1324                    Image offscreen;
1325                    if (repaintManager.useVolatileDoubleBuffer()
1326                            && (offscreen = getValidImage(repaintManager
1327                                    .getVolatileOffscreenBuffer(
1328                                            bufferComponent, w, h))) != null) {
1329                        VolatileImage vImage = (java.awt.image.VolatileImage) offscreen;
1330                        GraphicsConfiguration gc = bufferComponent
1331                                .getGraphicsConfiguration();
1332                        for (int i = 0; !paintCompleted
1333                                && i < RepaintManager.VOLATILE_LOOP_MAX; i++) {
1334                            if (vImage.validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE) {
1335                                repaintManager.resetVolatileDoubleBuffer(gc);
1336                                offscreen = repaintManager
1337                                        .getVolatileOffscreenBuffer(
1338                                                bufferComponent, w, h);
1339                                vImage = (java.awt.image.VolatileImage) offscreen;
1340                            }
1341                            paintDoubleBuffered(paintingComponent, vImage, g,
1342                                    x, y, w, h);
1343                            paintCompleted = !vImage.contentsLost();
1344                        }
1345                    }
1346                    // VolatileImage painting loop failed, fallback to regular
1347                    // offscreen buffer
1348                    if (!paintCompleted
1349                            && (offscreen = getValidImage(repaintManager
1350                                    .getOffscreenBuffer(bufferComponent, w, h))) != null) {
1351                        paintDoubleBuffered(paintingComponent, offscreen, g, x,
1352                                y, w, h);
1353                        paintCompleted = true;
1354                    }
1355                    return paintCompleted;
1356                }
1357
1358                /**
1359                 * Does a copy area on the specified region.
1360                 */
1361                public void copyArea(JComponent c, Graphics g, int x, int y,
1362                        int w, int h, int deltaX, int deltaY, boolean clip) {
1363                    g.copyArea(x, y, w, h, deltaX, deltaY);
1364                }
1365
1366                /**
1367                 * Invoked prior to any calls to paint or copyArea.
1368                 */
1369                public void beginPaint() {
1370                }
1371
1372                /**
1373                 * Invoked to indicate painting has been completed.
1374                 */
1375                public void endPaint() {
1376                }
1377
1378                /**
1379                 * Shows a region of a previously rendered component.  This
1380                 * will return true if successful, false otherwise.  The default
1381                 * implementation returns false.
1382                 */
1383                public boolean show(Container c, int x, int y, int w, int h) {
1384                    return false;
1385                }
1386
1387                /**
1388                 * Invoked when the doubleBuffered or useTrueDoubleBuffering
1389                 * properties of a JRootPane change.  This may come in on any thread.
1390                 */
1391                public void doubleBufferingChanged(JRootPane rootPane) {
1392                }
1393
1394                /**
1395                 * Paints a portion of a component to an offscreen buffer.
1396                 */
1397                protected void paintDoubleBuffered(JComponent c, Image image,
1398                        Graphics g, int clipX, int clipY, int clipW, int clipH) {
1399                    Graphics osg = image.getGraphics();
1400                    int bw = Math.min(clipW, image.getWidth(null));
1401                    int bh = Math.min(clipH, image.getHeight(null));
1402                    int x, y, maxx, maxy;
1403
1404                    try {
1405                        for (x = clipX, maxx = clipX + clipW; x < maxx; x += bw) {
1406                            for (y = clipY, maxy = clipY + clipH; y < maxy; y += bh) {
1407                                osg.translate(-x, -y);
1408                                osg.setClip(x, y, bw, bh);
1409                                c.paintToOffscreen(osg, x, y, bw, bh, maxx,
1410                                        maxy);
1411                                g.setClip(x, y, bw, bh);
1412                                g.drawImage(image, x, y, c);
1413                                osg.translate(x, y);
1414                            }
1415                        }
1416                    } finally {
1417                        osg.dispose();
1418                    }
1419                }
1420
1421                /**
1422                 * If <code>image</code> is non-null with a positive size it
1423                 * is returned, otherwise null is returned.
1424                 */
1425                private Image getValidImage(Image image) {
1426                    if (image != null && image.getWidth(null) > 0
1427                            && image.getHeight(null) > 0) {
1428                        return image;
1429                    }
1430                    return null;
1431                }
1432
1433                /**
1434                 * Schedules a repaint for the specified component.  This differs
1435                 * from <code>root.repaint</code> in that if the RepaintManager is
1436                 * currently processing paint requests it'll process this request
1437                 * with the current set of requests.
1438                 */
1439                protected void repaintRoot(JComponent root) {
1440                    assert (repaintManager.repaintRoot == null);
1441                    if (repaintManager.painting) {
1442                        repaintManager.repaintRoot = root;
1443                    } else {
1444                        root.repaint();
1445                    }
1446                }
1447
1448                /**
1449                 * Returns true if the component being painted is the root component
1450                 * that was previously passed to <code>repaintRoot</code>.
1451                 */
1452                protected boolean isRepaintingRoot() {
1453                    return isRepaintingRoot;
1454                }
1455
1456                /**
1457                 * Cleans up any state.  After invoked the PaintManager will no
1458                 * longer be used anymore.
1459                 */
1460                protected void dispose() {
1461                }
1462            }
1463
1464            private class DoubleBufferInfo {
1465                public Image image;
1466                public Dimension size;
1467                public boolean needsReset = false;
1468            }
1469
1470            /**
1471             * Listener installed to detect display changes. When display changes,
1472             * schedules a callback to notify all RepaintManagers of the display
1473             * changes. Only one DisplayChangedHandler is ever installed. The
1474             * singleton instance will schedule notification for all AppContexts.
1475             */
1476            private static final class DisplayChangedHandler implements 
1477                    DisplayChangedListener {
1478                public void displayChanged() {
1479                    scheduleDisplayChanges();
1480                }
1481
1482                public void paletteChanged() {
1483                }
1484
1485                private void scheduleDisplayChanges() {
1486                    // To avoid threading problems, we notify each RepaintManager
1487                    // on the thread it was created on.
1488                    for (Object c : AppContext.getAppContexts()) {
1489                        AppContext context = (AppContext) c;
1490                        synchronized (context) {
1491                            if (!context.isDisposed()) {
1492                                EventQueue eventQueue = (EventQueue) context
1493                                        .get(AppContext.EVENT_QUEUE_KEY);
1494                                if (eventQueue != null) {
1495                                    eventQueue.postEvent(new InvocationEvent(
1496                                            Toolkit.getDefaultToolkit(),
1497                                            new DisplayChangedRunnable()));
1498                                }
1499                            }
1500                        }
1501                    }
1502                }
1503            }
1504
1505            private static final class DisplayChangedRunnable implements 
1506                    Runnable {
1507                public void run() {
1508                    RepaintManager.currentManager((JComponent) null)
1509                            .displayChanged();
1510                }
1511            }
1512
1513            /**
1514             * Runnable used to process all repaint/revalidate requests.
1515             */
1516            private final class ProcessingRunnable implements  Runnable {
1517                // If true, we're wainting on the EventQueue.
1518                private boolean pending;
1519
1520                /**
1521                 * Marks this processing runnable as pending. If this was not
1522                 * already marked as pending, true is returned.
1523                 */
1524                public synchronized boolean markPending() {
1525                    if (!pending) {
1526                        pending = true;
1527                        return true;
1528                    }
1529                    return false;
1530                }
1531
1532                public void run() {
1533                    synchronized (this ) {
1534                        pending = false;
1535                    }
1536                    // First pass, flush any heavy paint events into real paint
1537                    // events.  If there are pending heavy weight requests this will
1538                    // result in q'ing this request up one more time.  As
1539                    // long as no other requests come in between now and the time
1540                    // the second one is processed nothing will happen.  This is not
1541                    // ideal, but the logic needed to suppress the second request is
1542                    // more headache than it's worth.
1543                    scheduleHeavyWeightPaints();
1544                    // Do the actual validation and painting.
1545                    validateInvalidComponents();
1546                    prePaintDirtyRegions();
1547                }
1548            }
1549        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.