Fixes Issue #844.
Adds mouse wheel support to the DOM libraries and adds them appropriately
to mousey widgets.

Patch by: bobv
Review by: jgw, knorton



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@958 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/DOM.java b/user/src/com/google/gwt/user/client/DOM.java
index 16ee082..b6c1073 100644
--- a/user/src/com/google/gwt/user/client/DOM.java
+++ b/user/src/com/google/gwt/user/client/DOM.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2007 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -34,7 +34,7 @@
 
   //<BrowserEventPreview>
   private static Vector sEventPreviewStack = new Vector();
-  
+
   static {
     impl = (DOMImpl) GWT.create(DOMImpl.class);
     impl.init();
@@ -46,7 +46,7 @@
    * to their listeners. Note that the event preview will receive <u>all </u>
    * events, including those received due to bubbling, whereas normal event
    * handlers only receive explicitly sunk events.
-   * 
+   *
    * @param preview the event preview to be added to the stack.
    */
   public static void addEventPreview(EventPreview preview) {
@@ -57,7 +57,7 @@
 
   /**
    * Appends one element to another's list of children.
-   * 
+   *
    * @param parent the parent element
    * @param child its new child
    */
@@ -68,7 +68,7 @@
   /**
    * Compares two elements for equality (note that reference equality is not
    * sufficient to determine equality among elements on most browsers).
-   * 
+   *
    * @param elem1 the first element to be compared
    * @param elem2 the second element to be compared
    * @return <code>true</code> if they are in fact the same element
@@ -80,7 +80,7 @@
 
   /**
    * Creates an HTML A element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createAnchor() {
@@ -89,7 +89,7 @@
 
   /**
    * Creates an HTML BUTTON element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createButton() {
@@ -104,10 +104,10 @@
   public static Element createCaption() {
     return impl.createElement("caption");
   }
-  
+
   /**
    * Creates an HTML COL element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createCol() {
@@ -125,7 +125,7 @@
 
   /**
    * Creates an HTML DIV element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createDiv() {
@@ -134,7 +134,7 @@
 
   /**
    * Creates an HTML element.
-   * 
+   *
    * @param tagName the HTML tag of the element to be created
    * @return the newly-created element
    */
@@ -144,7 +144,7 @@
 
   /**
    * Creates an HTML FIELDSET element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createFieldSet() {
@@ -153,7 +153,7 @@
 
   /**
    * Creates an HTML FORM element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createForm() {
@@ -162,7 +162,7 @@
 
   /**
    * Creates an HTML IFRAME element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createIFrame() {
@@ -171,7 +171,7 @@
 
   /**
    * Creates an HTML IMG element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createImg() {
@@ -180,7 +180,7 @@
 
   /**
    * Creates an HTML INPUT type='CHECK' element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createInputCheck() {
@@ -189,7 +189,7 @@
 
   /**
    * Creates an HTML INPUT type='PASSWORD' element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createInputPassword() {
@@ -198,7 +198,7 @@
 
   /**
    * Creates an HTML INPUT type='RADIO' element.
-   * 
+   *
    * @param group the name of the group with which this radio button will be
    *          associated
    * @return the newly-created element
@@ -209,7 +209,7 @@
 
   /**
    * Creates an HTML INPUT type='TEXT' element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createInputText() {
@@ -218,7 +218,7 @@
 
   /**
    * Creates an HTML LABEL element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createLabel() {
@@ -227,7 +227,7 @@
 
   /**
    * Creates an HTML LEGEND element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createLegend() {
@@ -236,7 +236,7 @@
 
   /**
    * Creates an HTML OPTIONS element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createOptions() {
@@ -245,7 +245,7 @@
 
   /**
    * Creates an HTML SELECT element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createSelect() {
@@ -254,7 +254,7 @@
 
   /**
    * Creates an HTML SPAN element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createSpan() {
@@ -263,7 +263,7 @@
 
   /**
    * Creates an HTML TABLE element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createTable() {
@@ -272,7 +272,7 @@
 
   /**
    * Creates an HTML TBODY element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createTBody() {
@@ -281,7 +281,7 @@
 
   /**
    * Creates an HTML TD element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createTD() {
@@ -290,7 +290,7 @@
 
   /**
    * Creates an HTML TEXTAREA element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createTextArea() {
@@ -308,7 +308,7 @@
 
   /**
    * Creates an HTML TH element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createTH() {
@@ -326,7 +326,7 @@
 
   /**
    * Creates an HTML TR element.
-   * 
+   *
    * @return the newly-created element
    */
   public static Element createTR() {
@@ -336,7 +336,7 @@
   /**
    * Cancels bubbling for the given event. This will stop the event from being
    * propagated to parent elements.
-   * 
+   *
    * @param evt the event on which to cancel bubbling
    * @param cancel <code>true</code> to cancel bubbling
    */
@@ -346,7 +346,7 @@
 
   /**
    * Gets whether the ALT key was depressed when the given event occurred.
-   * 
+   *
    * @param evt the event to be tested
    * @return <code>true</code> if ALT was depressed when the event occurred
    */
@@ -356,7 +356,7 @@
 
   /**
    * Gets the mouse buttons that were depressed when the given event occurred.
-   * 
+   *
    * @param evt the event to be tested
    * @return a bit-field, defined by {@link Event#BUTTON_LEFT},
    *         {@link Event#BUTTON_MIDDLE}, and {@link Event#BUTTON_RIGHT}
@@ -367,7 +367,7 @@
 
   /**
    * Gets the mouse x-position within the browser window's client area.
-   * 
+   *
    * @param evt the event to be tested
    * @return the mouse x-position
    */
@@ -377,7 +377,7 @@
 
   /**
    * Gets the mouse y-position within the browser window's client area.
-   * 
+   *
    * @param evt the event to be tested
    * @return the mouse y-position
    */
@@ -387,7 +387,7 @@
 
   /**
    * Gets whether the CTRL key was depressed when the given event occurred.
-   * 
+   *
    * @param evt the event to be tested
    * @return <code>true</code> if CTRL was depressed when the event occurred
    */
@@ -398,7 +398,7 @@
   /**
    * Gets the element from which the mouse pointer was moved (only valid for
    * {@link Event#ONMOUSEOVER}).
-   * 
+   *
    * @param evt the event to be tested
    * @return the element from which the mouse pointer was moved
    */
@@ -408,13 +408,13 @@
 
   /**
    * Gets the key code associated with this event.
-   * 
+   *
    * <p>
    * For {@link Event#ONKEYPRESS}, this method returns the Unicode value of the
    * character generated. For {@link Event#ONKEYDOWN} and {@link Event#ONKEYUP},
    * it returns the code associated with the physical key.
    * </p>
-   * 
+   *
    * @param evt the event to be tested
    * @return the Unicode character or key code.
    * @see com.google.gwt.user.client.ui.KeyboardListener
@@ -424,8 +424,28 @@
   }
 
   /**
+   * Gets the velocity of the mouse wheel associated with the event along the
+   * Y axis.
+   * <p>
+   * The velocity of the event is an artifical measurement for relative
+   * comparisons of wheel activity.  It is affected by some non-browser
+   * factors, including choice of input hardware and mouse acceleration
+   * settings.  The sign of the velocity measurement agrees with the screen
+   * coordinate system; negative values are towards the origin and positive
+   * values are away from the origin.  Standard scrolling speed is approximately
+   * ten units per event.
+   * </p>
+   *
+   * @param evt the event to be examined.
+   * @return The velocity of the mouse wheel.
+   */
+  public static int eventGetMouseWheelVelocityY(Event evt) {
+    return impl.eventGetMouseWheelVelocityY(evt);
+  }
+
+  /**
    * Gets the key-repeat state of this event.
-   * 
+   *
    * @param evt the event to be tested
    * @return <code>true</code> if this key event was an auto-repeat
    */
@@ -435,7 +455,7 @@
 
   /**
    * Gets the mouse x-position on the user's display.
-   * 
+   *
    * @param evt the event to be tested
    * @return the mouse x-position
    */
@@ -445,7 +465,7 @@
 
   /**
    * Gets the mouse y-position on the user's display.
-   * 
+   *
    * @param evt the event to be tested
    * @return the mouse y-position
    */
@@ -455,7 +475,7 @@
 
   /**
    * Gets whether the shift key was depressed when the given event occurred.
-   * 
+   *
    * @param evt the event to be tested
    * @return <code>true</code> if shift was depressed when the event occurred
    */
@@ -465,7 +485,7 @@
 
   /**
    * Returns the element that was the actual target of the given event.
-   * 
+   *
    * @param evt the event to be tested
    * @return the target element
    */
@@ -476,7 +496,7 @@
   /**
    * Gets the element to which the mouse pointer was moved (only valid for
    * {@link Event#ONMOUSEOUT}).
-   * 
+   *
    * @param evt the event to be tested
    * @return the element to which the mouse pointer was moved
    */
@@ -486,7 +506,7 @@
 
   /**
    * Gets the enumerated type of this event (as defined in {@link Event}).
-   * 
+   *
    * @param evt the event to be tested
    * @return the event's enumerated type
    */
@@ -496,7 +516,7 @@
 
   /**
    * Gets the type of the given event as a string.
-   * 
+   *
    * @param evt the event to be tested
    * @return the event's type name
    */
@@ -506,7 +526,7 @@
 
   /**
    * Prevents the browser from taking its default action for the given event.
-   * 
+   *
    * @param evt the event whose default action is to be prevented
    */
   public static void eventPreventDefault(Event evt) {
@@ -515,7 +535,7 @@
 
   /**
    * Sets the key code associated with the given keyboard event.
-   * 
+   *
    * @param evt the event whose key code is to be set
    * @param key the new key code
    */
@@ -526,7 +546,7 @@
   /**
    * Returns a stringized version of the event. This string is for debugging
    * purposes and will NOT be consistent on different browsers.
-   * 
+   *
    * @param evt the event to stringize
    * @return a string form of the event
    */
@@ -537,7 +557,7 @@
   /**
    * Gets an element's absolute left coordinate in the document's coordinate
    * system.
-   * 
+   *
    * @param elem the element to be measured
    * @return the element's absolute left coordinate
    */
@@ -548,7 +568,7 @@
   /**
    * Gets an element's absolute top coordinate in the document's coordinate
    * system.
-   * 
+   *
    * @param elem the element to be measured
    * @return the element's absolute top coordinate
    */
@@ -558,11 +578,11 @@
 
   /**
    * Gets any named attribute from an element, as a string.
-   * 
+   *
    * @param elem the element whose attribute is to be retrieved
    * @param attr the name of the attribute
    * @return the attribute's value
-   * @deprecated Use the more appropriately named 
+   * @deprecated Use the more appropriately named
    * {@link #getElementProperty(Element, String)} instead.
    */
   public static String getAttribute(Element elem, String attr) {
@@ -571,11 +591,11 @@
 
   /**
    * Gets a boolean attribute on the given element.
-   * 
+   *
    * @param elem the element whose attribute is to be set
    * @param attr the name of the attribute to be set
    * @return the attribute's value as a boolean
-   * @deprecated Use the more appropriately named 
+   * @deprecated Use the more appropriately named
    * {@link #getElementPropertyBoolean(Element, String)} instead.
    */
   public static boolean getBooleanAttribute(Element elem, String attr) {
@@ -584,7 +604,7 @@
 
   /**
    * Gets the element that currently has mouse capture.
-   * 
+   *
    * @return a handle to the capture element, or <code>null</code> if none
    *         exists
    */
@@ -594,7 +614,7 @@
 
   /**
    * Gets an element's n-th child element.
-   * 
+   *
    * @param parent the element whose child is to be retrieved
    * @param index the index of the child element
    * @return the n-th child element
@@ -605,7 +625,7 @@
 
   /**
    * Gets the number of child elements present in a given parent element.
-   * 
+   *
    * @param parent the element whose children are to be counted
    * @return the number of children
    */
@@ -615,7 +635,7 @@
 
   /**
    * Gets the index of a given child element within its parent.
-   * 
+   *
    * @param parent the parent element
    * @param child the child element
    * @return the child's index within its parent, or <code>-1</code> if it is
@@ -627,7 +647,7 @@
 
   /**
    * Gets the named attribute from the element.
-   * 
+   *
    * @param elem the element whose property is to be retrieved
    * @param attr the name of the attribute
    * @return the value of the attribute
@@ -635,11 +655,11 @@
   public static String getElementAttribute(Element elem, String attr) {
      return impl.getElementAttribute(elem, attr);
   }
-  
+
   /**
    * Gets the element associated with the given unique id within the entire
    * document.
-   * 
+   *
    * @param id the id whose associated element is to be retrieved
    * @return the associated element, or <code>null</code> if none is found
    */
@@ -648,7 +668,7 @@
   }
   /**
    * Gets any named property from an element, as a string.
-   * 
+   *
    * @param elem the element whose property is to be retrieved
    * @param prop the name of the property
    * @return the property's value
@@ -656,10 +676,10 @@
   public static String getElementProperty(Element elem, String prop) {
      return impl.getElementProperty(elem, prop);
   }
-  
+
   /**
    * Gets any named property from an element, as a boolean.
-   * 
+   *
    * @param elem the element whose property is to be retrieved
    * @param prop the name of the property
    * @return the property's value as a boolean
@@ -667,10 +687,10 @@
   public static boolean getElementPropertyBoolean(Element elem, String prop) {
      return impl.getElementPropertyBoolean(elem, prop);
   }
-  
+
   /**
    * Gets any named property from an element, as an int.
-   * 
+   *
    * @param elem the element whose property is to be retrieved
    * @param prop the name of the property
    * @return the property's value as an int
@@ -678,10 +698,10 @@
   public static int getElementPropertyInt(Element elem, String prop) {
      return impl.getElementPropertyInt(elem, prop);
   }
-  
+
   /**
    * Gets the current set of events sunk by a given element.
-   * 
+   *
    * @param elem the element whose events are to be retrieved
    * @return a bitfield describing the events sunk on this element (its possible
    *         values are described in {@link Event})
@@ -692,7 +712,7 @@
 
   /**
    * Gets the first child element of the given element.
-   * 
+   *
    * @param elem the element whose child is to be retrieved
    * @return the child element
    */
@@ -702,7 +722,7 @@
 
   /**
    * Gets an HTML representation of an element's children.
-   * 
+   *
    * @param elem the element whose HTML is to be retrieved
    * @return the HTML representation of the element's children
    */
@@ -713,7 +733,7 @@
   /**
    * Gets the text contained within an element. If the element has child
    * elements, only the text between them will be retrieved.
-   * 
+   *
    * @param elem the element whose inner text is to be retrieved
    * @return the text inside this element
    */
@@ -723,11 +743,11 @@
 
   /**
    * Gets an integer attribute on a given element.
-   * 
+   *
    * @param elem the element whose attribute is to be retrieved
    * @param attr the name of the attribute to be retrieved
    * @return the attribute's value as an integer
-   * @deprecated Use the more appropriately named 
+   * @deprecated Use the more appropriately named
    * {@link #getElementPropertyInt(Element, String)} instead.
    */
   public static int getIntAttribute(Element elem, String attr) {
@@ -736,7 +756,7 @@
 
   /**
    * Gets an integer attribute on a given element's style.
-   * 
+   *
    * @param elem the element whose style attribute is to be retrieved
    * @param attr the name of the attribute to be retrieved
    * @return the style attribute's value as an integer
@@ -747,7 +767,7 @@
 
   /**
    * Gets an element's next sibling element.
-   * 
+   *
    * @param elem the element whose sibling is to be retrieved
    * @return the sibling element
    */
@@ -757,7 +777,7 @@
 
   /**
    * Gets an element's parent element.
-   * 
+   *
    * @param elem the element whose parent is to be retrieved
    * @return the parent element
    */
@@ -767,7 +787,7 @@
 
   /**
    * Gets an attribute of the given element's style.
-   * 
+   *
    * @param elem the element whose style attribute is to be retrieved
    * @param attr the name of the style attribute to be retrieved
    * @return the style attribute's value
@@ -778,7 +798,7 @@
 
   /**
    * Inserts an element as a child of the given parent element.
-   * 
+   *
    * @param parent the parent element
    * @param child the child element
    * @param index the index before which the child will be inserted (any value
@@ -796,7 +816,7 @@
 
   /**
    * Determine whether one element is equal to, or the child of, another.
-   * 
+   *
    * @param parent the potential parent element
    * @param child the potential child element
    * @return <code>true</code> if the relationship holds
@@ -809,7 +829,7 @@
   /**
    * Releases mouse capture on the given element. Calling this method has no
    * effect if the element does not currently have mouse capture.
-   * 
+   *
    * @param elem the element to release capture
    * @see #setCapture(Element)
    */
@@ -822,7 +842,7 @@
 
   /**
    * Removes a child element from the given parent element.
-   * 
+   *
    * @param parent the parent element
    * @param child the child element to be removed
    */
@@ -835,7 +855,6 @@
    *
    * @param elem the element whose attribute is to be removed
    * @param attr the name of the element to remove
-   * @return true if the element was removed, false if the element did not exist
    */
   public static void removeElementAttribute(Element elem, String attr) {
     impl.removeElementAttribute(elem, attr);
@@ -844,7 +863,7 @@
   /**
    * Removes an element from the preview stack. This element will no longer
    * capture events, though any preview underneath it will begin to do so.
-   * 
+   *
    * @param preview the event preview to be removed from the stack
    */
   public static void removeEventPreview(EventPreview preview) {
@@ -855,14 +874,14 @@
   }
   /**
    * Scrolls the given element into view.
-   * 
+   *
    * <p>
    * This method crawls up the DOM hierarchy, adjusting the scrollLeft and
    * scrollTop properties of each scrollable element to ensure that the
    * specified element is completely in view. It adjusts each scroll position by
    * the minimum amount necessary.
    * </p>
-   * 
+   *
    * @param elem the element to be made visible
    */
   public static void scrollIntoView(Element elem) {
@@ -871,11 +890,11 @@
 
   /**
    * Sets an attribute on the given element.
-   * 
+   *
    * @param elem the element whose attribute is to be set
    * @param attr the name of the attribute to be set
    * @param value the new attribute value
-   * @deprecated Use the more appropriately named 
+   * @deprecated Use the more appropriately named
    * {@link #setElementProperty(Element, String, String)} instead.
    */
   public static void setAttribute(Element elem, String attr, String value) {
@@ -884,11 +903,11 @@
 
   /**
    * Sets a boolean attribute on the given element.
-   * 
+   *
    * @param elem the element whose attribute is to be set
    * @param attr the name of the attribute to be set
    * @param value the attribute's new boolean value
-   * @deprecated Use the more appropriately named 
+   * @deprecated Use the more appropriately named
    * {@link #setElementPropertyBoolean(Element, String, boolean)} instead.
    */
   public static void setBooleanAttribute(Element elem, String attr,
@@ -899,17 +918,17 @@
   /**
    * Sets mouse-capture on the given element. This element will directly receive
    * all mouse events until {@link #releaseCapture(Element)} is called on it.
-   * 
+   *
    * @param elem the element on which to set mouse capture
    */
   public static void setCapture(Element elem) {
     sCaptureElem = elem;
     impl.setCapture(elem);
   }
-  
+
   /**
    * Sets an attribute on a given element.
-   * 
+   *
    * @param elem element whose attribute is to be set
    * @param attr the name of the attribute
    * @param value the value to which the attribute should be set
@@ -918,10 +937,10 @@
       String value) {
     impl.setElementAttribute(elem, attr, value);
   }
-  
+
   /**
    * Sets a property on the given element.
-   * 
+   *
    * @param elem the element whose property is to be set
    * @param prop the name of the property to be set
    * @param value the new property value
@@ -933,7 +952,7 @@
 
   /**
    * Sets a boolean property on the given element.
-   * 
+   *
    * @param elem the element whose property is to be set
    * @param prop the name of the property to be set
    * @param value the new property value as a boolean
@@ -945,7 +964,7 @@
 
   /**
    * Sets an int property on the given element.
-   * 
+   *
    * @param elem the element whose property is to be set
    * @param prop the name of the property to be set
    * @param value the new property value as an int
@@ -958,7 +977,7 @@
   /**
    * Sets the {@link EventListener} to receive events for the given element.
    * Only one such listener may exist for a single element.
-   * 
+   *
    * @param elem the element whose listener is to be set
    * @param listener the listener to receive {@link Event events}
    */
@@ -968,7 +987,7 @@
 
   /**
    * Sets the HTML contained within an element.
-   * 
+   *
    * @param elem the element whose inner HTML is to be set
    * @param html the new html
    */
@@ -979,7 +998,7 @@
   /**
    * Sets the text contained within an element. If the element already has
    * children, they will be destroyed.
-   * 
+   *
    * @param elem the element whose inner text is to be set
    * @param text the new text
    */
@@ -989,11 +1008,11 @@
 
   /**
    * Sets an integer attribute on the given element.
-   * 
+   *
    * @param elem the element whose attribute is to be set
    * @param attr the name of the attribute to be set
    * @param value the attribute's new integer value
-   * @deprecated Use the more appropriately named 
+   * @deprecated Use the more appropriately named
    * {@link #setElementPropertyInt(Element, String, int)} instead.
    */
   public static void setIntAttribute(Element elem, String attr, int value) {
@@ -1002,7 +1021,7 @@
 
   /**
    * Sets an integer attribute on the given element's style.
-   * 
+   *
    * @param elem the element whose style attribute is to be set
    * @param attr the name of the style attribute to be set
    * @param value the style attribute's new integer value
@@ -1014,7 +1033,7 @@
 
   /**
    * Sets the option text of the given select object.
-   * 
+   *
    * @param select the select object whose option text is being set
    * @param text the text to set
    * @param index the index of the option whose text should be set
@@ -1025,7 +1044,7 @@
 
   /**
    * Sets an attribute on the given element's style.
-   * 
+   *
    * @param elem the element whose style attribute is to be set
    * @param attr the name of the style attribute to be set
    * @param value the style attribute's new value
@@ -1039,7 +1058,7 @@
    * Sets the current set of events sunk by a given element. These events will
    * be fired to the nearest {@link EventListener} specified on any of the
    * element's parents.
-   * 
+   *
    * @param elem the element whose events are to be retrieved
    * @param eventBits a bitfield describing the events sunk on this element (its
    *          possible values are described in {@link Event})
@@ -1051,7 +1070,7 @@
   /**
    * Returns a stringized version of the element. This string is for debugging
    * purposes and will NOT be consistent on different browsers.
-   * 
+   *
    * @param elem the element to stringize
    * @return a string form of the element
    */
@@ -1061,7 +1080,7 @@
 
   /**
    * This method is called directly by native code when any event is fired.
-   * 
+   *
    * @param evt the handle to the event being fired.
    * @param elem the handle to the element that received the event.
    * @param listener the listener associated with the element that received the
@@ -1079,7 +1098,7 @@
   /**
    * This method is called directly by native code when event preview is being
    * used.
-   * 
+   *
    * @param evt a handle to the event being previewed
    * @return <code>false</code> to cancel the event
    */
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java
index f170042..5fb0795 100644
--- a/user/src/com/google/gwt/user/client/Event.java
+++ b/user/src/com/google/gwt/user/client/Event.java
@@ -1,12 +1,12 @@
 /*
- * Copyright 2006 Google Inc.
- * 
+ * Copyright 2007 Google Inc.
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -124,6 +124,11 @@
   public static final int ONMOUSEUP = 0x00008;
 
   /**
+   * Fired when the user scrolls the mouse wheel over an element.
+   */
+  public static final int ONMOUSEWHEEL = 0x20000;
+
+  /**
    * Fired when a scrollable element's scroll offset changes.
    */
   public static final int ONSCROLL = 0x04000;
@@ -140,7 +145,7 @@
 
   /**
    * A bit-mask covering all mouse events (down, up, move, over, and out), but
-   * not click or dblclick.
+   * not click, dblclick, or wheel events.
    */
   public static final int MOUSEEVENTS = ONMOUSEDOWN | ONMOUSEUP | ONMOUSEMOVE
     | ONMOUSEOVER | ONMOUSEOUT;
@@ -155,7 +160,7 @@
 
   /*
    * (non-Javadoc)
-   * 
+   *
    * @see java.lang.Object#equals(java.lang.Object)
    */
   public boolean equals(Object other) {
@@ -164,7 +169,7 @@
 
   /*
    * (non-Javadoc)
-   * 
+   *
    * @see java.lang.Object#hashCode()
    */
   public int hashCode() {
@@ -173,7 +178,7 @@
 
   /*
    * (non-Javadoc)
-   * 
+   *
    * @see java.lang.Object#toString()
    */
   public String toString() {
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImpl.java b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
index 6e5afd7..af68a7c 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2007 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -77,6 +77,8 @@
     return evt.which ? evt.which : evt.keyCode;
   }-*/;
 
+  public abstract int eventGetMouseWheelVelocityY(Event evt);
+
   public native boolean eventGetRepeat(Event evt) /*-{
     return evt.repeat;
   }-*/;
@@ -120,6 +122,8 @@
       case "mouseup": return 0x00008;
       case "scroll": return 0x04000;
       case "error": return 0x10000;
+      case "mousewheel": return 0x20000;
+      case "DOMMouseScroll": return 0x20000;
     }
   }-*/;
 
@@ -139,7 +143,7 @@
     }
     return left + $doc.body.scrollLeft;
   }-*/;
-  
+
   public native int getAbsoluteTop(Element elem) /*-{
     var top = 0;
     while (elem) {
@@ -159,7 +163,7 @@
     var ret = elem.getAttribute(attr);
     return (ret == null) ? null : ret;
   }-*/;
-  
+
   public native Element getElementById(String id) /*-{
     var elem = $doc.getElementById(id);
     return elem ? elem : null;
@@ -199,7 +203,7 @@
     var text = '', child = node.firstChild;
     while (child) {
       // 1 == Element node
-      if (child.nodeType == 1) { 
+      if (child.nodeType == 1) {
         text += this.@com.google.gwt.user.client.impl.DOMImpl::getInnerText(Lcom/google/gwt/user/client/Element;)(child);
       } else if (child.nodeValue) {
         text += child.nodeValue;
@@ -252,7 +256,7 @@
   public native void removeChild(Element parent, Element child) /*-{
     parent.removeChild(child);
   }-*/;
-  
+
   public native void removeElementAttribute(Element elem, String attr) /*-{
     elem.removeAttribute(attr);
   }-*/;
@@ -300,7 +304,7 @@
   public native void setElementAttribute(Element elem, String attr, String value) /*-{
     elem.setAttribute(attr, value);
   }-*/;
-  
+
   public native void setElementProperty(Element elem, String prop, String value) /*-{
     elem[prop] = value;
   }-*/;
@@ -342,8 +346,8 @@
   }-*/;
 
   public native void setOptionText(Element select, String text, int index) /*-{
-    // IE doesn't properly update the screen when you use 
-    // setAttribute("option", text), so we instead directly assign to the 
+    // IE doesn't properly update the screen when you use
+    // setAttribute("option", text), so we instead directly assign to the
     // 'option' property, which works correctly on all browsers.
     var option = select.options[index];
     option.text = text;
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
index ddfa359..59b5046 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2007 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -35,7 +35,11 @@
   public native Element createInputRadioElement(String group) /*-{
     return $doc.createElement("<INPUT type='RADIO' name='" + group + "'>");
   }-*/;
- 
+
+  public native int eventGetMouseWheelVelocityY(Event evt) /*-{
+    return -evt.wheelDelta / 40;
+  }-*/;
+
   public native Element eventGetTarget(Event evt) /*-{
     var elem = evt.srcElement;
     return elem ? elem : null;
@@ -57,7 +61,7 @@
   public native int getAbsoluteLeft(Element elem) /*-{
     // Standard mode || Quirks mode.
     var scrollLeft = $doc.documentElement.scrollLeft || $doc.body.scrollLeft;
-    
+
     // Standard mode use $doc.documentElement.clientLeft (= always 2)
     // Quirks mode use $doc.body.clientLeft (=BODY border width)
     return (elem.getBoundingClientRect().left + scrollLeft)
@@ -67,7 +71,7 @@
   public native int getAbsoluteTop(Element elem) /*-{
     // Standard mode || Quirks mode.
     var scrollTop = $doc.documentElement.scrollTop || $doc.body.scrollTop;
-  
+
     // Standard mode use $doc.documentElement.clientTop (= always 2)
     // Quirks mode use $doc.body.clientTop (= BODY border width)
     return (elem.getBoundingClientRect().top +  scrollTop)
@@ -135,11 +139,12 @@
       if (this.__eventBits & 2)
         $wnd.__dispatchEvent.call(this);
     };
-  
+
     $doc.body.onclick       =
     $doc.body.onmousedown   =
     $doc.body.onmouseup     =
     $doc.body.onmousemove   =
+    $doc.body.onmousewheel  =
     $doc.body.onkeydown     =
     $doc.body.onkeypress    =
     $doc.body.onkeyup       =
@@ -212,5 +217,6 @@
     elem.onscroll      = (bits & 0x04000) ? $wnd.__dispatchEvent : null;
     elem.onload        = (bits & 0x08000) ? $wnd.__dispatchEvent : null;
     elem.onerror       = (bits & 0x10000) ? $wnd.__dispatchEvent : null;
+    elem.onmousewheel  = (bits & 0x20000) ? $wnd.__dispatchEvent : null;
   }-*/;
 }
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
index 1e5c408..b203e1b 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2007 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -42,12 +42,16 @@
     if(button == 0) {
       return 1;
     } else if (button == 1) {
-      return 4;     
+      return 4;
     } else {
       return button;
     }
  }-*/;
 
+  public native int eventGetMouseWheelVelocityY(Event evt) /*-{
+    return evt.detail;
+  }-*/;
+
   public native int getAbsoluteLeft(Element elem) /*-{
     var left = $doc.getBoxObjectFor(elem).x;
     var parent = elem;
@@ -59,8 +63,8 @@
       }
       parent = parent.parentNode;
     }
- 
-  // Must cover both Standard and Quirks mode. 
+
+  // Must cover both Standard and Quirks mode.
     return left + $doc.body.scrollLeft + $doc.documentElement.scrollLeft;
   }-*/;
 
@@ -74,7 +78,7 @@
       }
       parent = parent.parentNode;
     }
-   
+
     // Must cover both Standard and Quirks mode.
     return top + $doc.body.scrollTop + $doc.documentElement.scrollTop;
   }-*/;
@@ -93,6 +97,11 @@
     return -1;
   }-*/;
 
+  public void init() {
+    super.init();
+    initMozilla();
+  }
+
   public native boolean isOrHasChild(Element parent, Element child) /*-{
     while (child) {
       if (parent.isSameNode(child)) {
@@ -120,9 +129,20 @@
       $wnd.__captureElem = null;
     }
   }-*/;
-  
+
+  public void sinkEvents(Element elem, int bits) {
+    super.sinkEvents(elem, bits);
+    sinkEventsMozilla(elem, bits);
+  }
+
+  public native void sinkEventsMozilla(Element elem, int bits) /*-{
+    if (bits & 0x20000) {
+      elem.addEventListener('DOMMouseScroll', $wnd.__dispatchEvent, false);
+    }
+  }-*/;
+
   public native String toString(Element elem) /*-{
-    // Basic idea is to use the innerHTML property by copying the node into a 
+    // Basic idea is to use the innerHTML property by copying the node into a
     // div and getting the innerHTML
     var temp = elem.cloneNode(true);
     var tempDiv = $doc.createElement("DIV");
@@ -131,4 +151,9 @@
     temp.innerHTML = "";
     return outer;
   }-*/;
+
+  protected native void initMozilla() /*-{
+    $wnd.addEventListener('DOMMouseScroll', $wnd.__dispatchCapturedMouseEvent, true);
+  }-*/;
+
 }
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java b/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
index 6ea8317..b9700d9 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
@@ -1,12 +1,12 @@
 /*
- * Copyright 2006 Google Inc.
- * 
+ * Copyright 2007 Google Inc.
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -21,15 +21,20 @@
  * Opera implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
  */
 public class DOMImplOpera extends DOMImplStandard {
-  
-   public native int eventGetButton(Event evt) /*-{
+
+  public native int eventGetButton(Event evt) /*-{
     // Opera and IE disagree on what the button codes for left button should be.
-    // Translating to match IE standard. 
+    // Translating to match IE standard.
     var button = evt.button;
     if(button == 0){
       return 1;
     } else {
       return button;
     }
- }-*/;
+  }-*/;
+
+  public native int eventGetMouseWheelVelocityY(Event evt) /*-{
+    return evt.detail * 4;
+  }-*/;
+
 }
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java b/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
index c426660..0266024 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2007 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -16,12 +16,17 @@
 package com.google.gwt.user.client.impl;
 
 import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
 
 /**
  * Safari implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
  */
 class DOMImplSafari extends DOMImplStandard {
 
+  public native int eventGetMouseWheelVelocityY(Event evt) /*-{
+    return -evt.wheelDelta / 40;
+  }-*/;
+
   public native int getAbsoluteLeft(Element elem) /*-{
     var left = 0;
     while (elem) {
@@ -34,7 +39,7 @@
           (elem.style.position == 'absolute')) {
         return left;
       }
-      
+
       elem = parent;
     }
     return left + $doc.body.scrollLeft;
@@ -52,7 +57,7 @@
           (elem.style.position == 'absolute')) {
         return top;
       }
-      
+
       elem = parent;
     }
     return top + $doc.body.scrollTop;
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
index 67fd117..5242540 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2007 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -166,6 +166,7 @@
     $wnd.addEventListener('mousedown', $wnd.__dispatchCapturedMouseEvent, true);
     $wnd.addEventListener('mouseup', $wnd.__dispatchCapturedMouseEvent, true);
     $wnd.addEventListener('mousemove', $wnd.__dispatchCapturedMouseEvent, true);
+    $wnd.addEventListener('mousewheel', $wnd.__dispatchCapturedMouseEvent, true);
     $wnd.addEventListener('keydown', $wnd.__dispatchCapturedEvent, true);
     $wnd.addEventListener('keyup', $wnd.__dispatchCapturedEvent, true);
     $wnd.addEventListener('keypress', $wnd.__dispatchCapturedEvent, true);
@@ -237,5 +238,6 @@
     elem.onscroll      = (bits & 0x04000) ? $wnd.__dispatchEvent : null;
     elem.onload        = (bits & 0x08000) ? $wnd.__dispatchEvent : null;
     elem.onerror       = (bits & 0x10000) ? $wnd.__dispatchEvent : null;
+    elem.onmousewheel  = (bits & 0x20000) ? $wnd.__dispatchEvent : null;
   }-*/;
 }
diff --git a/user/src/com/google/gwt/user/client/ui/FocusPanel.java b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
index 54b9a94..b2f3f1a 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
@@ -1,12 +1,12 @@
 /*
- * Copyright 2006 Google Inc.
- * 
+ * Copyright 2007 Google Inc.
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -25,7 +25,7 @@
  * catch mouse and keyboard events.
  */
 public class FocusPanel extends SimplePanel implements HasFocus,
-    SourcesClickEvents, SourcesMouseEvents {
+    SourcesClickEvents, SourcesMouseEvents, SourcesMouseWheelEvents {
 
   static final FocusImpl impl = (FocusImpl) GWT.create(FocusImpl.class);
 
@@ -33,11 +33,12 @@
   private FocusListenerCollection focusListeners;
   private KeyboardListenerCollection keyboardListeners;
   private MouseListenerCollection mouseListeners;
+  private MouseWheelListenerCollection mouseWheelListeners;
 
   public FocusPanel() {
     super(impl.createFocusable());
     sinkEvents(Event.FOCUSEVENTS | Event.KEYEVENTS | Event.ONCLICK
-      | Event.MOUSEEVENTS);
+      | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL);
   }
 
   public FocusPanel(Widget child) {
@@ -73,6 +74,13 @@
     mouseListeners.add(listener);
   }
 
+  public void addMouseWheelListener(MouseWheelListener listener) {
+    if (mouseWheelListeners == null) {
+      mouseWheelListeners = new MouseWheelListenerCollection();
+    }
+    mouseWheelListeners.add(listener);
+  }
+
   public int getTabIndex() {
     return impl.getTabIndex(getElement());
   }
@@ -95,6 +103,12 @@
         }
         break;
 
+      case Event.ONMOUSEWHEEL:
+        if (mouseWheelListeners != null) {
+          mouseWheelListeners.fireMouseWheelEvent(this, event);
+        }
+        break;
+
       case Event.ONBLUR:
       case Event.ONFOCUS:
         if (focusListeners != null) {
@@ -136,6 +150,12 @@
     }
   }
 
+  public void removeMouseWheelListener(MouseWheelListener listener) {
+    if (mouseWheelListeners != null) {
+      mouseWheelListeners.remove(listener);
+    }
+  }
+
   public void setAccessKey(char key) {
     impl.setAccessKey(getElement(), key);
   }
diff --git a/user/src/com/google/gwt/user/client/ui/Image.java b/user/src/com/google/gwt/user/client/ui/Image.java
index 9bfb776..e373a76 100644
--- a/user/src/com/google/gwt/user/client/ui/Image.java
+++ b/user/src/com/google/gwt/user/client/ui/Image.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2007 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -34,19 +34,19 @@
  * image is constructed, and how it is transformed after construction. Methods
  * will operate differently depending on the mode that the image is in. These
  * differences are detailed in the documentation for each method.
- * 
+ *
  * <p>
  * If an image transitions between clipped mode and unclipped mode, any
  * {@link Element}-specific attributes added by the user (including style
  * attributes, style names, and style modifiers), except for event listeners,
  * will be lost.
  * </p>
- * 
+ *
  * <h3>CSS Style Rules</h3>
  * <ul class="css">
  * <li>.gwt-Image { }</li>
  * </ul>
- * 
+ *
  * Tranformations between clipped and unclipped state will result in a loss of
  * any style names that were set/added; the only style names that are preserved
  * are those that are mentioned in the static CSS style rules. Due to
@@ -55,14 +55,14 @@
  * expected when an image is in clipped mode. These limitations can usually be
  * easily worked around by encapsulating the image in a container widget that
  * can itself be styled.
- * 
+ *
  * <p>
  * <h3>Example</h3>
  * {@example com.google.gwt.examples.ImageExample}
  * </p>
  */
 public class Image extends Widget implements SourcesClickEvents,
-    SourcesMouseEvents, SourcesLoadEvents {
+    SourcesLoadEvents, SourcesMouseEvents, SourcesMouseWheelEvents {
 
   /**
    * Abstract class which is used to hold the state associated with an image
@@ -101,7 +101,7 @@
     UnclippedState(Image image) {
       image.setElement(DOM.createImg());
       image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONLOAD
-          | Event.ONERROR);
+          | Event.ONERROR | Event.ONMOUSEWHEEL);
     }
 
     UnclippedState(Image image, String url) {
@@ -183,7 +183,7 @@
        * because the root element is a wrapper element around the <img> element.
        * Since we are synthesizing a load event, we do not need to sink the
        * onload event.
-       * 
+       *
        * We use a deferred command here to simulate the native version of the
        * load event as closely as possible. In the native event case, it is
        * unlikely that a second load event would occur while you are in the load
@@ -273,7 +273,7 @@
 
   /**
    * Causes the browser to pre-fetch the image at a given URL.
-   * 
+   *
    * @param url the URL of the image to be prefetched
    */
   public static void prefetch(String url) {
@@ -285,6 +285,7 @@
   private ClickListenerCollection clickListeners;
   private LoadListenerCollection loadListeners;
   private MouseListenerCollection mouseListeners;
+  private MouseWheelListenerCollection mouseWheelListeners;
 
   private State state;
 
@@ -299,7 +300,7 @@
   /**
    * Creates an image with a specified URL. The load event will be fired once
    * the image at the given URL has been retrieved by the browser.
-   * 
+   *
    * @param url the URL of the image to be displayed
    */
   public Image(String url) {
@@ -316,7 +317,7 @@
    * the width and height are specified explicitly by the user, this behavior
    * will not cause problems with retrieving the width and height of a clipped
    * image in a load event handler.
-   * 
+   *
    * @param url the URL of the image to be displayed
    * @param left the horizontal co-ordinate of the upper-left vertex of the
    *          visibility rectangle
@@ -351,11 +352,18 @@
     mouseListeners.add(listener);
   }
 
+  public void addMouseWheelListener(MouseWheelListener listener) {
+    if (mouseWheelListeners == null) {
+      mouseWheelListeners = new MouseWheelListenerCollection();
+    }
+    mouseWheelListeners.add(listener);
+  }
+
   /**
    * Gets the height of the image. When the image is in the unclipped state, the
    * height of the image is not known until the image has been loaded (i.e. load
    * event has been fired for the image).
-   * 
+   *
    * @return the height of the image, or 0 if the height is unknown
    */
   public int getHeight() {
@@ -367,7 +375,7 @@
    * visibility rectangle. If the image is in the unclipped state, then the
    * visibility rectangle is assumed to be the rectangle which encompasses the
    * entire image, which has an upper-left vertex of (0,0).
-   * 
+   *
    * @return the horizontal co-ordinate of the upper-left vertex of the image's
    *         visibility rectangle
    */
@@ -380,7 +388,7 @@
    * visibility rectangle. If the image is in the unclipped state, then the
    * visibility rectangle is assumed to be the rectangle which encompasses the
    * entire image, which has an upper-left vertex of (0,0).
-   * 
+   *
    * @return the vertical co-ordinate of the upper-left vertex of the image's
    *         visibility rectangle
    */
@@ -392,7 +400,7 @@
    * Gets the URL of the image. The URL that is returned is not necessarily the
    * URL that was passed in by the user. It may have been transformed to an
    * absolute URL.
-   * 
+   *
    * @return the image URL
    */
   public String getUrl() {
@@ -403,7 +411,7 @@
    * Gets the width of the image. When the image is in the unclipped state, the
    * width of the image is not known until the image has been loaded (i.e. load
    * event has been fired for the image).
-   * 
+   *
    * @return the width of the image, or 0 if the width is unknown
    */
   public int getWidth() {
@@ -428,6 +436,11 @@
         }
         break;
       }
+      case Event.ONMOUSEWHEEL:
+        if (mouseWheelListeners != null) {
+          mouseWheelListeners.fireMouseWheelEvent(this, event);
+        }
+        break;
       case Event.ONLOAD: {
         if (loadListeners != null) {
           loadListeners.fireLoad(this);
@@ -461,12 +474,18 @@
     }
   }
 
+  public void removeMouseWheelListener(MouseWheelListener listener) {
+    if (mouseWheelListeners != null) {
+      mouseWheelListeners.remove(listener);
+    }
+  }
+
   /**
    * Sets the URL of the image to be displayed. If the image is in the clipped
    * state, a call to this method will cause a transition of the image to the
    * unclipped state. Regardless of whether or not the image is in the clipped
    * or unclipped state, a load event will be fired.
-   * 
+   *
    * @param url the image URL
    */
   public void setUrl(String url) {
@@ -480,7 +499,7 @@
    * visibility rectangle co-ordinates. If the image is currently in the
    * unclipped state, a call to this method will cause a transition to the
    * clipped state.
-   * 
+   *
    * @param url the image URL
    * @param left the horizontal coordinate of the upper-left vertex of the
    *          visibility rectangle
@@ -503,7 +522,7 @@
    * is in the unclipped state, a call to this method will cause a transition of
    * the image to the clipped state. This transition will cause a load event to
    * fire.
-   * 
+   *
    * @param left the horizontal coordinate of the upper-left vertex of the
    *          visibility rectangle
    * @param top the vertical coordinate of the upper-left vertex of the
diff --git a/user/src/com/google/gwt/user/client/ui/Label.java b/user/src/com/google/gwt/user/client/ui/Label.java
index 2046301..2bceecd 100644
--- a/user/src/com/google/gwt/user/client/ui/Label.java
+++ b/user/src/com/google/gwt/user/client/ui/Label.java
@@ -1,12 +1,12 @@
 /*
- * Copyright 2006 Google Inc.
- * 
+ * Copyright 2007 Google Inc.
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -20,35 +20,37 @@
 
 /**
  * A widget that contains arbitrary text, <i>not</i> interpreted as HTML.
- * 
+ *
  * <h3>CSS Style Rules</h3>
  * <ul class='css'>
  * <li>.gwt-Label { }</li>
  * </ul>
- * 
+ *
  * <p>
  * <h3>Example</h3> {@example com.google.gwt.examples.HTMLExample}
  * </p>
  */
 public class Label extends Widget implements SourcesClickEvents,
-    SourcesMouseEvents, HasHorizontalAlignment, HasText, HasWordWrap {
+    SourcesMouseEvents, SourcesMouseWheelEvents,
+    HasHorizontalAlignment, HasText, HasWordWrap {
 
   private ClickListenerCollection clickListeners;
   private HorizontalAlignmentConstant horzAlign;
   private MouseListenerCollection mouseListeners;
+  private MouseWheelListenerCollection mouseWheelListeners;
 
   /**
    * Creates an empty label.
    */
   public Label() {
     setElement(DOM.createDiv());
-    sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS);
+    sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL);
     setStyleName("gwt-Label");
   }
 
   /**
    * Creates a label with the specified text.
-   * 
+   *
    * @param text the new label's text
    */
   public Label(String text) {
@@ -58,7 +60,7 @@
 
   /**
    * Creates a label with the specified text.
-   * 
+   *
    * @param text the new label's text
    * @param wordWrap <code>false</code> to disable word wrapping
    */
@@ -81,6 +83,13 @@
     mouseListeners.add(listener);
   }
 
+  public void addMouseWheelListener(MouseWheelListener listener) {
+    if (mouseWheelListeners == null) {
+      mouseWheelListeners = new MouseWheelListenerCollection();
+    }
+    mouseWheelListeners.add(listener);
+  }
+
   public HorizontalAlignmentConstant getHorizontalAlignment() {
     return horzAlign;
   }
@@ -110,6 +119,12 @@
           mouseListeners.fireMouseEvent(this, event);
         }
         break;
+
+      case Event.ONMOUSEWHEEL:
+        if (mouseWheelListeners != null) {
+          mouseWheelListeners.fireMouseWheelEvent(this, event);
+        }
+        break;
     }
   }
 
@@ -125,6 +140,12 @@
     }
   }
 
+  public void removeMouseWheelListener(MouseWheelListener listener) {
+    if (mouseWheelListeners != null) {
+      mouseWheelListeners.remove(listener);
+    }
+  }
+
   public void setHorizontalAlignment(HorizontalAlignmentConstant align) {
     horzAlign = align;
     DOM
diff --git a/user/src/com/google/gwt/user/client/ui/MouseWheelListener.java b/user/src/com/google/gwt/user/client/ui/MouseWheelListener.java
new file mode 100644
index 0000000..fef1870
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/MouseWheelListener.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import java.util.EventListener;
+
+/**
+ * Event listener interface for mouse wheel events.
+ */
+public interface MouseWheelListener extends EventListener {
+
+  /**
+   * Fired when the user scrolls the mouse wheel over a widget.
+   *
+   * @param sender the widget sending the event
+   * @param x the x coordinate of the mouse
+   * @param y the y coordinate of the mouse
+   * @param velocity the velocity information for the wheel event
+   */
+  void onMouseWheel(Widget sender, int x, int y, MouseWheelVelocity velocity);
+}
diff --git a/user/src/com/google/gwt/user/client/ui/MouseWheelListenerCollection.java b/user/src/com/google/gwt/user/client/ui/MouseWheelListenerCollection.java
new file mode 100644
index 0000000..1cb2906
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/MouseWheelListenerCollection.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+/**
+ * A helper class for implementers of the SourcesMouseWheelEvents interface.
+ * This subclass of Vector assumes that all objects added to it will be of type
+ * {@link com.google.gwt.user.client.ui.MouseWheelListener}.
+ */
+public class MouseWheelListenerCollection extends Vector {
+
+  /**
+   * Fires a mouse wheel event to all listeners.
+   *
+   * @param sender the widget sending the event
+   * @param x the x coordinate of the mouse
+   * @param y the y coordinate of the mouse
+   * @param velocity the velocity information for the event
+   */
+  public void fireMouseWheel(Widget sender, int x, int y,
+      MouseWheelVelocity velocity) {
+
+    for (Iterator it = iterator(); it.hasNext();) {
+      MouseWheelListener listener = (MouseWheelListener) it.next();
+      listener.onMouseWheel(sender, x, y, velocity);
+    }
+  }
+
+  /**
+   * A helper for widgets that source mouse events.
+   *
+   * @param sender the widget sending the event
+   * @param event the {@link Event} received by the widget
+   */
+  public void fireMouseWheelEvent(Widget sender, Event event) {
+    if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) {
+      int x = DOM.eventGetClientX(event)
+          - DOM.getAbsoluteLeft(sender.getElement());
+      int y = DOM.eventGetClientY(event)
+          - DOM.getAbsoluteTop(sender.getElement());
+      MouseWheelVelocity velocity = new MouseWheelVelocity(event);
+
+      fireMouseWheel(sender, x, y, velocity);
+    }
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/MouseWheelVelocity.java b/user/src/com/google/gwt/user/client/ui/MouseWheelVelocity.java
new file mode 100644
index 0000000..88c7811
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/MouseWheelVelocity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+
+/**
+ * Encapsulates the direction and velocity of mouse wheel events.  Not all
+ * combinations of browser and user input devices can generate all combinations
+ * of direction or range of velocity information.
+ *
+ * @see com.google.gwt.user.client.DOM#eventGetMouseWheelVelocityY
+ *   An explanation of the units used for mouse wheel velocity.
+ */
+public class MouseWheelVelocity {
+
+  /**
+   * Stores the Y-axis velocity.
+   */
+  protected final int vY;
+
+  /**
+   *  Construct the higher-level view of the original ONMOUSEWHEEL Event.
+   * @param e the event
+   */
+  public MouseWheelVelocity(Event e) {
+    vY = DOM.eventGetMouseWheelVelocityY(e);
+  }
+
+  public boolean equals(Object o) {
+    if (o instanceof MouseWheelVelocity) {
+      MouseWheelVelocity v = (MouseWheelVelocity)o;
+      return getVelocityY() == v.getVelocityY();
+    }
+
+    return false;
+  }
+
+  /**
+   * @return The velocity of the mouse wheel event along the Y-axis
+   */
+  public int getVelocityY() {
+    return vY;
+  }
+
+  public int hashCode() {
+    return getVelocityY();
+  }
+
+  /**
+   * @return <code>true</code> if the velocity includes a component directed
+   *         toword the top of the screen
+   */
+  public boolean isNorth() {
+    return getVelocityY() < 0;
+  }
+
+  /**
+   * @return <code>true</code> if the velocity includes a component directed
+   *         toword the bottom of the screen
+   */
+  public boolean isSouth() {
+    return getVelocityY() > 0;
+  }
+
+  public String toString() {
+    return "<" + getVelocityY() + ">";
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/SourcesMouseWheelEvents.java b/user/src/com/google/gwt/user/client/ui/SourcesMouseWheelEvents.java
new file mode 100644
index 0000000..0744fec
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/SourcesMouseWheelEvents.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+/**
+ * A widget that implements this interface sources the events defined by the
+ * {@link com.google.gwt.user.client.ui.MouseWheelListener} interface.
+ */
+public interface SourcesMouseWheelEvents {
+
+  /**
+   * Adds a listener interface to receive mouse events.
+   *
+   * @param listener the listener interface to add
+   */
+  void addMouseWheelListener(MouseWheelListener listener);
+
+  /**
+   * Removes a previously added listener interface.
+   *
+   * @param listener the listener interface to remove
+   */
+  void removeMouseWheelListener(MouseWheelListener listener);
+}