This fixes two issues with the RepaintManager:
- In addDirtyRegion() we need to protect the dirtyComponents data
structure a little more to avoid threading issues.
- The RepaintWorkerEvent class needs to have to dispatch() method
declared to allow applications to play dirty reflection tricks on it.
Yes I have such an app here :-(

2006-10-18  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/RepaintManager.java
        (RepaintWorkerEvent): Pass full set of params to super.
        (RepaintWorker.dispatch): Overridden to allow apps to call this
        via reflection.
        (addDirtyRegion): Synchronize a little more to protect the
        dirtyComponents field and avoid NPEs.
        (invokeLater): Pass full set of params to RepaintWorkerEvent
        constructor.
Index: javax/swing/RepaintManager.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/RepaintManager.java,v
retrieving revision 1.46
diff -u -1 -5 -r1.46 RepaintManager.java
--- javax/swing/RepaintManager.java	27 Sep 2006 20:17:27 -0000	1.46
+++ javax/swing/RepaintManager.java	18 Oct 2006 10:00:39 -0000
@@ -57,60 +57,73 @@
 import java.util.Iterator;
 import java.util.Set;
 import java.util.WeakHashMap;
 
 /**
  * <p>The repaint manager holds a set of dirty regions, invalid components,
  * and a double buffer surface.  The dirty regions and invalid components
  * are used to coalesce multiple revalidate() and repaint() calls in the
  * component tree into larger groups to be refreshed "all at once"; the
  * double buffer surface is used by root components to paint
  * themselves.</p>
  *
  * <p>See <a
  * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html";>this
  * document</a> for more details.</p>
+ * document</a> for more details.</p>
  *
  * @author Roman Kennke ([EMAIL PROTECTED])
  * @author Graydon Hoare ([EMAIL PROTECTED])
  * @author Audrius Meskauskas ([EMAIL PROTECTED])
  */
 public class RepaintManager
 {
   /**
    * An InvocationEvent subclass that implements LowPriorityEvent. This is used
    * to defer the execution of RepaintManager requests as long as possible on
    * the event queue. This way we make sure that all available input is
    * processed before getting active with the RepaintManager. This allows
    * for better optimization (more validate and repaint requests can be
    * coalesced) and thus has a positive effect on performance for GUI
    * applications under heavy load.
    */
   private static class RepaintWorkerEvent
     extends InvocationEvent
     implements LowPriorityEvent
   {
 
     /**
      * Creates a new RepaintManager event.
      *
      * @param source the source
      * @param runnable the runnable to execute
      */
-    public RepaintWorkerEvent(Object source, Runnable runnable)
+    public RepaintWorkerEvent(Object source, Runnable runnable,
+                              Object notifier, boolean catchEx)
     {
-      super(source, runnable);
+      super(source, runnable, notifier, catchEx);
+    }
+
+    /**
+     * An application that I met implements its own event dispatching and
+     * calls dispatch() via reflection, and only checks declared methods,
+     * that is, it expects this method to be in the event's class, not
+     * in a superclass. So I put this in here... sigh.
+     */
+    public void dispatch()
+    {
+      super.dispatch();
     }
   }
   
   /**
    * The current repaint managers, indexed by their ThreadGroups.
    */
   static WeakHashMap currentRepaintManagers;
 
   /**
    * A rectangle object to be reused in damaged regions calculation.
    */
   private static Rectangle rectCache = new Rectangle();
 
   /**
    * <p>A helper class which is placed into the system event queue at
@@ -407,39 +420,40 @@
    * @see #isCompletelyDirty
    * @see #markCompletelyClean
    * @see #markCompletelyDirty
    */
   public void addDirtyRegion(JComponent component, int x, int y,
                              int w, int h)
   {
     if (w <= 0 || h <= 0 || !component.isShowing())
       return;
 
     component.computeVisibleRect(rectCache);
     SwingUtilities.computeIntersection(x, y, w, h, rectCache);
 
     if (! rectCache.isEmpty())
       {
-        if (dirtyComponents.containsKey(component))
+        synchronized (dirtyComponents)
           {
-            SwingUtilities.computeUnion(rectCache.x, rectCache.y,
-                                        rectCache.width, rectCache.height,
-                                   (Rectangle) dirtyComponents.get(component));
-          }
-        else
-          {
-            synchronized (dirtyComponents)
+            Rectangle dirtyRect = (Rectangle)dirtyComponents.get(component);
+            if (dirtyRect != null)
+              {
+                SwingUtilities.computeUnion(rectCache.x, rectCache.y,
+                                            rectCache.width, rectCache.height,
+                                            dirtyRect);
+              }
+            else
               {
                 dirtyComponents.put(component, rectCache.getBounds());
               }
           }
 
         if (! repaintWorker.isLive())
           {
             repaintWorker.setLive(true);
             invokeLater(repaintWorker);
           }
       }
   }
 
   /**
    * Get the dirty region associated with a component, or <code>null</code>
@@ -826,19 +840,19 @@
   public String toString()
   {
     return "RepaintManager";
   }
 
   /**
    * Sends an RepaintManagerEvent to the event queue with the specified
    * runnable. This is similar to SwingUtilities.invokeLater(), only that the
    * event is a low priority event in order to defer the execution a little
    * more.
    */
   private void invokeLater(Runnable runnable)
   {
     Toolkit tk = Toolkit.getDefaultToolkit();
     EventQueue evQueue = tk.getSystemEventQueue();
-    InvocationEvent ev = new RepaintWorkerEvent(this, runnable);
+    InvocationEvent ev = new RepaintWorkerEvent(evQueue, runnable, null, false);
     evQueue.postEvent(ev);
   }
 }

Reply via email to