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(;;) {
|