summaryrefslogtreecommitdiffstats
path: root/libjava/classpath/javax/swing/RepaintManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/RepaintManager.java')
-rw-r--r--libjava/classpath/javax/swing/RepaintManager.java292
1 files changed, 202 insertions, 90 deletions
diff --git a/libjava/classpath/javax/swing/RepaintManager.java b/libjava/classpath/javax/swing/RepaintManager.java
index 698dbe8e898..b857b126180 100644
--- a/libjava/classpath/javax/swing/RepaintManager.java
+++ b/libjava/classpath/javax/swing/RepaintManager.java
@@ -1,5 +1,5 @@
/* RepaintManager.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -43,12 +43,11 @@ import java.awt.Dimension;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.VolatileImage;
-import java.util.Enumeration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
-import java.util.Hashtable;
import java.util.Iterator;
-import java.util.Map;
-import java.util.Vector;
/**
* <p>The repaint manager holds a set of dirty regions, invalid components,
@@ -66,7 +65,11 @@ import java.util.Vector;
*/
public class RepaintManager
{
-
+ /**
+ * The current repaint managers, indexed by their ThreadGroups.
+ */
+ static HashMap currentRepaintManagers;
+
/**
* <p>A helper class which is placed into the system event queue at
* various times in order to facilitate repainting and layout. There is
@@ -80,33 +83,95 @@ public class RepaintManager
* swing paint thread, which revalidates all invalid components and
* repaints any damage in the swing scene.</p>
*/
-
protected class RepaintWorker
implements Runnable
{
+
boolean live;
+
public RepaintWorker()
{
live = false;
}
+
public synchronized void setLive(boolean b)
{
live = b;
}
+
public synchronized boolean isLive()
{
return live;
}
+
public void run()
{
- RepaintManager rm = RepaintManager.globalManager;
+ ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
+ RepaintManager rm =
+ (RepaintManager) currentRepaintManagers.get(threadGroup);
setLive(false);
rm.validateInvalidComponents();
rm.paintDirtyRegions();
}
+
+ }
+
+ /**
+ * Compares two components using their depths in the component hierarchy.
+ * A component with a lesser depth (higher level components) are sorted
+ * before components with a deeper depth (low level components). This is used
+ * to order paint requests, so that the higher level components are painted
+ * before the low level components get painted.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+ private class ComponentComparator implements Comparator
+ {
+
+ /**
+ * Compares two components.
+ *
+ * @param o1 the first component
+ * @param o2 the second component
+ *
+ * @return a negative integer, if <code>o1</code> is higher in the
+ * hierarchy than <code>o2</code>, zero, if both are at the same
+ * level and a positive integer, if <code>o1</code> is deeper in
+ * the hierarchy than <code>o2</code>
+ */
+ public int compare(Object o1, Object o2)
+ {
+ if (o1 instanceof JComponent && o2 instanceof JComponent)
+ {
+ JComponent c1 = (JComponent) o1;
+ JComponent c2 = (JComponent) o2;
+ return getDepth(c1) - getDepth(c2);
+ }
+ else
+ throw new ClassCastException("This comparator can only be used with "
+ + "JComponents");
+ }
+
+ /**
+ * Computes the depth for a given JComponent.
+ *
+ * @param c the component to compute the depth for
+ *
+ * @return the depth of the component
+ */
+ private int getDepth(JComponent c)
+ {
+ Component comp = c;
+ int depth = 0;
+ while (comp != null)
+ {
+ comp = comp.getParent();
+ depth++;
+ }
+ return depth;
+ }
}
-
/**
* A table storing the dirty regions of components. The keys of this
* table are components, the values are rectangles. Each component maps
@@ -119,7 +184,20 @@ public class RepaintManager
* @see #markCompletelyClean
* @see #markCompletelyDirty
*/
- Hashtable dirtyComponents;
+ HashMap dirtyComponents;
+
+ HashMap workDirtyComponents;
+
+ /**
+ * Stores the order in which the components get repainted.
+ */
+ ArrayList repaintOrder;
+ ArrayList workRepaintOrder;
+
+ /**
+ * The comparator used for ordered inserting into the repaintOrder list.
+ */
+ Comparator comparator;
/**
* A single, shared instance of the helper class. Any methods which mark
@@ -142,14 +220,15 @@ public class RepaintManager
* @see #removeInvalidComponent
* @see #validateInvalidComponents
*/
- Vector invalidComponents;
+ ArrayList invalidComponents;
+ ArrayList workInvalidComponents;
/**
* Whether or not double buffering is enabled on this repaint
* manager. This is merely a hint to clients; the RepaintManager will
* always return an offscreen buffer when one is requested.
*
- * @see #getDoubleBufferingEnabled
+ * @see #isDoubleBufferingEnabled
* @see #setDoubleBufferingEnabled
*/
boolean doubleBufferingEnabled;
@@ -176,53 +255,62 @@ public class RepaintManager
/**
- * The global, shared RepaintManager instance. This is reused for all
- * components in all windows. This is package-private to avoid an accessor
- * method.
- *
- * @see #currentManager
- * @see #setCurrentManager
- */
- static RepaintManager globalManager;
-
- /**
* Create a new RepaintManager object.
*/
public RepaintManager()
{
- dirtyComponents = new Hashtable();
- invalidComponents = new Vector();
+ dirtyComponents = new HashMap();
+ workDirtyComponents = new HashMap();
+ repaintOrder = new ArrayList();
+ workRepaintOrder = new ArrayList();
+ invalidComponents = new ArrayList();
+ workInvalidComponents = new ArrayList();
repaintWorker = new RepaintWorker();
doubleBufferMaximumSize = new Dimension(2000,2000);
doubleBufferingEnabled = true;
}
/**
- * Get the value of the shared {@link #globalManager} instance, possibly
- * returning a special manager associated with the specified
- * component. The default implementaiton ignores the component parameter.
+ * Returns the <code>RepaintManager</code> for the current thread's
+ * thread group. The default implementation ignores the
+ * <code>component</code> parameter and returns the same repaint manager
+ * for all components.
*
- * @param component A component to look up the manager of
+ * @param component a component to look up the manager of
*
- * @return The current repaint manager
+ * @return the current repaint manager for the calling thread's thread group
+ * and the specified component
*
* @see #setCurrentManager
*/
public static RepaintManager currentManager(Component component)
{
- if (globalManager == null)
- globalManager = new RepaintManager();
- return globalManager;
+ if (currentRepaintManagers == null)
+ currentRepaintManagers = new HashMap();
+ ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
+ RepaintManager currentManager =
+ (RepaintManager) currentRepaintManagers.get(threadGroup);
+ if (currentManager == null)
+ {
+ currentManager = new RepaintManager();
+ currentRepaintManagers.put(threadGroup, currentManager);
+ }
+ return currentManager;
}
/**
- * Get the value of the shared {@link #globalManager} instance, possibly
- * returning a special manager associated with the specified
- * component. The default implementaiton ignores the component parameter.
+ * Returns the <code>RepaintManager</code> for the current thread's
+ * thread group. The default implementation ignores the
+ * <code>component</code> parameter and returns the same repaint manager
+ * for all components.
*
- * @param component A component to look up the manager of
+ * This method is only here for backwards compatibility with older versions
+ * of Swing and simply forwards to {@link #currentManager(Component)}.
*
- * @return The current repaint manager
+ * @param component a component to look up the manager of
+ *
+ * @return the current repaint manager for the calling thread's thread group
+ * and the specified component
*
* @see #setCurrentManager
*/
@@ -232,15 +320,20 @@ public class RepaintManager
}
/**
- * Set the value of the shared {@link #globalManager} instance.
+ * Sets the repaint manager for the calling thread's thread group.
*
- * @param manager The new value of the shared instance
+ * @param manager the repaint manager to set for the current thread's thread
+ * group
*
- * @see #currentManager(JComponent)
+ * @see #currentManager(Component)
*/
public static void setCurrentManager(RepaintManager manager)
{
- globalManager = manager;
+ if (currentRepaintManagers == null)
+ currentRepaintManagers = new HashMap();
+
+ ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
+ currentRepaintManagers.put(threadGroup, manager);
}
/**
@@ -287,7 +380,7 @@ public class RepaintManager
*/
public synchronized void removeInvalidComponent(JComponent component)
{
- invalidComponents.removeElement(component);
+ invalidComponents.remove(component);
}
/**
@@ -311,12 +404,13 @@ public class RepaintManager
public synchronized void addDirtyRegion(JComponent component, int x, int y,
int w, int h)
{
- if (w == 0 || h == 0)
+ if (w == 0 || h == 0 || !component.isShowing())
return;
-
Rectangle r = new Rectangle(x, y, w, h);
if (dirtyComponents.containsKey(component))
r = r.union((Rectangle)dirtyComponents.get(component));
+ else
+ insertInRepaintOrder(component);
dirtyComponents.put(component, r);
if (! repaintWorker.isLive())
{
@@ -324,7 +418,23 @@ public class RepaintManager
SwingUtilities.invokeLater(repaintWorker);
}
}
-
+
+ /**
+ * Inserts a component into the repaintOrder list in an ordered fashion,
+ * using a binary search.
+ *
+ * @param c the component to be inserted
+ */
+ private void insertInRepaintOrder(JComponent c)
+ {
+ if (comparator == null)
+ comparator = new ComponentComparator();
+ int insertIndex = Collections.binarySearch(repaintOrder, c, comparator);
+ if (insertIndex < 0)
+ insertIndex = -(insertIndex + 1);
+ repaintOrder.add(insertIndex, c);
+ }
+
/**
* Get the dirty region associated with a component, or <code>null</code>
* if the component has no dirty region.
@@ -341,7 +451,10 @@ public class RepaintManager
*/
public Rectangle getDirtyRegion(JComponent component)
{
- return (Rectangle) dirtyComponents.get(component);
+ Rectangle dirty = (Rectangle) dirtyComponents.get(component);
+ if (dirty == null)
+ dirty = new Rectangle();
+ return dirty;
}
/**
@@ -359,6 +472,7 @@ public class RepaintManager
{
Rectangle r = component.getBounds();
addDirtyRegion(component, r.x, r.y, r.width, r.height);
+ component.isCompletelyDirty = true;
}
/**
@@ -374,7 +488,11 @@ public class RepaintManager
*/
public void markCompletelyClean(JComponent component)
{
- dirtyComponents.remove(component);
+ synchronized (this)
+ {
+ dirtyComponents.remove(component);
+ }
+ component.isCompletelyDirty = false;
}
/**
@@ -393,13 +511,9 @@ public class RepaintManager
*/
public boolean isCompletelyDirty(JComponent component)
{
- Rectangle dirty = (Rectangle) dirtyComponents.get(component);
- if (dirty == null)
+ if (! dirtyComponents.containsKey(component))
return false;
- Rectangle r = component.getBounds();
- if (r == null)
- return true;
- return dirty.contains(r);
+ return component.isCompletelyDirty;
}
/**
@@ -408,58 +522,56 @@ public class RepaintManager
*/
public void validateInvalidComponents()
{
- for (Enumeration e = invalidComponents.elements(); e.hasMoreElements(); )
+ // In order to keep the blocking of application threads minimal, we switch
+ // the invalidComponents field with the workInvalidComponents field and
+ // work with the workInvalidComponents field.
+ synchronized(this)
+ {
+ ArrayList swap = invalidComponents;
+ invalidComponents = workInvalidComponents;
+ workInvalidComponents = swap;
+ }
+ for (Iterator i = workInvalidComponents.iterator(); i.hasNext(); )
{
- JComponent comp = (JComponent) e.nextElement();
+ JComponent comp = (JComponent) i.next();
if (! (comp.isVisible() && comp.isShowing()))
continue;
comp.validate();
}
- invalidComponents.clear();
+ workInvalidComponents.clear();
}
/**
* Repaint all regions of all components which have been marked dirty in
* the {@link #dirtyComponents} table.
*/
- public void paintDirtyRegions()
+ public synchronized void paintDirtyRegions()
{
- // step 1: pull out roots and calculate spanning damage
-
- HashMap roots = new HashMap();
- for (Enumeration e = dirtyComponents.keys(); e.hasMoreElements(); )
+ // In order to keep the blocking of application threads minimal, we switch
+ // the dirtyComponents field with the workdirtyComponents field and the
+ // repaintOrder field with the workRepaintOrder field and work with the
+ // work* fields.
+ synchronized(this)
+ {
+ ArrayList swap = workRepaintOrder;
+ workRepaintOrder = repaintOrder;
+ repaintOrder = swap;
+ HashMap swap2 = workDirtyComponents;
+ workDirtyComponents = dirtyComponents;
+ dirtyComponents = swap2;
+ }
+ for (Iterator i = workRepaintOrder.iterator(); i.hasNext();)
{
- JComponent comp = (JComponent) e.nextElement();
- if (! (comp.isVisible() && comp.isShowing()))
- continue;
- Rectangle damaged = getDirtyRegion(comp);
- if (damaged.width == 0 || damaged.height == 0)
+ JComponent comp = (JComponent) i.next();
+ // If a component is marked completely clean in the meantime, then skip
+ // it.
+ Rectangle damaged = (Rectangle) workDirtyComponents.get(comp);
+ if (damaged == null || damaged.isEmpty())
continue;
- JRootPane root = comp.getRootPane();
- // If the component has no root, no repainting will occur.
- if (root == null)
- continue;
- Rectangle rootDamage = SwingUtilities.convertRectangle(comp, damaged, root);
- if (! roots.containsKey(root))
- {
- roots.put(root, rootDamage);
- }
- else
- {
- roots.put(root, ((Rectangle)roots.get(root)).union(rootDamage));
- }
- }
- dirtyComponents.clear();
-
- // step 2: paint those roots
- Iterator i = roots.entrySet().iterator();
- while(i.hasNext())
- {
- Map.Entry ent = (Map.Entry) i.next();
- JRootPane root = (JRootPane) ent.getKey();
- Rectangle rect = (Rectangle) ent.getValue();
- root.paintImmediately(rect);
+ comp.paintImmediately(damaged);
}
+ workRepaintOrder.clear();
+ workDirtyComponents.clear();
}
/**
OpenPOWER on IntegriCloud