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

Print this page
rev 5725 : Merge


  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing;
  26 
  27 
  28 import java.awt.*;
  29 import java.awt.event.*;
  30 import java.awt.peer.ComponentPeer;
  31 import java.awt.peer.ContainerPeer;
  32 import java.awt.image.VolatileImage;

  33 import java.security.AccessController;

  34 import java.util.*;

  35 import java.applet.*;
  36 
  37 import sun.awt.AWTAccessor;
  38 import sun.awt.AppContext;
  39 import sun.awt.DisplayChangedListener;
  40 import sun.awt.SunToolkit;
  41 import sun.java2d.SunGraphicsEnvironment;


  42 import sun.security.action.GetPropertyAction;
  43 
  44 import com.sun.java.swing.SwingUtilities3;
  45 
  46 /**
  47  * This class manages repaint requests, allowing the number
  48  * of repaints to be minimized, for example by collapsing multiple
  49  * requests into a single repaint for members of a component tree.
  50  * <p>
  51  * As of 1.6 <code>RepaintManager</code> handles repaint requests
  52  * for Swing's top level components (<code>JApplet</code>,
  53  * <code>JWindow</code>, <code>JFrame</code> and <code>JDialog</code>).
  54  * Any calls to <code>repaint</code> on one of these will call into the
  55  * appropriate <code>addDirtyRegion</code> method.
  56  *
  57  * @author Arnaud Weber
  58  */
  59 public class RepaintManager
  60 {
  61     /**


 159      * set to true in <code>paintDirtyRegions</code>.
 160      */
 161     private boolean painting;
 162     /**
 163      * If the PaintManager calls into repaintRoot during painting this field
 164      * will be set to the root.
 165      */
 166     private JComponent repaintRoot;
 167 
 168     /**
 169      * The Thread that has initiated painting.  If null it
 170      * indicates painting is not currently in progress.
 171      */
 172     private Thread paintThread;
 173 
 174     /**
 175      * Runnable used to process all repaint/revalidate requests.
 176      */
 177     private final ProcessingRunnable processingRunnable;
 178 



 179 
 180     static {
 181         volatileImageBufferEnabled = "true".equals(AccessController.
 182                 doPrivileged(new GetPropertyAction(
 183                 "swing.volatileImageBufferEnabled", "true")));
 184         boolean headless = GraphicsEnvironment.isHeadless();
 185         if (volatileImageBufferEnabled && headless) {
 186             volatileImageBufferEnabled = false;
 187         }
 188         nativeDoubleBuffering = "true".equals(AccessController.doPrivileged(
 189                     new GetPropertyAction("awt.nativeDoubleBuffering")));
 190         String bs = AccessController.doPrivileged(
 191                           new GetPropertyAction("swing.bufferPerWindow"));
 192         if (headless) {
 193             BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_SPECIFIED_OFF;
 194         }
 195         else if (bs == null) {
 196             BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_NOT_SPECIFIED;
 197         }
 198         else if ("true".equals(bs)) {


 531                               int x, int y, int w, int h) {
 532         if (w > 0 && h > 0) {
 533             synchronized(this) {
 534                 Rectangle dirty = hwDirtyComponents.get(c);
 535                 if (dirty == null) {
 536                     hwDirtyComponents.put(c, new Rectangle(x, y, w, h));
 537                 }
 538                 else {
 539                     hwDirtyComponents.put(c, SwingUtilities.computeUnion(
 540                                               x, y, w, h, dirty));
 541                 }
 542             }
 543             scheduleProcessingRunnable(appContext);
 544         }
 545     }
 546 
 547     //
 548     // This is called from the toolkit thread when awt needs to run a
 549     // Runnable before we paint.
 550     //
 551     void nativeQueueSurfaceDataRunnable(AppContext appContext, Component c,
 552                                         Runnable r) {

 553         synchronized(this) {
 554             if (runnableList == null) {
 555                 runnableList = new LinkedList<Runnable>();
 556             }
 557             runnableList.add(r);












 558         }
 559         scheduleProcessingRunnable(appContext);
 560     }
 561 
 562     /**
 563      * Extends the dirty region for the specified component to include
 564      * the new region.
 565      *
 566      * @return false if <code>c</code> is not yet marked dirty.
 567      */
 568     private synchronized boolean extendDirtyRegion(
 569         Component c, int x, int y, int w, int h) {
 570         Rectangle r = dirtyComponents.get(c);
 571         if (r != null) {
 572             // A non-null r implies c is already marked as dirty,
 573             // and that the parent is valid. Therefore we can
 574             // just union the rect and bail.
 575             SwingUtilities.computeUnion(x, y, w, h, r);
 576             return true;
 577         }


 635         RepaintManager delegate = getDelegate(aComponent);
 636         if (delegate != null) {
 637             return delegate.isCompletelyDirty(aComponent);
 638         }
 639         Rectangle r;
 640 
 641         r = getDirtyRegion(aComponent);
 642         if(r.width == Integer.MAX_VALUE &&
 643            r.height == Integer.MAX_VALUE)
 644             return true;
 645         else
 646             return false;
 647     }
 648 
 649 
 650     /**
 651      * Validate all of the components that have been marked invalid.
 652      * @see #addInvalidComponent
 653      */
 654     public void validateInvalidComponents() {
 655         java.util.List<Component> ic;
 656         synchronized(this) {
 657             if(invalidComponents == null) {
 658                 return;
 659             }
 660             ic = invalidComponents;
 661             invalidComponents = null;
 662         }
 663         int n = ic.size();
 664         for(int i = 0; i < n; i++) {
 665             ic.get(i).validate();










 666         }
 667     }
 668 
 669 
 670     /**
 671      * This is invoked to process paint requests.  It's needed
 672      * for backward compatability in so far as RepaintManager would previously
 673      * not see paint requests for top levels, so, we have to make sure
 674      * a subclass correctly paints any dirty top levels.
 675      */
 676     private void prePaintDirtyRegions() {
 677         Map<Component,Rectangle> dirtyComponents;
 678         java.util.List<Runnable> runnableList;
 679         synchronized(this) {
 680             dirtyComponents = this.dirtyComponents;
 681             runnableList = this.runnableList;
 682             this.runnableList = null;
 683         }
 684         if (runnableList != null) {
 685             for (Runnable runnable : runnableList) {


 723 
 724     boolean isPainting() {
 725         return painting;
 726     }
 727 
 728     /**
 729      * Paint all of the components that have been marked dirty.
 730      *
 731      * @see #addDirtyRegion
 732      */
 733     public void paintDirtyRegions() {
 734         synchronized(this) {  // swap for thread safety
 735             Map<Component,Rectangle> tmp = tmpDirtyComponents;
 736             tmpDirtyComponents = dirtyComponents;
 737             dirtyComponents = tmp;
 738             dirtyComponents.clear();
 739         }
 740         paintDirtyRegions(tmpDirtyComponents);
 741     }
 742 
 743     private void paintDirtyRegions(Map<Component,Rectangle>
 744                                    tmpDirtyComponents){
 745         int i, count;
 746         java.util.List<Component> roots;
 747         Component dirtyComponent;
 748 
 749         count = tmpDirtyComponents.size();
 750         if (count == 0) {
 751             return;
 752         }
 753 
 754         Rectangle rect;
 755         int localBoundsX = 0;
 756         int localBoundsY = 0;
 757         int localBoundsH;
 758         int localBoundsW;
 759         Enumeration keys;
 760 
 761         roots = new ArrayList<Component>(count);
 762 
 763         for (Component dirty : tmpDirtyComponents.keySet()) {
 764             collectDirtyComponents(tmpDirtyComponents, dirty, roots);
 765         }
 766 
 767         count = roots.size();
 768         painting = true;
 769         try {
 770             for(i=0 ; i < count ; i++) {
 771                 dirtyComponent = roots.get(i);
 772                 rect = tmpDirtyComponents.get(dirtyComponent);
 773                 localBoundsH = dirtyComponent.getHeight();
 774                 localBoundsW = dirtyComponent.getWidth();
 775 
 776                 SwingUtilities.computeIntersection(localBoundsX,
 777                                                    localBoundsY,







 778                                                    localBoundsW,
 779                                                    localBoundsH,
 780                                                    rect);
 781                 if (dirtyComponent instanceof JComponent) {
 782                     ((JComponent)dirtyComponent).paintImmediately(
 783                         rect.x,rect.y,rect.width, rect.height);
 784                 }
 785                 else if (dirtyComponent.isShowing()) {
 786                     Graphics g = JComponent.safelyGetGraphics(
 787                             dirtyComponent, dirtyComponent);
 788                     // If the Graphics goes away, it means someone disposed of
 789                     // the window, don't do anything.
 790                     if (g != null) {
 791                         g.setClip(rect.x, rect.y, rect.width, rect.height);
 792                         try {
 793                             dirtyComponent.paint(g);
 794                         } finally {
 795                             g.dispose();
 796                         }
 797                     }
 798                 }
 799                 // If the repaintRoot has been set, service it now and
 800                 // remove any components that are children of repaintRoot.
 801                 if (repaintRoot != null) {
 802                     adjustRoots(repaintRoot, roots, i + 1);
 803                     count = roots.size();
 804                     paintManager.isRepaintingRoot = true;
 805                     repaintRoot.paintImmediately(0, 0, repaintRoot.getWidth(),
 806                                                  repaintRoot.getHeight());
 807                     paintManager.isRepaintingRoot = false;
 808                     // Only service repaintRoot once.
 809                     repaintRoot = null;
 810                 }




 811             }
 812         } finally {
 813             painting = false;
 814         }
 815 
 816         updateWindows(tmpDirtyComponents);
 817 
 818         tmpDirtyComponents.clear();
 819     }
 820 
 821 
 822     /**
 823      * Removes any components from roots that are children of
 824      * root.
 825      */
 826     private void adjustRoots(JComponent root,
 827                              java.util.List<Component> roots, int index) {
 828         for (int i = roots.size() - 1; i >= index; i--) {
 829             Component c = roots.get(i);
 830             for(;;) {




  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing;
  26 
  27 
  28 import java.awt.*;
  29 import java.awt.event.*;


  30 import java.awt.image.VolatileImage;
  31 import java.security.AccessControlContext;
  32 import java.security.AccessController;
  33 import java.security.PrivilegedAction;
  34 import java.util.*;
  35 import java.util.concurrent.atomic.AtomicInteger;
  36 import java.applet.*;
  37 
  38 import sun.awt.AWTAccessor;
  39 import sun.awt.AppContext;
  40 import sun.awt.DisplayChangedListener;
  41 import sun.awt.SunToolkit;
  42 import sun.java2d.SunGraphicsEnvironment;
  43 import sun.misc.JavaSecurityAccess;
  44 import sun.misc.SharedSecrets;
  45 import sun.security.action.GetPropertyAction;
  46 
  47 import com.sun.java.swing.SwingUtilities3;
  48 
  49 /**
  50  * This class manages repaint requests, allowing the number
  51  * of repaints to be minimized, for example by collapsing multiple
  52  * requests into a single repaint for members of a component tree.
  53  * <p>
  54  * As of 1.6 <code>RepaintManager</code> handles repaint requests
  55  * for Swing's top level components (<code>JApplet</code>,
  56  * <code>JWindow</code>, <code>JFrame</code> and <code>JDialog</code>).
  57  * Any calls to <code>repaint</code> on one of these will call into the
  58  * appropriate <code>addDirtyRegion</code> method.
  59  *
  60  * @author Arnaud Weber
  61  */
  62 public class RepaintManager
  63 {
  64     /**


 162      * set to true in <code>paintDirtyRegions</code>.
 163      */
 164     private boolean painting;
 165     /**
 166      * If the PaintManager calls into repaintRoot during painting this field
 167      * will be set to the root.
 168      */
 169     private JComponent repaintRoot;
 170 
 171     /**
 172      * The Thread that has initiated painting.  If null it
 173      * indicates painting is not currently in progress.
 174      */
 175     private Thread paintThread;
 176 
 177     /**
 178      * Runnable used to process all repaint/revalidate requests.
 179      */
 180     private final ProcessingRunnable processingRunnable;
 181 
 182     private final static JavaSecurityAccess javaSecurityAccess =
 183         SharedSecrets.getJavaSecurityAccess();
 184 
 185 
 186     static {
 187         volatileImageBufferEnabled = "true".equals(AccessController.
 188                 doPrivileged(new GetPropertyAction(
 189                 "swing.volatileImageBufferEnabled", "true")));
 190         boolean headless = GraphicsEnvironment.isHeadless();
 191         if (volatileImageBufferEnabled && headless) {
 192             volatileImageBufferEnabled = false;
 193         }
 194         nativeDoubleBuffering = "true".equals(AccessController.doPrivileged(
 195                     new GetPropertyAction("awt.nativeDoubleBuffering")));
 196         String bs = AccessController.doPrivileged(
 197                           new GetPropertyAction("swing.bufferPerWindow"));
 198         if (headless) {
 199             BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_SPECIFIED_OFF;
 200         }
 201         else if (bs == null) {
 202             BUFFER_STRATEGY_TYPE = BUFFER_STRATEGY_NOT_SPECIFIED;
 203         }
 204         else if ("true".equals(bs)) {


 537                               int x, int y, int w, int h) {
 538         if (w > 0 && h > 0) {
 539             synchronized(this) {
 540                 Rectangle dirty = hwDirtyComponents.get(c);
 541                 if (dirty == null) {
 542                     hwDirtyComponents.put(c, new Rectangle(x, y, w, h));
 543                 }
 544                 else {
 545                     hwDirtyComponents.put(c, SwingUtilities.computeUnion(
 546                                               x, y, w, h, dirty));
 547                 }
 548             }
 549             scheduleProcessingRunnable(appContext);
 550         }
 551     }
 552 
 553     //
 554     // This is called from the toolkit thread when awt needs to run a
 555     // Runnable before we paint.
 556     //
 557     void nativeQueueSurfaceDataRunnable(AppContext appContext,
 558                                         final Component c, final Runnable r)
 559     {
 560         synchronized(this) {
 561             if (runnableList == null) {
 562                 runnableList = new LinkedList<Runnable>();
 563             }
 564             runnableList.add(new Runnable() {
 565                 public void run() {
 566                     AccessControlContext stack = AccessController.getContext();
 567                     AccessControlContext acc =
 568                         AWTAccessor.getComponentAccessor().getAccessControlContext(c);
 569                     javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Void>() {
 570                         public Void run() {
 571                             r.run();
 572                             return null;
 573                         }
 574                     }, stack, acc);
 575                 }
 576             });
 577         }
 578         scheduleProcessingRunnable(appContext);
 579     }
 580 
 581     /**
 582      * Extends the dirty region for the specified component to include
 583      * the new region.
 584      *
 585      * @return false if <code>c</code> is not yet marked dirty.
 586      */
 587     private synchronized boolean extendDirtyRegion(
 588         Component c, int x, int y, int w, int h) {
 589         Rectangle r = dirtyComponents.get(c);
 590         if (r != null) {
 591             // A non-null r implies c is already marked as dirty,
 592             // and that the parent is valid. Therefore we can
 593             // just union the rect and bail.
 594             SwingUtilities.computeUnion(x, y, w, h, r);
 595             return true;
 596         }


 654         RepaintManager delegate = getDelegate(aComponent);
 655         if (delegate != null) {
 656             return delegate.isCompletelyDirty(aComponent);
 657         }
 658         Rectangle r;
 659 
 660         r = getDirtyRegion(aComponent);
 661         if(r.width == Integer.MAX_VALUE &&
 662            r.height == Integer.MAX_VALUE)
 663             return true;
 664         else
 665             return false;
 666     }
 667 
 668 
 669     /**
 670      * Validate all of the components that have been marked invalid.
 671      * @see #addInvalidComponent
 672      */
 673     public void validateInvalidComponents() {
 674         final java.util.List<Component> ic;
 675         synchronized(this) {
 676             if (invalidComponents == null) {
 677                 return;
 678             }
 679             ic = invalidComponents;
 680             invalidComponents = null;
 681         }
 682         int n = ic.size();
 683         for(int i = 0; i < n; i++) {
 684             final Component c = ic.get(i);
 685             AccessControlContext stack = AccessController.getContext();
 686             AccessControlContext acc =
 687                 AWTAccessor.getComponentAccessor().getAccessControlContext(c);
 688             javaSecurityAccess.doIntersectionPrivilege(
 689                 new PrivilegedAction<Void>() {
 690                     public Void run() {
 691                         c.validate();
 692                         return null;
 693                     }
 694                 }, stack, acc);
 695         }
 696     }
 697 
 698 
 699     /**
 700      * This is invoked to process paint requests.  It's needed
 701      * for backward compatability in so far as RepaintManager would previously
 702      * not see paint requests for top levels, so, we have to make sure
 703      * a subclass correctly paints any dirty top levels.
 704      */
 705     private void prePaintDirtyRegions() {
 706         Map<Component,Rectangle> dirtyComponents;
 707         java.util.List<Runnable> runnableList;
 708         synchronized(this) {
 709             dirtyComponents = this.dirtyComponents;
 710             runnableList = this.runnableList;
 711             this.runnableList = null;
 712         }
 713         if (runnableList != null) {
 714             for (Runnable runnable : runnableList) {


 752 
 753     boolean isPainting() {
 754         return painting;
 755     }
 756 
 757     /**
 758      * Paint all of the components that have been marked dirty.
 759      *
 760      * @see #addDirtyRegion
 761      */
 762     public void paintDirtyRegions() {
 763         synchronized(this) {  // swap for thread safety
 764             Map<Component,Rectangle> tmp = tmpDirtyComponents;
 765             tmpDirtyComponents = dirtyComponents;
 766             dirtyComponents = tmp;
 767             dirtyComponents.clear();
 768         }
 769         paintDirtyRegions(tmpDirtyComponents);
 770     }
 771 
 772     private void paintDirtyRegions(
 773         final Map<Component,Rectangle> tmpDirtyComponents)
 774     {
 775         if (tmpDirtyComponents.isEmpty()) {




 776             return;
 777         }
 778 
 779         final java.util.List<Component> roots =
 780             new ArrayList<Component>(tmpDirtyComponents.size());






 781 
 782         for (Component dirty : tmpDirtyComponents.keySet()) {
 783             collectDirtyComponents(tmpDirtyComponents, dirty, roots);
 784         }
 785 
 786         final AtomicInteger count = new AtomicInteger(roots.size());
 787         painting = true;
 788         try {
 789             for(int j = 0; j < count.get(); j++) {
 790                 final int i = j;
 791                 final Component dirtyComponent = roots.get(j);
 792 
 793                 AccessControlContext stack = AccessController.getContext();
 794                 AccessControlContext acc =
 795                     AWTAccessor.getComponentAccessor().getAccessControlContext(dirtyComponent);
 796                 javaSecurityAccess.doIntersectionPrivilege(new PrivilegedAction<Void>() {
 797                     public Void run() {
 798                         Rectangle rect = tmpDirtyComponents.get(dirtyComponent);
 799 
 800                         int localBoundsH = dirtyComponent.getHeight();
 801                         int localBoundsW = dirtyComponent.getWidth();
 802                         SwingUtilities.computeIntersection(0,
 803                                                            0,
 804                                                            localBoundsW,
 805                                                            localBoundsH,
 806                                                            rect);
 807                         if (dirtyComponent instanceof JComponent) {
 808                             ((JComponent)dirtyComponent).paintImmediately(
 809                                 rect.x,rect.y,rect.width, rect.height);
 810                         }
 811                         else if (dirtyComponent.isShowing()) {
 812                             Graphics g = JComponent.safelyGetGraphics(
 813                                     dirtyComponent, dirtyComponent);
 814                             // If the Graphics goes away, it means someone disposed of
 815                             // the window, don't do anything.
 816                             if (g != null) {
 817                                 g.setClip(rect.x, rect.y, rect.width, rect.height);
 818                                 try {
 819                                     dirtyComponent.paint(g);
 820                                 } finally {
 821                                     g.dispose();
 822                                 }
 823                             }
 824                         }
 825                         // If the repaintRoot has been set, service it now and
 826                         // remove any components that are children of repaintRoot.
 827                         if (repaintRoot != null) {
 828                             adjustRoots(repaintRoot, roots, i + 1);
 829                             count.set(roots.size());
 830                             paintManager.isRepaintingRoot = true;
 831                             repaintRoot.paintImmediately(0, 0, repaintRoot.getWidth(),
 832                                                          repaintRoot.getHeight());
 833                             paintManager.isRepaintingRoot = false;
 834                             // Only service repaintRoot once.
 835                             repaintRoot = null;
 836                         }
 837 
 838                         return null;
 839                     }
 840                 }, stack, acc);
 841             }
 842         } finally {
 843             painting = false;
 844         }
 845 
 846         updateWindows(tmpDirtyComponents);
 847 
 848         tmpDirtyComponents.clear();
 849     }
 850 
 851 
 852     /**
 853      * Removes any components from roots that are children of
 854      * root.
 855      */
 856     private void adjustRoots(JComponent root,
 857                              java.util.List<Component> roots, int index) {
 858         for (int i = roots.size() - 1; i >= index; i--) {
 859             Component c = roots.get(i);
 860             for(;;) {