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);
}
}