OSDN Git Service

libjava/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / awt / Component.java
index dbbec8a..44676ba 100644 (file)
@@ -39,6 +39,12 @@ exception statement from your version. */
 
 package java.awt;
 
+//import gnu.java.awt.dnd.peer.gtk.GtkDropTargetContextPeer;
+
+import gnu.java.awt.ComponentReshapeEvent;
+
+import gnu.java.lang.CPStringBuilder;
+
 import java.awt.dnd.DropTarget;
 import java.awt.event.ActionEvent;
 import java.awt.event.AdjustmentEvent;
@@ -70,6 +76,7 @@ import java.awt.image.ImageProducer;
 import java.awt.image.VolatileImage;
 import java.awt.peer.ComponentPeer;
 import java.awt.peer.LightweightPeer;
+import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.io.IOException;
@@ -170,7 +177,7 @@ public abstract class Component
   /**
    * Constant returned by the <code>getAlignmentY</code> and
    * <code>getAlignmentX</code> methods to indicate
-   * that the component wishes to be aligned to the center relative to
+   * that the component wishes to be aligned to the centdisper relative to
    * other components.
    *
    * @see #getAlignmentX()
@@ -213,6 +220,12 @@ public abstract class Component
    */
   static final Object treeLock = new String("AWT_TREE_LOCK");
 
+  /**
+   * The default maximum size.
+   */
+  private static final Dimension DEFAULT_MAX_SIZE 
+                             = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
+
   // Serialized fields from the serialization spec.
 
   /**
@@ -427,6 +440,24 @@ public abstract class Component
   Dimension minSize;
 
   /**
+   * Flag indicating whether the minimum size for the component has been set
+   * by a call to {@link #setMinimumSize(Dimension)} with a non-null value.
+   */
+  boolean minSizeSet;
+  
+  /**
+   * The maximum size for the component.
+   * @see #setMaximumSize(Dimension)
+   */
+  Dimension maxSize;
+  
+  /**
+   * A flag indicating whether the maximum size for the component has been set
+   * by a call to {@link #setMaximumSize(Dimension)} with a non-null value.
+   */
+  boolean maxSizeSet;
+  
+  /**
    * Cached information on the preferred size. Should have been transient.
    *
    * @serial ignore
@@ -434,6 +465,12 @@ public abstract class Component
   Dimension prefSize;
 
   /**
+   * Flag indicating whether the preferred size for the component has been set
+   * by a call to {@link #setPreferredSize(Dimension)} with a non-null value.
+   */
+  boolean prefSizeSet;
+
+  /**
    * Set to true if an event is to be handled by this component, false if
    * it is to be passed up the hierarcy.
    *
@@ -546,7 +583,7 @@ public abstract class Component
   transient ComponentPeer peer;
 
   /** The preferred component orientation. */
-  transient ComponentOrientation orientation = ComponentOrientation.UNKNOWN;
+  transient ComponentOrientation componentOrientation = ComponentOrientation.UNKNOWN;
 
   /**
    * The associated graphics configuration.
@@ -563,6 +600,17 @@ public abstract class Component
   transient BufferStrategy bufferStrategy;
 
   /**
+   * The number of hierarchy listeners of this container plus all of its
+   * children. This is needed for efficient handling of HierarchyEvents.
+   * These must be propagated to all child components with HierarchyListeners
+   * attached. To avoid traversal of the whole subtree, we keep track of
+   * the number of HierarchyListeners here and only walk the paths that
+   * actually have listeners.
+   */
+  int numHierarchyListeners;
+  int numHierarchyBoundsListeners;
+
+  /**
    * true if requestFocus was called on this component when its
    * top-level ancestor was not focusable.
    */
@@ -607,16 +655,19 @@ public abstract class Component
   }
 
   /**
-   * Sets the name of this component to the specified name.
+   * Sets the name of this component to the specified name (this is a bound
+   * property with the name 'name').
    *
-   * @param name the new name of this component
+   * @param name the new name (<code>null</code> permitted).
    * @see #getName()
    * @since 1.1
    */
   public void setName(String name)
   {
     nameExplicitlySet = true;
+    String old = this.name;
     this.name = name;
+    firePropertyChange("name", old, name);
   }
 
   /**
@@ -653,6 +704,9 @@ public abstract class Component
   public void setDropTarget(DropTarget dt)
   {
     this.dropTarget = dt;
+    
+    if (peer != null)
+      dropTarget.addNotify(peer);
   }
 
   /**
@@ -674,7 +728,23 @@ public abstract class Component
    */
   public GraphicsConfiguration getGraphicsConfiguration()
   {
-    return getGraphicsConfigurationImpl();
+    GraphicsConfiguration conf = null;
+    synchronized (getTreeLock())
+      {
+        if (graphicsConfig != null)
+          {
+            conf = graphicsConfig;
+          }
+        else
+          {
+            Component par = getParent();
+            if (par != null)
+              {
+                conf = parent.getGraphicsConfiguration();
+              }
+          }
+      }
+    return conf;
   }
 
   /**
@@ -696,16 +766,23 @@ public abstract class Component
    */
   public Toolkit getToolkit()
   {
-    if (peer != null)
+    // Only heavyweight peers can handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
       {
-        Toolkit tk = peer.getToolkit();
-        if (tk != null)
-          return tk;
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
       }
-    // Get toolkit for lightweight component.
-    if (parent != null)
-      return parent.getToolkit();
-    return Toolkit.getDefaultToolkit();
+
+    Toolkit tk = null;
+    if (p != null)
+      {
+        tk = peer.getToolkit();
+      }
+    if (tk == null)
+      tk = Toolkit.getDefaultToolkit();
+    return tk;
   }
 
   /**
@@ -718,7 +795,9 @@ public abstract class Component
    */
   public boolean isValid()
   {
-    return valid;
+    // Tests show that components are invalid as long as they are not showing, even after validate()
+    // has been called on them.
+    return peer != null && valid;
   }
 
   /**
@@ -762,10 +841,8 @@ public abstract class Component
    */
   public boolean isShowing()
   {
-    if (! visible || peer == null)
-      return false;
-
-    return parent == null ? false : parent.isShowing();
+    Component par = parent;
+    return visible && peer != null && (par == null || par.isShowing());
   }
 
   /**
@@ -804,9 +881,17 @@ public abstract class Component
    */
   public void enable()
   {
-    this.enabled = true;
-    if (peer != null)
-      peer.setEnabled (true);
+    if (! enabled)
+      {
+        // Need to lock the tree here, because the peers are involved.
+        synchronized (getTreeLock())
+          {
+            enabled = true;
+            ComponentPeer p = peer;
+            if (p != null)
+              p.enable();
+          }
+      }
   }
 
   /**
@@ -831,9 +916,17 @@ public abstract class Component
    */
   public void disable()
   {
-    this.enabled = false;
-    if (peer != null)
-      peer.setEnabled (false);
+    if (enabled)
+      {
+        // Need to lock the tree here, because the peers are involved.
+        synchronized (getTreeLock())
+          {
+            enabled = false;
+            ComponentPeer p = peer;
+            if (p != null)
+              p.disable();
+          }
+      }
   }
 
   /**
@@ -896,18 +989,40 @@ public abstract class Component
     // case lightweight components are not initially painted --
     // Container.paint first calls isShowing () before painting itself
     // and its children.
-    if(!isVisible())
+    if(! visible)
       {
-        this.visible = true;
-        // Avoid NullPointerExceptions by creating a local reference.
-        ComponentPeer currentPeer=peer;
-        if (currentPeer != null)
-            currentPeer.show();
-
-        // The JDK repaints the component before invalidating the parent.
-        // So do we.
-        if (isShowing() && isLightweight())
-          repaint();
+        // Need to lock the tree here to avoid races and inconsistencies.
+        synchronized (getTreeLock())
+          {
+            visible = true;
+            // Avoid NullPointerExceptions by creating a local reference.
+            ComponentPeer currentPeer = peer;
+            if (currentPeer != null)
+              {
+                currentPeer.show();
+
+                // Fire HierarchyEvent.
+                fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED,
+                                   this, parent,
+                                   HierarchyEvent.SHOWING_CHANGED);
+
+                // The JDK repaints the component before invalidating the parent.
+                // So do we.
+                if (peer instanceof LightweightPeer)
+                  repaint();
+              }
+
+            // Only post an event if this component actually has a listener
+            // or has this event explicitly enabled.
+            if (componentListener != null
+                || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
+              {
+                ComponentEvent ce =
+                  new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN);
+                getToolkit().getSystemEventQueue().postEvent(ce);
+              }
+          }
+
         // Invalidate the parent if we have one. The component itself must
         // not be invalidated. We also avoid NullPointerException with
         // a local reference here.
@@ -915,9 +1030,6 @@ public abstract class Component
         if (currentParent != null)
           currentParent.invalidate();
 
-        ComponentEvent ce =
-          new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN);
-        getToolkit().getSystemEventQueue().postEvent(ce);
       }
   }
 
@@ -943,29 +1055,47 @@ public abstract class Component
    */
   public void hide()
   {
-    if (isVisible())
+    if (visible)
       {
-        // Avoid NullPointerExceptions by creating a local reference.
-        ComponentPeer currentPeer=peer;
-        if (currentPeer != null)
-            currentPeer.setVisible(false);
-        boolean wasShowing = isShowing();
-        this.visible = false;
-
-        // The JDK repaints the component before invalidating the parent.
-        // So do we.
-        if (wasShowing)
-          repaint();
-        // Invalidate the parent if we have one. The component itself must
+        // Need to lock the tree here to avoid races and inconsistencies.
+        synchronized (getTreeLock())
+          {
+            visible = false;
+
+            // Avoid NullPointerExceptions by creating a local reference.
+            ComponentPeer currentPeer = peer;
+            if (currentPeer != null)
+              {
+                currentPeer.hide();
+
+                // Fire hierarchy event.
+                fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED,
+                                   this, parent,
+                                   HierarchyEvent.SHOWING_CHANGED);
+                // The JDK repaints the component before invalidating the
+                // parent. So do we. This only applies for lightweights.
+                if (peer instanceof LightweightPeer)
+                  repaint();
+              }
+
+            // Only post an event if this component actually has a listener
+            // or has this event explicitly enabled.
+            if (componentListener != null
+                || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
+              {
+                ComponentEvent ce =
+                  new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN);
+                getToolkit().getSystemEventQueue().postEvent(ce);
+              }
+          }
+
+        // Invalidate the parent if we have one. The component itself need
         // not be invalidated. We also avoid NullPointerException with
         // a local reference here.
         Container currentParent = parent;
         if (currentParent != null)
           currentParent.invalidate();
 
-        ComponentEvent ce =
-          new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN);
-        getToolkit().getSystemEventQueue().postEvent(ce);
       }
   }
 
@@ -1068,36 +1198,80 @@ public abstract class Component
    */
   public Font getFont()
   {
-    Font f = font;
-    if (f != null)
-      return f;
+    return getFontImpl();
+  }
 
-    Component p = parent;
-    if (p != null)
-      return p.getFont();
-    return null;
+  /**
+   * Implementation of getFont(). This is pulled out of getFont() to prevent
+   * client programs from overriding this.
+   *
+   * @return the font of this component
+   */
+  private final Font getFontImpl()
+  {
+    Font f = font;
+    if (f == null)
+      {
+        Component p = parent;
+        if (p != null)
+          f = p.getFontImpl();
+        else
+          {
+            // It is important to return null here and not some kind of default
+            // font, otherwise the Swing UI would not install its fonts because
+            // it keeps non-UIResource fonts.
+            f = null;
+          }
+      }
+    return f;
   }
 
   /**
    * Sets the font for this component to the specified font. This is a bound
    * property.
    *
-   * @param newFont the new font for this component
+   * @param f the new font for this component
    * 
    * @see #getFont()
    */
-  public void setFont(Font newFont)
+  public void setFont(Font f)
   {
-    if((newFont != null && (font == null || !font.equals(newFont)))
-       || newFont == null)
+    Font oldFont;
+    Font newFont;
+    // Synchronize on the tree because getFontImpl() relies on the hierarchy
+    // not beeing changed.
+    synchronized (getTreeLock())
       {
-        Font oldFont = font;
-        font = newFont;
-        if (peer != null)
-          peer.setFont(font);
-        firePropertyChange("font", oldFont, newFont);
-        invalidate();
+        // Synchronize on this here to guarantee thread safety wrt to the
+        // property values.
+        synchronized (this)
+          {
+            oldFont = font;
+            font = f;
+            newFont = f;
+          }
+        // Create local variable here for thread safety.
+        ComponentPeer p = peer;
+        if (p != null)
+          {
+            // The peer receives the real font setting, which can depend on 
+            // the parent font when this component's font has been set to null.
+            f = getFont();
+            if (f != null)
+              {
+                p.setFont(f);
+                peerFont = f;
+              }
+          }
       }
+
+    // Fire property change event.
+    firePropertyChange("font", oldFont, newFont);
+
+    // Invalidate when necessary as font changes can change the size of the
+    // component.
+    if (valid)
+      invalidate();
   }
 
   /**
@@ -1189,8 +1363,33 @@ public abstract class Component
       throw new IllegalComponentStateException("component "
                                                + getClass().getName()
                                                + " not showing");
-    // We know peer != null here.
-    return peer.getLocationOnScreen();
+
+    // Need to lock the tree here. We get crazy races and explosions when
+    // the tree changes while we are trying to find the location of this
+    // component.
+    synchronized (getTreeLock())
+      {
+        // Only a heavyweight peer can answer the question for the screen
+        // location. So we are going through the hierarchy until we find
+        // one and add up the offsets while doing so.
+        int offsX = 0;
+        int offsY = 0;
+        ComponentPeer p = peer;
+        Component comp = this;
+        while (p instanceof LightweightPeer)
+          {
+            offsX += comp.x;
+            offsY += comp.y;
+            comp = comp.parent;
+            p = comp == null ? null: comp.peer;
+          }
+        // Now we have a heavyweight component.
+        assert ! (p instanceof LightweightPeer);
+        Point loc = p.getLocationOnScreen();
+        loc.x += offsX;
+        loc.y += offsY;
+        return loc;
+      }
   }
 
   /**
@@ -1384,53 +1583,81 @@ public abstract class Component
    */
   public void reshape(int x, int y, int width, int height)
   {
-    int oldx = this.x;
-    int oldy = this.y;
-    int oldwidth = this.width;
-    int oldheight = this.height;
+    // We need to lock the tree here, otherwise we risk races and
+    // inconsistencies.
+    synchronized (getTreeLock())
+      {
+        int oldx = this.x;
+        int oldy = this.y;
+        int oldwidth = this.width;
+        int oldheight = this.height;
     
-    if (this.x == x && this.y == y && this.width == width
-        && this.height == height)
-      return;
+        boolean resized = oldwidth != width || oldheight != height;
+        boolean moved = oldx != x || oldy != y;
 
-    invalidate();
-    
-    this.x = x;
-    this.y = y;
-    this.width = width;
-    this.height = height;
-    if (peer != null)
-      peer.setBounds (x, y, width, height);
-    
-    // Erase old bounds and repaint new bounds for lightweights.
-    if (isLightweight() && isShowing())
-      {
-        if (parent != null)
+        if (resized || moved)
           {
-            Rectangle oldBounds = new Rectangle(oldx, oldy, oldwidth,
-                                                oldheight);
-            Rectangle newBounds = new Rectangle(x, y, width, height);
-            Rectangle destroyed = oldBounds.union(newBounds);
-            if (!destroyed.isEmpty())
-              parent.repaint(0, destroyed.x, destroyed.y, destroyed.width,
-                             destroyed.height);
+            // Update the fields.
+            this.x = x;
+            this.y = y;
+            this.width = width;
+            this.height = height;
+
+            if (peer != null)
+              {
+                peer.setBounds (x, y, width, height);
+                if (resized)
+                  invalidate();
+                if (parent != null && parent.valid)
+                  parent.invalidate();
+              }
+
+            // Send some events to interested listeners.
+            notifyReshape(resized, moved);
+
+            // Repaint this component and the parent if appropriate.
+            if (parent != null && peer instanceof LightweightPeer
+                && isShowing())
+              {
+                // The parent repaints the area that we occupied before.
+                parent.repaint(oldx, oldy, oldwidth, oldheight);
+                // This component repaints the area that we occupy now.
+                repaint();
+              }
           }
       }
+  }
 
-    // Only post event if this component is visible and has changed size.
-    if (isShowing ()
-        && (oldx != x || oldy != y))
+  /**
+   * Sends notification to interested listeners about resizing and/or moving
+   * the component. If this component has interested
+   * component listeners or the corresponding event mask enabled, then
+   * COMPONENT_MOVED and/or COMPONENT_RESIZED events are posted to the event
+   * queue.
+   *
+   * @param resized true if the component has been resized, false otherwise
+   * @param moved true if the component has been moved, false otherwise
+   */
+  void notifyReshape(boolean resized, boolean moved)
+  {
+    // Only post an event if this component actually has a listener
+    // or has this event explicitly enabled.
+    if (componentListener != null
+        || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
       {
-        ComponentEvent ce = new ComponentEvent(this,
+        // Fire component event on this component.
+        if (moved)
+          {
+            ComponentEvent ce = new ComponentEvent(this,
                                                ComponentEvent.COMPONENT_MOVED);
-        getToolkit().getSystemEventQueue().postEvent(ce);
-      }
-    if (isShowing ()
-        && (oldwidth != width || oldheight != height))
-      {
-        ComponentEvent ce = new ComponentEvent(this,
-                                               ComponentEvent.COMPONENT_RESIZED);
-        getToolkit().getSystemEventQueue().postEvent(ce);
+            getToolkit().getSystemEventQueue().postEvent(ce);
+          }
+        if (resized)
+          {
+            ComponentEvent ce = new ComponentEvent(this,
+                                             ComponentEvent.COMPONENT_RESIZED);
+            getToolkit().getSystemEventQueue().postEvent(ce);
+          }
       }
   }
 
@@ -1584,6 +1811,7 @@ public abstract class Component
    *
    * @return the component's preferred size
    * @see #getMinimumSize()
+   * @see #setPreferredSize(Dimension)
    * @see LayoutManager
    */
   public Dimension getPreferredSize()
@@ -1592,6 +1820,40 @@ public abstract class Component
   }
 
   /**
+   * Sets the preferred size that will be returned by 
+   * {@link #getPreferredSize()} always, and sends a 
+   * {@link PropertyChangeEvent} (with the property name 'preferredSize') to 
+   * all registered listeners.
+   * 
+   * @param size  the preferred size (<code>null</code> permitted).
+   * 
+   * @since 1.5
+   * 
+   * @see #getPreferredSize()
+   */
+  public void setPreferredSize(Dimension size)
+  {
+    Dimension old = prefSizeSet ? prefSize : null;
+    prefSize = size;
+    prefSizeSet = (size != null);
+    firePropertyChange("preferredSize", old, size);
+  }
+  
+  /**
+   * Returns <code>true</code> if the current preferred size is not 
+   * <code>null</code> and was set by a call to 
+   * {@link #setPreferredSize(Dimension)}, otherwise returns <code>false</code>.
+   * 
+   * @return A boolean.
+   * 
+   * @since 1.5
+   */
+  public boolean isPreferredSizeSet()
+  {
+    return prefSizeSet;
+  }
+  
+  /**
    * Returns the component's preferred size.
    *
    * @return the component's preferred size
@@ -1599,14 +1861,36 @@ public abstract class Component
    */
   public Dimension preferredSize()
   {
-    if (prefSize == null)
+    // Create a new Dimension object, so that the application doesn't mess
+    // with the actual values.
+    return new Dimension(preferredSizeImpl());
+  }
+
+  /**
+   * The actual calculation is pulled out of preferredSize() so that
+   * we can call it from Container.preferredSize() and avoid creating a
+   * new intermediate Dimension object.
+   * 
+   * @return the preferredSize of the component
+   */
+  Dimension preferredSizeImpl()
+  {
+    Dimension size = prefSize;
+    // Try to use a cached value.
+    if (size == null || !(valid || prefSizeSet))
       {
-        if (peer == null)
-          prefSize = minimumSize();
-        else
-          prefSize = peer.getPreferredSize();
+        // We need to lock here, because the calculation depends on the
+        // component structure not changing.
+        synchronized (getTreeLock())
+          {
+            ComponentPeer p = peer;
+            if (p != null)
+              size = peer.preferredSize();
+            else
+              size = minimumSizeImpl();
+          }
       }
-    return prefSize;
+    return size;
   }
 
   /**
@@ -1614,6 +1898,7 @@ public abstract class Component
    * 
    * @return the component's minimum size
    * @see #getPreferredSize()
+   * @see #setMinimumSize(Dimension)
    * @see LayoutManager
    */
   public Dimension getMinimumSize()
@@ -1622,6 +1907,39 @@ public abstract class Component
   }
 
   /**
+   * Sets the minimum size that will be returned by {@link #getMinimumSize()}
+   * always, and sends a {@link PropertyChangeEvent} (with the property name
+   * 'minimumSize') to all registered listeners.
+   * 
+   * @param size  the minimum size (<code>null</code> permitted).
+   * 
+   * @since 1.5
+   * 
+   * @see #getMinimumSize()
+   */
+  public void setMinimumSize(Dimension size)
+  {
+    Dimension old = minSizeSet ? minSize : null;
+    minSize = size;
+    minSizeSet = (size != null);
+    firePropertyChange("minimumSize", old, size);
+  }
+  
+  /**
+   * Returns <code>true</code> if the current minimum size is not 
+   * <code>null</code> and was set by a call to 
+   * {@link #setMinimumSize(Dimension)}, otherwise returns <code>false</code>.
+   * 
+   * @return A boolean.
+   * 
+   * @since 1.5
+   */
+  public boolean isMinimumSizeSet()
+  {
+    return minSizeSet;
+  }
+  
+  /**
    * Returns the component's minimum size.
    *
    * @return the component's minimum size
@@ -1629,10 +1947,36 @@ public abstract class Component
    */
   public Dimension minimumSize()
   {
-    if (minSize == null)
-      minSize = (peer != null ? peer.getMinimumSize()
-                 : new Dimension(width, height));
-    return minSize;
+    // Create a new Dimension object, so that the application doesn't mess
+    // with the actual values.
+    return new Dimension(minimumSizeImpl());
+  }
+
+  /**
+   * The actual calculation is pulled out of minimumSize() so that
+   * we can call it from Container.preferredSize() and
+   * Component.preferredSizeImpl and avoid creating a
+   * new intermediate Dimension object.
+   * 
+   * @return the minimum size of the component
+   */
+  Dimension minimumSizeImpl()
+  {
+    Dimension size = minSize;
+    if (size == null || !(valid || minSizeSet))
+      {
+        // We need to lock here, because the calculation depends on the
+        // component structure not changing.
+        synchronized (getTreeLock())
+          {
+            ComponentPeer p = peer;
+            if (p != null)
+              size = peer.minimumSize();
+            else
+              size = size();
+          }
+      }
+    return size;
   }
 
   /**
@@ -1640,15 +1984,66 @@ public abstract class Component
    *
    * @return the component's maximum size
    * @see #getMinimumSize()
+   * @see #setMaximumSize(Dimension)
    * @see #getPreferredSize()
    * @see LayoutManager
    */
   public Dimension getMaximumSize()
   {
-    return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
+    return new Dimension(maximumSizeImpl());
+  }
+
+  /**
+   * This is pulled out from getMaximumSize(), so that we can access it
+   * from Container.getMaximumSize() without creating an additional
+   * intermediate Dimension object.
+   *
+   * @return the maximum size of the component
+   */
+  Dimension maximumSizeImpl()
+  {
+    Dimension size;
+    if (maxSizeSet)
+      size = maxSize;
+    else
+      size = DEFAULT_MAX_SIZE;
+    return size;
+  }
+
+  /**
+   * Sets the maximum size that will be returned by {@link #getMaximumSize()}
+   * always, and sends a {@link PropertyChangeEvent} (with the property name
+   * 'maximumSize') to all registered listeners.
+   * 
+   * @param size  the maximum size (<code>null</code> permitted).
+   * 
+   * @since 1.5
+   * 
+   * @see #getMaximumSize()
+   */
+  public void setMaximumSize(Dimension size)
+  {
+    Dimension old = maxSizeSet ? maxSize : null;
+    maxSize = size;
+    maxSizeSet = (size != null);
+    firePropertyChange("maximumSize", old, size);
   }
 
   /**
+   * Returns <code>true</code> if the current maximum size is not 
+   * <code>null</code> and was set by a call to 
+   * {@link #setMaximumSize(Dimension)}, otherwise returns <code>false</code>.
+   * 
+   * @return A boolean.
+   * 
+   * @since 1.5
+   */
+  public boolean isMaximumSizeSet()
+  {
+    return maxSizeSet;
+  }
+  
+  /**
    * Returns the preferred horizontal alignment of this component. The value
    * returned will be between {@link #LEFT_ALIGNMENT} and
    * {@link #RIGHT_ALIGNMENT}, inclusive.
@@ -1706,7 +2101,32 @@ public abstract class Component
    */
   public void validate()
   {
-    valid = true;
+    if (! valid)
+      {
+        // Synchronize on the tree here as this might change the layout
+        // of the hierarchy.
+        synchronized (getTreeLock())
+          {
+            // Create local variables for thread safety.
+            ComponentPeer p = peer;
+            if (p != null)
+              {
+                // Possibly update the peer's font.
+                Font newFont = getFont();
+                Font oldFont = peerFont;
+                // Only update when the font really changed.
+                if (newFont != oldFont
+                    && (oldFont == null || ! oldFont.equals(newFont)))
+                  {
+                    p.setFont(newFont);
+                    peerFont = newFont;
+                  }
+                // Let the peer perform any layout.
+                p.layout();
+              }
+          }
+        valid = true;
+      }
   }
 
   /**
@@ -1716,11 +2136,25 @@ public abstract class Component
    */
   public void invalidate()
   {
-    valid = false;
-    prefSize = null;
-    minSize = null;
-    if (parent != null && parent.isValid())
-      parent.invalidate();
+    // Need to lock here, to avoid races and other ugly stuff when doing
+    // layout or structure changes in other threads.
+    synchronized (getTreeLock())
+      {
+        // Invalidate.
+        valid = false;
+
+        // Throw away cached layout information.
+        if (! minSizeSet)
+          minSize = null;
+        if (! prefSizeSet)
+          prefSize = null;
+        if (! maxSizeSet)
+          maxSize = null;
+
+        // Also invalidate the parent, if it hasn't already been invalidated.
+        if (parent != null && parent.isValid())
+          parent.invalidate();
+      }
   }
 
   /**
@@ -1732,22 +2166,28 @@ public abstract class Component
    */
   public Graphics getGraphics()
   {
-    if (peer != null)
+    // Only heavyweight peers can handle this.
+    ComponentPeer p = peer;
+    Graphics g = null;
+    if (p instanceof LightweightPeer)
       {
-        Graphics gfx = peer.getGraphics();
-        // Create peer for lightweights.
-        if (gfx == null && parent != null)
+        if (parent != null)
           {
-            gfx = parent.getGraphics();
-            Rectangle bounds = getBounds();
-            gfx.setClip(bounds);
-            gfx.translate(bounds.x, bounds.y);
-            return gfx;
+            g = parent.getGraphics();
+            if (g != null)
+              {
+                g.translate(x, y);
+                g.setClip(0, 0, width, height);
+                g.setFont(getFont());
+              }
           }
-        gfx.setFont(font);
-        return gfx;
       }
-    return null;
+    else
+      {
+        if (p != null)
+          g = p.getGraphics();
+      }
+    return g;
   }
 
   /**
@@ -1761,8 +2201,16 @@ public abstract class Component
    */
   public FontMetrics getFontMetrics(Font font)
   {
-    return peer == null ? getToolkit().getFontMetrics(font)
-      : peer.getFontMetrics(font);
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
+    return p == null ? getToolkit().getFontMetrics(font)
+           : p.getFontMetrics(font);
   }
 
   /**
@@ -1781,8 +2229,18 @@ public abstract class Component
   public void setCursor(Cursor cursor)
   {
     this.cursor = cursor;
-    if (peer != null)
-      peer.setCursor(cursor);
+
+    // Only heavyweight peers handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
+    if (p != null)
+      p.setCursor(cursor);
   }
 
   /**
@@ -1827,11 +2285,9 @@ public abstract class Component
   }
 
   /**
-   * Updates this component. This is called in response to
-   * <code>repaint</code>. This method fills the component with the
-   * background color, then sets the foreground color of the specified
-   * graphics context to the foreground color of this component and calls
-   * the <code>paint()</code> method. The coordinates of the graphics are
+   * Updates this component. This is called for heavyweight components in
+   * response to {@link #repaint()}. The default implementation simply forwards
+   * to {@link #paint(Graphics)}. The coordinates of the graphics are
    * relative to this component. Subclasses should call either
    * <code>super.update(g)</code> or <code>paint(g)</code>.
    *
@@ -1839,27 +2295,17 @@ public abstract class Component
    *
    * @see #paint(Graphics)
    * @see #repaint()
-   *
-   * @specnote In contrast to what the spec says, tests show that the exact
-   *           behaviour is to clear the background on lightweight and
-   *           top-level components only. Heavyweight components are not
-   *           affected by this method and only call paint().
    */
   public void update(Graphics g)
   {
-    // Tests show that the clearing of the background is only done in
-    // two cases:
-    // - If the component is lightweight (yes this is in contrast to the spec).
-    // or
-    // - If the component is a toplevel container.
-    if (isLightweight() || getParent() == null)
-      {
-        Rectangle clip = g.getClipBounds();
-        if (clip == null)
-          g.clearRect(0, 0, width, height);
-        else
-          g.clearRect(clip.x, clip.y, clip.width, clip.height);
-      }
+    // Note 1: We used to clear the background here for lightweights and
+    // toplevel components. Tests show that this is not what the JDK does
+    // here. Note that there is some special handling and background
+    // clearing code in Container.update(Graphics).
+
+    // Note 2 (for peer implementors): The JDK doesn't seem call update() for
+    // toplevel components, even when an UPDATE event is sent (as a result
+    // of repaint).
     paint(g);
   }
 
@@ -1872,9 +2318,14 @@ public abstract class Component
    */
   public void paintAll(Graphics g)
   {
-    if (! visible)
-      return;
-    paint(g);
+    if (isShowing())
+      {
+        validate();
+        if (peer instanceof LightweightPeer)
+          paint(g);
+        else
+          peer.paint(g);
+      }
   }
 
   /**
@@ -1935,11 +2386,42 @@ public abstract class Component
    */
   public void repaint(long tm, int x, int y, int width, int height)
   {
-    if (isShowing())
+    // The repaint() call has previously been delegated to
+    // {@link ComponentPeer.repaint()}. Testing on the JDK using some
+    // dummy peers show that this methods is never called. I think it makes
+    // sense to actually perform the tasks below here, since it's pretty
+    // much peer independent anyway, and makes sure only heavyweights are
+    // bothered by this.
+    ComponentPeer p = peer;
+
+    // Let the nearest heavyweight parent handle repainting for lightweight
+    // components.
+    // We need to recursivly call repaint() on the parent here, since
+    // a (lightweight) parent component might have overridden repaint()
+    // to perform additional custom tasks.
+
+    if (p instanceof LightweightPeer)
       {
-        ComponentPeer p = peer;
-        if (p != null)
-          p.repaint(tm, x, y, width, height);
+        // We perform some boundary checking to restrict the paint
+        // region to this component.
+        if (parent != null)
+          {
+            int px = this.x + Math.max(0, x); 
+            int py = this.y + Math.max(0, y);
+            int pw = Math.min(this.width, width);
+            int ph = Math.min(this.height, height);
+            parent.repaint(tm, px, py, pw, ph);
+          }
+      }
+    else
+      {
+        // Now send an UPDATE event to the heavyweight component that we've found.
+        if (isVisible() && p != null && width > 0 && height > 0)
+          {
+            PaintEvent pe = new PaintEvent(this, PaintEvent.UPDATE,
+                                           new Rectangle(x, y, width, height));
+            getToolkit().getSystemEventQueue().postEvent(pe);
+          }
       }
   }
 
@@ -1958,10 +2440,7 @@ public abstract class Component
   }
 
   /**
-   * Prints this component, including all sub-components. This method is
-   * provided so that printing can be done in a different manner from
-   * painting. However, the implementation in this class simply calls the
-   * <code>paintAll()</code> method.
+   * Prints this component, including all sub-components. 
    *
    * @param g the graphics context of the print device
    * 
@@ -1969,7 +2448,9 @@ public abstract class Component
    */
   public void printAll(Graphics g)
   {
-    paintAll(g);
+    if( peer != null )
+      peer.print( g );
+    paintAll( g );
   }
 
   /**
@@ -2028,11 +2509,22 @@ public abstract class Component
    */
   public Image createImage(ImageProducer producer)
   {
+    // Only heavyweight peers can handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
     // Sun allows producer to be null.
-    if (peer != null)
-      return peer.createImage(producer);
+    Image im;
+    if (p != null)
+      im = p.createImage(producer);
     else
-      return getToolkit().createImage(producer);
+      im = getToolkit().createImage(producer);
+    return im;
   }
 
   /**
@@ -2048,10 +2540,17 @@ public abstract class Component
     Image returnValue = null;
     if (!GraphicsEnvironment.isHeadless ())
       {
-       if (isLightweight () && parent != null)
-         returnValue = parent.createImage (width, height);
-       else if (peer != null)
-         returnValue = peer.createImage (width, height);
+        // Only heavyweight peers can handle this.
+        ComponentPeer p = peer;
+        Component comp = this;
+        while (p instanceof LightweightPeer)
+          {
+            comp = comp.parent;
+            p = comp == null ? null : comp.peer;
+          }
+
+        if (p != null)
+          returnValue = p.createImage(width, height);
       }
     return returnValue;
   }
@@ -2067,11 +2566,19 @@ public abstract class Component
    */
   public VolatileImage createVolatileImage(int width, int height)
   {
-    if (GraphicsEnvironment.isHeadless())
-      return null;
-    GraphicsConfiguration config = getGraphicsConfiguration();
-    return config == null ? null
-      : config.createCompatibleVolatileImage(width, height);
+    // Only heavyweight peers can handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
+    VolatileImage im = null;
+    if (p != null)
+      im = p.createVolatileImage(width, height);
+    return im;
   }
 
   /**
@@ -2090,11 +2597,19 @@ public abstract class Component
                                            ImageCapabilities caps)
     throws AWTException
   {
-    if (GraphicsEnvironment.isHeadless())
-      return null;
-    GraphicsConfiguration config = getGraphicsConfiguration();
-    return config == null ? null
-      : config.createCompatibleVolatileImage(width, height, caps);
+    // Only heavyweight peers can handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
+    VolatileImage im = null;
+    if (p != null)
+      im = peer.createVolatileImage(width, height);
+    return im;
   }
 
   /**
@@ -2124,10 +2639,21 @@ public abstract class Component
   public boolean prepareImage(Image image, int width, int height,
                               ImageObserver observer)
   {
-    if (peer != null)
-       return peer.prepareImage(image, width, height, observer);
+    // Only heavyweight peers handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
+    boolean retval;
+    if (p != null)
+       retval = p.prepareImage(image, width, height, observer);
     else
-       return getToolkit().prepareImage(image, width, height, observer);
+       retval = getToolkit().prepareImage(image, width, height, observer);
+    return retval;
   }
 
   /**
@@ -2161,9 +2687,21 @@ public abstract class Component
   public int checkImage(Image image, int width, int height,
                         ImageObserver observer)
   {
-    if (peer != null)
-      return peer.checkImage(image, width, height, observer);
-    return getToolkit().checkImage(image, width, height, observer);
+    // Only heavyweight peers handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
+    int retval;
+    if (p != null)
+      retval = p.checkImage(image, width, height, observer);
+    else
+      retval = getToolkit().checkImage(image, width, height, observer);
+    return retval;
   }
 
   /**
@@ -2309,20 +2847,23 @@ public abstract class Component
    */
   public final void dispatchEvent(AWTEvent e)
   {
-    Event oldEvent = translateEvent(e);
-    if (oldEvent != null)
-      postEvent (oldEvent);
-
-    // Give toolkit a chance to dispatch the event
-    // to globally registered listeners.
-    Toolkit.getDefaultToolkit().globalDispatchEvent(e);
-
     // Some subclasses in the AWT package need to override this behavior,
     // hence the use of dispatchEventImpl().
     dispatchEventImpl(e);
   }
 
   /**
+   * By default, no old mouse events should be ignored.
+   * This can be overridden by subclasses.
+   * 
+   * @return false, no mouse events are ignored.
+   */
+  static boolean ignoreOldMouseEvents()
+  {
+    return false;
+  }
+  
+  /**
    * AWT 1.0 event handler.
    *
    * This method simply calls handleEvent and returns the result.
@@ -2356,9 +2897,12 @@ public abstract class Component
    */
   public synchronized void addComponentListener(ComponentListener listener)
   {
-    componentListener = AWTEventMulticaster.add(componentListener, listener);
-    if (componentListener != null)
-      enableEvents(AWTEvent.COMPONENT_EVENT_MASK);
+    if (listener != null)
+      {
+        componentListener = AWTEventMulticaster.add(componentListener,
+                                                    listener);
+        newEventsOnly = true;
+      }
   }
 
   /**
@@ -2404,9 +2948,11 @@ public abstract class Component
    */
   public synchronized void addFocusListener(FocusListener listener)
   {
-    focusListener = AWTEventMulticaster.add(focusListener, listener);
-    if (focusListener != null)
-      enableEvents(AWTEvent.FOCUS_EVENT_MASK);
+    if (listener != null)
+      {
+        focusListener = AWTEventMulticaster.add(focusListener, listener);
+        newEventsOnly = true;
+      }
   }
 
   /**
@@ -2451,9 +2997,20 @@ public abstract class Component
    */
   public synchronized void addHierarchyListener(HierarchyListener listener)
   {
-    hierarchyListener = AWTEventMulticaster.add(hierarchyListener, listener);
-    if (hierarchyListener != null)
-      enableEvents(AWTEvent.HIERARCHY_EVENT_MASK);
+    if (listener != null)
+      {
+        hierarchyListener = AWTEventMulticaster.add(hierarchyListener,
+                                                    listener);
+        newEventsOnly = true;
+        // Need to lock the tree, otherwise we might end up inconsistent.
+        synchronized (getTreeLock())
+        {
+          numHierarchyListeners++;
+          if (parent != null)
+            parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK,
+                                                1);
+        }
+      }
   }
 
   /**
@@ -2469,6 +3026,15 @@ public abstract class Component
   public synchronized void removeHierarchyListener(HierarchyListener listener)
   {
     hierarchyListener = AWTEventMulticaster.remove(hierarchyListener, listener);
+
+    // Need to lock the tree, otherwise we might end up inconsistent.
+    synchronized (getTreeLock())
+      {
+        numHierarchyListeners--;
+        if (parent != null)
+          parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK,
+                                              -1);
+      }
   }
 
   /**
@@ -2500,10 +3066,21 @@ public abstract class Component
   public synchronized void
     addHierarchyBoundsListener(HierarchyBoundsListener listener)
   {
-    hierarchyBoundsListener =
-      AWTEventMulticaster.add(hierarchyBoundsListener, listener);
-    if (hierarchyBoundsListener != null)
-      enableEvents(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK);
+    if (listener != null)
+      {
+        hierarchyBoundsListener =
+          AWTEventMulticaster.add(hierarchyBoundsListener, listener);
+        newEventsOnly = true;
+
+        // Need to lock the tree, otherwise we might end up inconsistent.
+        synchronized (getTreeLock())
+        {
+          numHierarchyBoundsListeners++;
+          if (parent != null)
+            parent.updateHierarchyListenerCount
+                                     (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 1);
+        }
+      }
   }
 
   /**
@@ -2521,6 +3098,16 @@ public abstract class Component
   {
     hierarchyBoundsListener =
       AWTEventMulticaster.remove(hierarchyBoundsListener, listener);
+
+    // Need to lock the tree, otherwise we might end up inconsistent.
+    synchronized (getTreeLock())
+      {
+        numHierarchyBoundsListeners--;
+        if (parent != null)
+          parent.updateHierarchyListenerCount
+                                         (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
+                                          -1);
+      }
   }
 
   /**
@@ -2539,6 +3126,40 @@ public abstract class Component
   }
 
   /**
+   * Fires a HierarchyEvent or HierarchyChangeEvent on this component.
+   *
+   * @param id the event id
+   * @param changed the changed component
+   * @param parent the parent
+   * @param flags the event flags
+   */
+  void fireHierarchyEvent(int id, Component changed, Container parent,
+                          long flags)
+  {
+    boolean enabled = false;
+    switch (id)
+    {
+      case HierarchyEvent.HIERARCHY_CHANGED:
+        enabled = hierarchyListener != null
+                  || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0;
+        break;
+      case HierarchyEvent.ANCESTOR_MOVED:
+      case HierarchyEvent.ANCESTOR_RESIZED:
+        enabled = hierarchyBoundsListener != null
+                  || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0;
+        break;
+      default:
+        assert false : "Should not reach here";
+    }
+    if (enabled)
+      {
+        HierarchyEvent ev = new HierarchyEvent(this, id, changed, parent,
+                                               flags);
+        dispatchEvent(ev);
+      }
+  }
+
+  /**
    * Adds the specified listener to this component. This is harmless if the
    * listener is null, but if the listener has already been registered, it
    * will now be registered twice.
@@ -2551,9 +3172,11 @@ public abstract class Component
    */
   public synchronized void addKeyListener(KeyListener listener)
   {
-    keyListener = AWTEventMulticaster.add(keyListener, listener);
-    if (keyListener != null)
-      enableEvents(AWTEvent.KEY_EVENT_MASK);
+    if (listener != null)
+      {
+        keyListener = AWTEventMulticaster.add(keyListener, listener);
+        newEventsOnly = true;
+      }
   }
 
   /**
@@ -2598,9 +3221,11 @@ public abstract class Component
    */
   public synchronized void addMouseListener(MouseListener listener)
   {
-    mouseListener = AWTEventMulticaster.add(mouseListener, listener);
-    if (mouseListener != null)
-      enableEvents(AWTEvent.MOUSE_EVENT_MASK);
+    if (listener != null)
+      {
+        mouseListener = AWTEventMulticaster.add(mouseListener, listener);
+        newEventsOnly = true;
+      }
   }
 
   /**
@@ -2645,9 +3270,12 @@ public abstract class Component
    */
   public synchronized void addMouseMotionListener(MouseMotionListener listener)
   {
-    mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener, listener);
-    if (mouseMotionListener != null)
-      enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
+    if (listener != null)
+      {
+        mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener,
+                                                      listener);
+        newEventsOnly = true;
+      }
   }
 
   /**
@@ -2694,9 +3322,12 @@ public abstract class Component
    */
   public synchronized void addMouseWheelListener(MouseWheelListener listener)
   {
-    mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener, listener);
-    if (mouseWheelListener != null)
-      enableEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
+    if (listener != null)
+      {
+        mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener,
+                                                     listener);
+        newEventsOnly = true;
+      }
   }
 
   /**
@@ -2744,9 +3375,12 @@ public abstract class Component
    */
   public synchronized void addInputMethodListener(InputMethodListener listener)
   {
-    inputMethodListener = AWTEventMulticaster.add(inputMethodListener, listener);
-    if (inputMethodListener != null)
-      enableEvents(AWTEvent.INPUT_METHOD_EVENT_MASK);
+    if (listener != null)
+      {
+        inputMethodListener = AWTEventMulticaster.add(inputMethodListener,
+                                                      listener);
+        newEventsOnly = true;
+      }
   }
 
   /**
@@ -2805,29 +3439,29 @@ public abstract class Component
    * @see #getPropertyChangeListeners()
    * @since 1.3
    */
-  public EventListener[] getListeners(Class listenerType)
+  public <T extends EventListener> T[] getListeners(Class<T> listenerType)
   {
     if (listenerType == ComponentListener.class)
-      return getComponentListeners();
+      return (T[]) getComponentListeners();
     if (listenerType == FocusListener.class)
-      return getFocusListeners();
+      return (T[]) getFocusListeners();
     if (listenerType == HierarchyListener.class)
-      return getHierarchyListeners();
+      return (T[]) getHierarchyListeners();
     if (listenerType == HierarchyBoundsListener.class)
-      return getHierarchyBoundsListeners();
+      return (T[]) getHierarchyBoundsListeners();
     if (listenerType == KeyListener.class)
-      return getKeyListeners();
+      return (T[]) getKeyListeners();
     if (listenerType == MouseListener.class)
-      return getMouseListeners();
+      return (T[]) getMouseListeners();
     if (listenerType == MouseMotionListener.class)
-      return getMouseMotionListeners();
+      return (T[]) getMouseMotionListeners();
     if (listenerType == MouseWheelListener.class)
-      return getMouseWheelListeners();
+      return (T[]) getMouseWheelListeners();
     if (listenerType == InputMethodListener.class)
-      return getInputMethodListeners();
+      return (T[]) getInputMethodListeners();
     if (listenerType == PropertyChangeListener.class)
-      return getPropertyChangeListeners();
-    return (EventListener[]) Array.newInstance(listenerType, 0);
+      return (T[]) getPropertyChangeListeners();
+    return (T[]) Array.newInstance(listenerType, 0);
   }
 
   /**
@@ -2872,18 +3506,49 @@ public abstract class Component
    */
   protected final void enableEvents(long eventsToEnable)
   {
+    // Update the counter for hierarchy (bounds) listeners.
+    if ((eventsToEnable & AWTEvent.HIERARCHY_EVENT_MASK) != 0
+        && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) == 0)
+      {
+        // Need to lock the tree, otherwise we might end up inconsistent.
+        synchronized (getTreeLock())
+          {
+            numHierarchyListeners++;
+            if (parent != null)
+              parent.updateHierarchyListenerCount
+                                                (AWTEvent.HIERARCHY_EVENT_MASK,
+                                                 1);
+          }
+      }
+    if ((eventsToEnable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0
+        && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) == 0)
+      {
+        // Need to lock the tree, otherwise we might end up inconsistent.
+        synchronized (getTreeLock())
+          {
+            numHierarchyBoundsListeners++;
+            if (parent != null)
+              parent.updateHierarchyListenerCount
+                                         (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
+                                          1);
+          }
+      }
+
     eventMask |= eventsToEnable;
-    // TODO: Unlike Sun's implementation, I think we should try and
-    // enable/disable events at the peer (gtk/X) level. This will avoid
-    // clogging the event pipeline with useless mousemove events that
-    // we arn't interested in, etc. This will involve extending the peer
-    // interface, but thats okay because the peer interfaces have been
-    // deprecated for a long time, and no longer feature in the
-    // API specification at all.
-    if (isLightweight() && parent != null)
-      parent.enableEvents(eventsToEnable);
-    else if (peer != null)
-      peer.setEventMask(eventMask);
+    newEventsOnly = true;
+
+    // Only heavyweight peers handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
+    if (p != null)
+      p.setEventMask(eventMask);
+
   }
 
   /**
@@ -2896,8 +3561,48 @@ public abstract class Component
    */
   protected final void disableEvents(long eventsToDisable)
   {
+    // Update the counter for hierarchy (bounds) listeners.
+    if ((eventsToDisable & AWTEvent.HIERARCHY_EVENT_MASK) != 0
+        && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0)
+      {
+        // Need to lock the tree, otherwise we might end up inconsistent.
+        synchronized (getTreeLock())
+          {
+            numHierarchyListeners--;
+            if (parent != null)
+              parent.updateHierarchyListenerCount
+                                                (AWTEvent.HIERARCHY_EVENT_MASK,
+                                                 -1);
+          }
+      }
+    if ((eventsToDisable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0
+        && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0)
+      {
+        // Need to lock the tree, otherwise we might end up inconsistent.
+        synchronized (getTreeLock())
+          {
+            numHierarchyBoundsListeners--;
+            if (parent != null)
+              parent.updateHierarchyListenerCount
+                                         (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
+                                          -1);
+          }
+      }
+
     eventMask &= ~eventsToDisable;
-    // forward new event mask to peer?
+
+    // Only heavyweight peers handle this.
+    ComponentPeer p = peer;
+    Component comp = this;
+    while (p instanceof LightweightPeer)
+      {
+        comp = comp.parent;
+        p = comp == null ? null : comp.peer;
+      }
+
+    if (p != null)
+      p.setEventMask(eventMask);
+
   }
 
   /**
@@ -2913,19 +3618,42 @@ public abstract class Component
    */
   protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent)
   {
+    AWTEvent coalesced = null;
     switch (existingEvent.id)
       {
       case MouseEvent.MOUSE_MOVED:
       case MouseEvent.MOUSE_DRAGGED:
         // Just drop the old (intermediate) event and return the new one.
-        return newEvent;
+        MouseEvent me1 = (MouseEvent) existingEvent;
+        MouseEvent me2 = (MouseEvent) newEvent;
+        if (me1.getModifiers() == me2.getModifiers())
+          coalesced = newEvent;
+        break;
       case PaintEvent.PAINT:
       case PaintEvent.UPDATE:
-        return coalescePaintEvents((PaintEvent) existingEvent,
-                                   (PaintEvent) newEvent);
+        // For heavyweights the EventQueue should ask the peer.
+        if (peer == null || peer instanceof LightweightPeer)
+          {
+            PaintEvent pe1 = (PaintEvent) existingEvent;
+            PaintEvent pe2 = (PaintEvent) newEvent;
+            Rectangle r1 = pe1.getUpdateRect();
+            Rectangle r2 = pe2.getUpdateRect();
+            if (r1.contains(r2))
+              coalesced = existingEvent;
+            else if (r2.contains(r1))
+              coalesced = newEvent;
+          }
+        else
+          {
+            // Replace the event and let the heavyweight figure out the expanding
+            // of the repaint area.
+            coalesced = newEvent;
+          }
+        break;
       default:
-        return null;
+        coalesced = null;
       }
+    return coalesced;
   }
 
   /**
@@ -3440,18 +4168,37 @@ public abstract class Component
    */
   public void addNotify()
   {
-    if (peer == null)
-      peer = getToolkit().createComponent(this);
-    else if (parent != null && parent.isLightweight())
-      new HeavyweightInLightweightListener(parent);
-    /* Now that all the children has gotten their peers, we should
-       have the event mask needed for this component and its
-       lightweight subcomponents. */
-    peer.setEventMask(eventMask);
-    /* We do not invalidate here, but rather leave that job up to
-       the peer. For efficiency, the peer can choose not to
-       invalidate if it is happy with the current dimensions,
-       etc. */
+    // We need to lock the tree here to avoid races and inconsistencies.
+    synchronized (getTreeLock())
+      {
+        if (peer == null)
+          peer = getToolkit().createComponent(this);
+        else if (parent != null && parent.isLightweight())
+          new HeavyweightInLightweightListener(parent);
+        // Now that all the children has gotten their peers, we should
+        // have the event mask needed for this component and its
+        //lightweight subcomponents.
+        peer.setEventMask(eventMask);
+
+        // We used to leave the invalidate() to the peer. However, I put it
+        // back here for 2 reasons: 1) The RI does call invalidate() from
+        // addNotify(); 2) The peer shouldn't be bother with validation too
+        // much.
+        invalidate();
+
+        if (dropTarget != null) 
+          dropTarget.addNotify(peer);
+
+        // Fetch the peerFont for later installation in validate().
+        peerFont = getFont();
+
+        // Notify hierarchy listeners.
+        long flags = HierarchyEvent.DISPLAYABILITY_CHANGED;
+        if (isHierarchyVisible())
+          flags |= HierarchyEvent.SHOWING_CHANGED;
+        fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent,
+                           flags);
+      }
   }
 
   /**
@@ -3465,17 +4212,29 @@ public abstract class Component
    */
   public void removeNotify()
   {
-    // We null our peer field before disposing of it, such that if we're
-    // not the event dispatch thread and the dispatch thread is awoken by
-    // the dispose call, there will be no race checking the peer's null
-    // status.
-
-    ComponentPeer tmp = peer;
-    peer = null;
-    if (tmp != null)
+    // We need to lock the tree here to avoid races and inconsistencies.
+    synchronized (getTreeLock())
       {
-        tmp.hide();
-        tmp.dispose();
+        // We null our peer field before disposing of it, such that if we're
+        // not the event dispatch thread and the dispatch thread is awoken by
+        // the dispose call, there will be no race checking the peer's null
+        // status.
+
+        ComponentPeer tmp = peer;
+        peer = null;
+        peerFont = null;
+        if (tmp != null)
+          {
+            tmp.hide();
+            tmp.dispose();
+          }
+
+        // Notify hierarchy listeners.
+        long flags = HierarchyEvent.DISPLAYABILITY_CHANGED;
+        if (isHierarchyVisible())
+          flags |= HierarchyEvent.SHOWING_CHANGED;
+        fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent,
+                           flags);
       }
   }
 
@@ -3594,7 +4353,8 @@ public abstract class Component
    * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
    * @since 1.4
    */
-  public void setFocusTraversalKeys(int id, Set keystrokes)
+  public void setFocusTraversalKeys(int id,
+                                   Set<? extends AWTKeyStroke> keystrokes)
   {
     if (keystrokes == null)
       {
@@ -3686,14 +4446,14 @@ public abstract class Component
    * 
    * @since 1.4
    */
-  public Set getFocusTraversalKeys (int id)
+  public Set<AWTKeyStroke> getFocusTraversalKeys (int id)
   {
     if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
         id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
         id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
       throw new IllegalArgumentException();
 
-    Set s = null;
+    Set<AWTKeyStroke> s = null;
 
     if (focusTraversalKeys != null)
       s = focusTraversalKeys[id];
@@ -3796,56 +4556,7 @@ public abstract class Component
    */
   public void requestFocus ()
   {
-    if (isDisplayable ()
-       && isShowing ()
-       && isFocusable ())
-      {
-        synchronized (getTreeLock ())
-          {
-            // Find this Component's top-level ancestor.            
-            Container parent = (this instanceof Container) ? (Container) this
-                                                          : getParent();            
-            while (parent != null
-                   && !(parent instanceof Window))
-              parent = parent.getParent ();
-
-            if (parent == null)
-              return;
-            
-            Window toplevel = (Window) parent;
-            if (toplevel.isFocusableWindow ())
-              {
-                if (peer != null && !isLightweight())
-                  // This call will cause a FOCUS_GAINED event to be
-                  // posted to the system event queue if the native
-                  // windowing system grants the focus request.
-                  peer.requestFocus ();
-                else
-                  {
-                    // Either our peer hasn't been created yet or we're a
-                    // lightweight component.  In either case we want to
-                    // post a FOCUS_GAINED event.
-                    EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
-                    synchronized (eq)
-                      {
-                        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
-                        Component currentFocusOwner = manager.getGlobalPermanentFocusOwner ();
-                        if (currentFocusOwner != null)
-                          {
-                            eq.postEvent (new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST,
-                                                         false, this));
-                            eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, false,
-                                                         currentFocusOwner));
-                          }
-                        else
-                          eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, false));
-                      }
-                  }
-              }
-            else
-              pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED);
-          }
-      }
+    requestFocusImpl(false, true);
   }
 
   /**
@@ -3885,61 +4596,7 @@ public abstract class Component
    */
   protected boolean requestFocus (boolean temporary)
   {
-    if (isDisplayable ()
-       && isShowing ()
-       && isFocusable ())
-      {
-        synchronized (getTreeLock ())
-          {
-            // Find this Component's top-level ancestor.
-            Container parent = getParent ();
-
-            while (parent != null
-                   && !(parent instanceof Window))
-              parent = parent.getParent ();
-
-            Window toplevel = (Window) parent;
-            if (toplevel.isFocusableWindow ())
-              {
-                if (peer != null && !isLightweight())
-                  // This call will cause a FOCUS_GAINED event to be
-                  // posted to the system event queue if the native
-                  // windowing system grants the focus request.
-                  peer.requestFocus ();
-                else
-                  {
-                    // Either our peer hasn't been created yet or we're a
-                    // lightweight component.  In either case we want to
-                    // post a FOCUS_GAINED event.
-                    EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
-                    synchronized (eq)
-                      {
-                        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
-                        Component currentFocusOwner = manager.getGlobalPermanentFocusOwner ();
-                        if (currentFocusOwner != null)
-                          {
-                            eq.postEvent (new FocusEvent(currentFocusOwner,
-                                                         FocusEvent.FOCUS_LOST,
-                                                         temporary, this));
-                            eq.postEvent (new FocusEvent(this,
-                                                         FocusEvent.FOCUS_GAINED,
-                                                         temporary,
-                                                         currentFocusOwner));
-                          }
-                        else
-                          eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary));
-                      }
-                  }
-              }
-            else
-              // FIXME: need to add a focus listener to our top-level
-              // ancestor, so that we can post this event when it becomes
-              // the focused window.
-              pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary);
-          }
-      }
-    // Always return true.
-    return true;
+    return requestFocusImpl(temporary, true);
   }
 
   /**
@@ -3967,7 +4624,7 @@ public abstract class Component
    */
   public boolean requestFocusInWindow ()
   {
-    return requestFocusInWindow (false);
+    return requestFocusImpl(false, false);
   }
 
   /**
@@ -3998,65 +4655,84 @@ public abstract class Component
    */
   protected boolean requestFocusInWindow (boolean temporary)
   {
-    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
-
-    Window focusedWindow = manager.getFocusedWindow ();
+    return requestFocusImpl(temporary, false);
+  }
 
-    if (isDisplayable ()
-       && isShowing ()
-       && isFocusable ())
+  /**
+   * Helper method for all 4 requestFocus variants.
+   *
+   * @param temporary indicates if the focus change is temporary
+   * @param focusWindow indicates if the window focus may be changed
+   *
+   * @return <code>false</code> if the request has been definitely denied,
+   *         <code>true</code> otherwise
+   */
+  private boolean requestFocusImpl(boolean temporary, boolean focusWindow)
+  {
+    boolean retval = false;
+    // Don't try to focus non-focusable and non-visible components.
+    if (isFocusable() && isVisible())
       {
-        if (focusedWindow != null)
+        ComponentPeer myPeer = peer;
+        if (peer != null)
           {
-            synchronized (getTreeLock ())
+            // Find Window ancestor and find out if we're showing while
+            // doing this.
+            boolean showing = true;
+            Component window = this;
+            while (! (window instanceof Window))
               {
-                Container parent = getParent ();
-
-                while (parent != null
-                       && !(parent instanceof Window))
-                  parent = parent.getParent ();
-
-                Window toplevel = (Window) parent;
-
-                // Check if top-level ancestor is currently focused window.
-                if (focusedWindow == toplevel)
+                if (! window.isVisible())
+                  showing = false;
+                window = window.parent;
+              }
+            // Don't allow focus when there is no window or the window
+            // is not focusable.
+            if (window != null && ((Window) window).isFocusableWindow()
+                && showing)
+              {
+                // Search for nearest heavy ancestor (including this
+                // component).
+                Component heavyweightParent = this;
+                while (heavyweightParent.peer instanceof LightweightPeer)
+                  heavyweightParent = heavyweightParent.parent;
+
+                // Don't allow focus on lightweight components without
+                // visible heavyweight ancestor
+                if (heavyweightParent != null && heavyweightParent.isVisible())
                   {
-                    if (peer != null
-                        && !isLightweight()
-                        && !(this instanceof Window))
-                      // This call will cause a FOCUS_GAINED event to be
-                      // posted to the system event queue if the native
-                      // windowing system grants the focus request.
-                      peer.requestFocus ();
-                    else
+                    // Don't allow focus when heavyweightParent has no peer.
+                    myPeer = heavyweightParent.peer;
+                    if (myPeer != null)
                       {
-                        // Either our peer hasn't been created yet or we're a
-                        // lightweight component.  In either case we want to
-                        // post a FOCUS_GAINED event.
-                        EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
-                        synchronized (eq)
+                        // Register lightweight focus request.
+                        if (heavyweightParent != this)
+                          {
+                            KeyboardFocusManager
+                            .addLightweightFocusRequest(heavyweightParent,
+                                                        this);
+                          }
+
+                        // Try to focus the component.
+                        long time = EventQueue.getMostRecentEventTime();
+                        boolean success = myPeer.requestFocus(this, temporary,
+                                                              focusWindow,
+                                                              time);
+                        if (! success)
                           {
-                            Component currentFocusOwner = manager.getGlobalPermanentFocusOwner ();
-                            if (currentFocusOwner != null)
-                              {
-                                eq.postEvent (new FocusEvent(currentFocusOwner, FocusEvent.FOCUS_LOST,
-                                                             temporary, this));
-                                eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary,
-                                                             currentFocusOwner));
-                              }
-                            else
-                              eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary));
+                            // Dequeue key events if focus request failed.
+                            KeyboardFocusManager kfm =
+                              KeyboardFocusManager.getCurrentKeyboardFocusManager();
+                            kfm.dequeueKeyEvents(time, this);
                           }
+                        retval = success;
                       }
                   }
-                else
-                  return false;
               }
           }
-
-        return true;
       }
-    return false;
+    return retval;
   }
 
   /**
@@ -4317,7 +4993,7 @@ public abstract class Component
    */
   protected String paramString()
   {
-    StringBuffer param = new StringBuffer();
+    CPStringBuilder param = new CPStringBuilder();
     String name = getName();
     if (name != null)
       param.append(name).append(",");
@@ -4557,7 +5233,7 @@ p   * <li>the set of backward traversal keys
                                     Object newValue)
   {
     if (changeSupport != null)
-      changeSupport.firePropertyChange(propertyName, oldValue, newValue);
+      changeSupport.firePropertyChange(propertyName, oldValue, newValue);  
   }
 
   /**
@@ -4698,28 +5374,26 @@ p   * <li>the set of backward traversal keys
    * {@link #applyComponentOrientation(ComponentOrientation)} affects the
    * entire hierarchy.
    *
-   * @param o the new orientation
-   * @throws NullPointerException if o is null
+   * @param o the new orientation (<code>null</code> is accepted)
    * @see #getComponentOrientation()
    */
   public void setComponentOrientation(ComponentOrientation o)
   {
-    if (o == null)
-      throw new NullPointerException();
-    ComponentOrientation oldOrientation = orientation;
-    orientation = o;
+    ComponentOrientation oldOrientation = componentOrientation;
+    componentOrientation = o;
     firePropertyChange("componentOrientation", oldOrientation, o);
   }
 
   /**
    * Determines the text layout orientation used by this component.
    *
-   * @return the component orientation
+   * @return the component orientation (this can be <code>null</code>)
    * @see #setComponentOrientation(ComponentOrientation)
    */
   public ComponentOrientation getComponentOrientation()
   {
-    return orientation;
+    return componentOrientation;
   }
 
   /**
@@ -4778,27 +5452,6 @@ p   * <li>the set of backward traversal keys
   }
 
   /**
-   * Implementation method that allows classes such as Canvas and Window to
-   * override the graphics configuration without violating the published API.
-   *
-   * @return the graphics configuration
-   */
-  GraphicsConfiguration getGraphicsConfigurationImpl()
-  {
-    if (peer != null)
-      {
-        GraphicsConfiguration config = peer.getGraphicsConfiguration();
-        if (config != null)
-          return config;
-      }
-
-    if (parent != null)
-      return parent.getGraphicsConfiguration();
-
-    return null;
-  }
-
-  /**
    * Translate an AWT 1.1 event ({@link AWTEvent}) into an AWT 1.0
    * event ({@link Event}).
    *
@@ -4810,8 +5463,38 @@ p   * <li>the set of backward traversal keys
   {
     Object target = e.getSource ();
     Event translated = null;
+    
+    if (e instanceof WindowEvent)
+      {
+        WindowEvent we = (WindowEvent) e;
+        int id = we.id;
+        int newId = 0;
+        
+        switch (id)
+          {
+          case WindowEvent.WINDOW_DEICONIFIED:
+            newId = Event.WINDOW_DEICONIFY;
+            break;
+          case WindowEvent.WINDOW_CLOSED:
+          case WindowEvent.WINDOW_CLOSING:
+            newId = Event.WINDOW_DESTROY;
+            break;
+          case WindowEvent.WINDOW_ICONIFIED:
+            newId = Event.WINDOW_ICONIFY;
+            break;
+          case WindowEvent.WINDOW_GAINED_FOCUS:
+            newId = Event.GOT_FOCUS;
+            break;
+          case WindowEvent.WINDOW_LOST_FOCUS:
+            newId = Event.LOST_FOCUS;
+            break;
+          default:
+            return null;
+          }
 
-    if (e instanceof InputEvent)
+        translated = new Event(target, 0, newId, 0, 0, 0, 0);
+      }
+    else if (e instanceof InputEvent)
       {
         InputEvent ie = (InputEvent) e;
         long when = ie.getWhen ();
@@ -4839,7 +5522,7 @@ p   * <li>the set of backward traversal keys
         if ((mods & InputEvent.ALT_DOWN_MASK) != 0)
           oldMods |= Event.ALT_MASK;
 
-        if (e instanceof MouseEvent)
+        if (e instanceof MouseEvent && !ignoreOldMouseEvents())
           {
             if (id == MouseEvent.MOUSE_PRESSED)
               oldID = Event.MOUSE_DOWN;
@@ -4974,7 +5657,7 @@ p   * <li>the set of backward traversal keys
                 oldKey = Event.UP;
                 break;
               default:
-                oldKey = (int) ((KeyEvent) e).getKeyChar();
+                oldKey = ((KeyEvent) e).getKeyChar();
               }
 
             translated = new Event (target, when, oldID,
@@ -5017,50 +5700,53 @@ p   * <li>the set of backward traversal keys
    *
    * @param e the event to dispatch
    */
-
   void dispatchEventImpl(AWTEvent e)
   {
-    // This boolean tells us not to process focus events when the focus
-    // opposite component is the same as the focus component.
-    boolean ignoreFocus = 
-      (e instanceof FocusEvent && 
-       ((FocusEvent)e).getComponent() == ((FocusEvent)e).getOppositeComponent());
-    
-    if (eventTypeEnabled (e.id))
+    // Update the component's knowledge about the size.
+    // Important: Please look at the big comment in ComponentReshapeEvent
+    // to learn why we did it this way. If you change this code, make
+    // sure that the peer->AWT bounds update still works.
+    // (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 )
+    if (e instanceof ComponentReshapeEvent)
       {
-        if (e.id != PaintEvent.PAINT && e.id != PaintEvent.UPDATE
-            && !ignoreFocus)
-          processEvent(e);
-        
-        // the trick we use to communicate between dispatch and redispatch
-        // is to have KeyboardFocusManager.redispatch synchronize on the
-        // object itself. we then do not redispatch to KeyboardFocusManager
-        // if we are already holding the lock.
-        if (! Thread.holdsLock(e))
+        ComponentReshapeEvent reshape = (ComponentReshapeEvent) e;
+        x = reshape.x;
+        y = reshape.y;
+        width = reshape.width;
+        height = reshape.height;
+        return;
+      }
+
+    // Retarget focus events before dispatching it to the KeyboardFocusManager
+    // in order to handle lightweight components properly.
+    boolean dispatched = false;
+    if (! e.isFocusManagerEvent)
+      {
+        e = KeyboardFocusManager.retargetFocusEvent(e);
+        dispatched = KeyboardFocusManager.getCurrentKeyboardFocusManager()
+                                          .dispatchEvent(e);
+      }
+
+    if (! dispatched)
+      {
+        // Give toolkit a chance to dispatch the event
+        // to globally registered listeners.
+        Toolkit.getDefaultToolkit().globalDispatchEvent(e);
+
+        if (newEventsOnly)
           {
-            switch (e.id)
-              {
-              case WindowEvent.WINDOW_GAINED_FOCUS:
-              case WindowEvent.WINDOW_LOST_FOCUS:
-              case KeyEvent.KEY_PRESSED:
-              case KeyEvent.KEY_RELEASED:
-              case KeyEvent.KEY_TYPED:
-              case FocusEvent.FOCUS_GAINED:
-              case FocusEvent.FOCUS_LOST:
-                if (KeyboardFocusManager
-                    .getCurrentKeyboardFocusManager()
-                    .dispatchEvent(e))
-                    return;
-              case MouseEvent.MOUSE_PRESSED:
-                if (isLightweight() && !e.isConsumed())
-                    requestFocus();
-                break;
-              }
+            if (eventTypeEnabled(e.id))
+              processEvent(e);
+          }
+        else
+          {
+            Event oldEvent = translateEvent(e);
+            if (oldEvent != null)
+              postEvent (oldEvent);
           }
+        if (peer != null)
+          peer.handleEvent(e);
       }
-
-    if (peer != null)
-      peer.handleEvent(e);
   }
 
   /**
@@ -5130,42 +5816,79 @@ p   * <li>the set of backward traversal keys
   }
 
   /**
-   * Coalesce paint events. Current heuristic is: Merge if the union of
-   * areas is less than twice that of the sum of the areas. The X server
-   * tend to create a lot of paint events that are adjacent but not
-   * overlapping.
+   * Returns <code>true</code> when this component and all of its ancestors
+   * are visible, <code>false</code> otherwise.
    *
-   * <pre>
-   * +------+
-   * |      +-----+  ...will be merged
-   * |      |     |
-   * |      |     |
-   * +------+     |
-   *        +-----+
+   * @return <code>true</code> when this component and all of its ancestors
+   *         are visible, <code>false</code> otherwise
+   */
+  boolean isHierarchyVisible()
+  {
+    boolean visible = isVisible();
+    Component comp = parent;
+    while (comp != null && visible)
+      {
+        comp = comp.parent;
+        if (comp != null)
+          visible = visible && comp.isVisible();
+      }
+    return visible;
+  }
+
+  /**
+   * Returns the mouse pointer position relative to this Component's
+   * top-left corner.
    *
-   * +---------------+--+
-   * |               |  |  ...will not be merged
-   * +---------------+  |
-   *                 |  |
-   *                 |  |
-   *                 |  |
-   *                 |  |
-   *                 |  |
-   *                 +--+
-   * </pre>
+   * @return relative mouse pointer position
    *
-   * @param queuedEvent the first paint event
-   * @param newEvent the second paint event
-   * @return the combined paint event, or null
+   * @throws HeadlessException if in a headless environment
    */
-  private PaintEvent coalescePaintEvents(PaintEvent queuedEvent,
-                                         PaintEvent newEvent)
+  public Point getMousePosition() throws HeadlessException
+  {
+    return getMousePositionHelper(true);
+  }
+
+  Point getMousePositionHelper(boolean allowChildren) throws HeadlessException
+  {
+    if (GraphicsEnvironment.isHeadless())
+      throw new HeadlessException("can't get mouse position"
+                                  + " in headless environment");
+    if (!isShowing())
+      return null;
+
+    Component parent = this;
+    int windowRelativeXOffset = 0;
+    int windowRelativeYOffset = 0;
+    while (parent != null && !(parent instanceof Window))
+      {
+        windowRelativeXOffset += parent.getX();
+        windowRelativeYOffset += parent.getY();
+        parent = parent.getParent();
+      }
+    if (parent == null)
+      return null;
+
+    Window window = (Window) parent;
+    if (!Toolkit.getDefaultToolkit()
+        .getMouseInfoPeer().isWindowUnderMouse(window))
+      return null;
+
+    PointerInfo info = MouseInfo.getPointerInfo();
+    Point mouseLocation = info.getLocation();
+    Point windowLocation = window.getLocationOnScreen();
+
+    int x = mouseLocation.x - windowLocation.x;
+    int y = mouseLocation.y - windowLocation.y;
+
+    if (!mouseOverComponent(window.getComponentAt(x, y), allowChildren))
+      return null;
+
+    return new Point(x - windowRelativeXOffset, y - windowRelativeYOffset);
+  }
+
+  boolean mouseOverComponent(Component component, boolean allowChildren)
   {
-    Rectangle r1 = queuedEvent.getUpdateRect();
-    Rectangle r2 = newEvent.getUpdateRect();
-    Rectangle union = r1.union(r2);
-    newEvent.setUpdateRect(union);
-    return newEvent;
+    return component == this;
   }
 
   /**
@@ -5308,7 +6031,7 @@ p   * <li>the set of backward traversal keys
      */
     public void componentHidden(ComponentEvent event)
     {
-      if (!isShowing())
+      if (isShowing())
         peer.hide();
     }
   }