Adding drag and drop support to the mobile web app. The desktop TaskEditView now has a list of templates.  Users can drag a template over the edit form to populate the fields.

I found a few holes in the drag and drop API, which are also fixed in this patch. I added the missing DragStartEvent, DragEvent, and DragEndEvent, which are part of the HTML5 spec. Also, the native dragexit event is deprecated and only used by older versions of firefox, so I switch the DragExitEvent to use the correct event type "dragleave". I modified sinkEvents to handle the new bitless drag event types. I also added the DataTransfer JSO, which is required to actually use drag and drop (I didn't implement the entire API until I have more time to test the other methods in DataTransfer, but the important ones are there).

I updated DragAndDropEventsSinkTest to use a WidgetCreator instead of duplicating code all over the place. Also, we don't need to test every subclass of FocusWidget, since FocusWidget itself adds the drag handlers.

Demo at http://gwt-cloudtasks.appspot.com/.  Note that in IE9, you have to select text before you can trigger a drag event, and you must drop directly over the input boxes in the form.  In other browsers, this is not the case.

Review at http://gwt-code-reviews.appspot.com/1420811

Review by: rice@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10138 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.css b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.css
new file mode 100644
index 0000000..a449793
--- /dev/null
+++ b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.css
@@ -0,0 +1,10 @@
+.taskTemplateCell {
+  margin: 8px;
+  border: 1px solid #666;
+  -moz-border-radius: 8px;
+  border-radius: 8px;
+  padding: 18px 10px;
+  font-size: 12pt;
+  background-color: #eee;
+  -webkit-user-drag: element;
+}
diff --git a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.java b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.java
index 6ad5749..4bae38c 100644
--- a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.java
+++ b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.java
@@ -15,25 +15,50 @@
  */
 package com.google.gwt.sample.mobilewebapp.client.desktop;
 
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.ValueUpdater;
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.DataTransfer;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.EventTarget;
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.DragDropEventBase;
+import com.google.gwt.event.dom.client.DragLeaveEvent;
+import com.google.gwt.event.dom.client.DragLeaveHandler;
+import com.google.gwt.event.dom.client.DragOverEvent;
+import com.google.gwt.event.dom.client.DragOverHandler;
+import com.google.gwt.event.dom.client.DropEvent;
+import com.google.gwt.event.dom.client.DropHandler;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
 import com.google.gwt.sample.mobilewebapp.client.activity.TaskEditView;
 import com.google.gwt.sample.mobilewebapp.client.ui.DateButton;
 import com.google.gwt.sample.mobilewebapp.client.ui.EditorDecorator;
 import com.google.gwt.sample.mobilewebapp.shared.TaskProxy;
+import com.google.gwt.sample.mobilewebapp.shared.TaskProxyImpl;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.cellview.client.CellList;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.DecoratedPopupPanel;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
+import com.google.gwt.user.client.ui.HTMLPanel;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.PopupPanel;
 import com.google.gwt.user.client.ui.TextBoxBase;
 import com.google.gwt.user.client.ui.Widget;
 import com.google.web.bindery.requestfactory.gwt.client.RequestFactoryEditorDriver;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * View used to edit a task.
  */
@@ -46,8 +71,66 @@
   }
 
   /**
-   * Editor driver for this view.
+   * A ClientBundle that provides images for this widget.
    */
+  interface Resources extends ClientBundle {
+    @Source("DesktopTaskEditView.css")
+    Style style();
+  }
+
+  /**
+   * The styles used in this widget.
+   */
+  interface Style extends CssResource {
+    /**
+     * Applies to the cells in the task template list.
+     */
+    String taskTemplateCell();
+  }
+
+  /**
+   * The cell used to render task templates.
+   */
+  static class TaskTemplateCell extends AbstractCell<TaskProxy> {
+
+    interface Template extends SafeHtmlTemplates {
+      @SafeHtmlTemplates.Template("<div class=\"{0}\" draggable=\"true\">"
+          + "{1}<div style=\"font-size:80%;\">{2}</div></div>")
+      SafeHtml task(String className, String name, String notes);
+    }
+
+    private Template template = GWT.create(Template.class);
+    private final String className;
+
+    public TaskTemplateCell(String className) {
+      super("dragstart");
+      this.className = className;
+    }
+
+    @Override
+    public void onBrowserEvent(Context context, Element parent, TaskProxy value, NativeEvent event,
+        ValueUpdater<TaskProxy> valueUpdater) {
+      if ("dragstart".equals(event.getType())) {
+        // Save the ID of the TaskProxy.
+        DataTransfer dataTransfer = event.getDataTransfer();
+        dataTransfer.setData("text", String.valueOf(context.getIndex()));
+
+        // Set the image.
+        dataTransfer.setDragImage(parent, 25, 15);
+      }
+    }
+
+    @Override
+    public void render(Context context, TaskProxy value, SafeHtmlBuilder sb) {
+      if (value == null) {
+        return;
+      }
+
+      String notes = value.getNotes();
+      sb.append(template.task(className, value.getName(), (notes == null) ? "" : notes));
+    }
+  }
+
   interface Driver extends RequestFactoryEditorDriver<TaskProxy, DesktopTaskEditView> {
   }
 
@@ -84,6 +167,15 @@
   }
 
   @UiField
+  DockLayoutPanel dockLayoutPanel;
+
+  /**
+   * The panel that contains the edit form.
+   */
+  @UiField
+  HTMLPanel editForm;
+
+  @UiField
   Button deleteButton;
   @UiField
   DateButton dueDateEditor;
@@ -98,6 +190,12 @@
   @UiField
   Button saveButton;
 
+  @UiField(provided = true)
+  final CellList<TaskProxy> templateList;
+
+  @UiField
+  Widget templateListContainer;
+
   private final Driver driver = GWT.create(Driver.class);
 
   /**
@@ -105,14 +203,28 @@
    */
   private Presenter presenter;
 
+  private final Resources resources;
+
   /**
    * Construct a new {@link DesktopTaskEditView}.
    */
   public DesktopTaskEditView() {
+    // Initialize the styles.
+    resources = GWT.create(Resources.class);
+    resources.style().ensureInjected();
+
+    // Create the template list.
+    templateList = createTaskTemplateList();
+
     initWidget(uiBinder.createAndBindUi(this));
     nameEditor = EditorDecorator.create(nameField.asEditor(), nameViolation);
     driver.initialize(this);
 
+    // Hide the template list if it isn't supported.
+    if (!DragDropEventBase.isSupported()) {
+      dockLayoutPanel.setWidgetSize(templateListContainer, 0);
+    }
+
     // Create a new task or modify the current task when done is pressed.
     saveButton.addClickHandler(new ClickHandler() {
       public void onClick(ClickEvent event) {
@@ -130,6 +242,52 @@
         }
       }
     });
+
+    // Add the form as a drop target.
+    editForm.addDomHandler(new DragOverHandler() {
+      public void onDragOver(DragOverEvent event) {
+        // Highlight the name and notes box.
+        nameField.getElement().getStyle().setBackgroundColor("#ffa");
+        notesEditor.getElement().getStyle().setBackgroundColor("#ffa");
+      }
+    }, DragOverEvent.getType());
+    editForm.addDomHandler(new DragLeaveHandler() {
+      public void onDragLeave(DragLeaveEvent event) {
+        EventTarget eventTarget = event.getNativeEvent().getEventTarget();
+        if (!Element.is(eventTarget)) {
+          return;
+        }
+        Element target = Element.as(eventTarget);
+
+        if (target == editForm.getElement()) {
+          // Un-highlight the name and notes box.
+          nameField.getElement().getStyle().clearBackgroundColor();
+          notesEditor.getElement().getStyle().clearBackgroundColor();
+        }
+      }
+    }, DragLeaveEvent.getType());
+    editForm.addDomHandler(new DropHandler() {
+      public void onDrop(DropEvent event) {
+        // Prevent the default text drop.
+        event.preventDefault();
+
+        // Un-highlight the name and notes box.
+        nameField.getElement().getStyle().clearBackgroundColor();
+        notesEditor.getElement().getStyle().clearBackgroundColor();
+
+        // Fill in the form.
+        try {
+          // Get the template the from the data transfer object.
+          DataTransfer dataTransfer = event.getNativeEvent().getDataTransfer();
+          int templateIndex = Integer.parseInt(dataTransfer.getData("text"));
+          TaskProxy template = templateList.getVisibleItem(templateIndex);
+          nameField.setValue(template.getName());
+          notesEditor.setValue(template.getNotes());
+        } catch (NumberFormatException e) {
+          // The user probably dragged something other than a template.
+        }
+      }
+    }, DropEvent.getType());
   }
 
   public RequestFactoryEditorDriver<TaskProxy, ?> getEditorDriver() {
@@ -156,4 +314,19 @@
     this.presenter = presenter;
   }
 
+  private CellList<TaskProxy> createTaskTemplateList() {
+    CellList<TaskProxy> list =
+        new CellList<TaskProxy>(new TaskTemplateCell(resources.style().taskTemplateCell()));
+    list.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED);
+
+    // Create the templates.
+    List<TaskProxy> templates = new ArrayList<TaskProxy>();
+    templates.add(new TaskProxyImpl("Call mom", null));
+    templates.add(new TaskProxyImpl("Register to vote", "Where is my polling location again?"));
+    templates.add(new TaskProxyImpl("Replace air filter", "Size: 24x13x1"));
+    templates.add(new TaskProxyImpl("Take out the trash", null));
+    list.setRowData(templates);
+
+    return list;
+  }
 }
diff --git a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.ui.xml b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.ui.xml
index 584f643..4eb84b5 100644
--- a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.ui.xml
+++ b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskEditView.ui.xml
@@ -2,6 +2,7 @@
 <ui:UiBinder
   xmlns:ui="urn:ui:com.google.gwt.uibinder"
   xmlns:g="urn:import:com.google.gwt.user.client.ui"
+  xmlns:c="urn:import:com.google.gwt.user.cellview.client"
   xmlns:app="urn:import:com.google.gwt.sample.mobilewebapp.client.ui">
 
   <ui:style>
@@ -65,79 +66,108 @@
       color: white;
       background: #940000;
     }
+    
+    .templateList {
+      border-left: 1px solid #aaa;
+    }
   </ui:style>
 
-  <!-- Edit Form. -->
-  <g:HTMLPanel
-    addStyleNames="{style.editForm}">
-    <table
-      cellspacing="10"
-      align="center">
+  <g:DockLayoutPanel
+    ui:field="dockLayoutPanel"
+    unit="PX">
+    <!-- Edit Form. -->
+    <g:center>
+      <g:HTMLPanel
+        ui:field="editForm"
+        addStyleNames="{style.editForm}">
+        <table
+          cellspacing="10"
+          align="center">
 
-      <!-- Form title. -->
-      <tr>
-        <td
-          align='center'
-          colspan='2'
-          class="{style.title}">Task Details</td>
-      </tr>
+          <!-- Form title. -->
+          <tr>
+            <td
+              align='center'
+              colspan='2'
+              class="{style.title}">Task Details</td>
+          </tr>
 
-      <!-- Task name. -->
-      <tr>
-        <td
-          class="{style.label}">Task Name:</td>
-        <td
-          class="{style.textBoxWrapper}">
-          <g:TextBox
-            addStyleNames="{style.field}"
-            ui:field="nameField" />
-        </td>
-      </tr>
-      <tr>
-        <td></td>
-        <td
-          ui:field="nameViolation"
-          class="{style.violation}">
-        </td>
-      </tr>
+          <!-- Task name. -->
+          <tr>
+            <td
+              class="{style.label}">Task Name:</td>
+            <td
+              class="{style.textBoxWrapper}">
+              <g:TextBox
+                addStyleNames="{style.field}"
+                ui:field="nameField" />
+            </td>
+          </tr>
+          <tr>
+            <td></td>
+            <td
+              ui:field="nameViolation"
+              class="{style.violation}">
+            </td>
+          </tr>
 
-      <!-- Task notes. -->
-      <tr>
-        <td
-          class="{style.label}">Notes:</td>
-        <td
-          class="{style.textBoxWrapper}">
-          <g:TextArea
-            addStyleNames="{style.field} {style.notesBox}"
-            ui:field="notesEditor" />
-        </td>
-      </tr>
+          <!-- Task notes. -->
+          <tr>
+            <td
+              class="{style.label}">Notes:</td>
+            <td
+              class="{style.textBoxWrapper}">
+              <g:TextArea
+                addStyleNames="{style.field} {style.notesBox}"
+                ui:field="notesEditor" />
+            </td>
+          </tr>
 
-      <!-- Task due date. -->
-      <tr>
-        <td
-          class="{style.label}">Due date:</td>
-        <td>
-          <app:DateButton
-            addStyleNames="{style.field} {style.button} {style.dateButton}"
-            ui:field="dueDateEditor" />
-        </td>
-      </tr>
+          <!-- Task due date. -->
+          <tr>
+            <td
+              class="{style.label}">Due date:</td>
+            <td>
+              <app:DateButton
+                addStyleNames="{style.field} {style.button} {style.dateButton}"
+                ui:field="dueDateEditor" />
+            </td>
+          </tr>
 
-      <!-- Button panel. -->
-      <tr
-        class="{style.buttonPanel}">
-        <td></td>
-        <td
-          align='center'>
-          <g:Button
-            ui:field="saveButton"
-            addStyleNames="{style.button} {style.saveButton}">Done</g:Button>
-          <g:Button
-            ui:field="deleteButton"
-            addStyleNames="{style.button} {style.deleteButton}">Delete Item</g:Button>
-        </td>
-      </tr>
-    </table>
-  </g:HTMLPanel>
+          <!-- Button panel. -->
+          <tr
+            class="{style.buttonPanel}">
+            <td></td>
+            <td
+              align='center'>
+              <g:Button
+                ui:field="saveButton"
+                addStyleNames="{style.button} {style.saveButton}">Done</g:Button>
+              <g:Button
+                ui:field="deleteButton"
+                addStyleNames="{style.button} {style.deleteButton}">Delete Item</g:Button>
+            </td>
+          </tr>
+        </table>
+      </g:HTMLPanel>
+    </g:center>
+
+    <!-- Templates. -->
+    <g:east
+      size="250">
+      <g:ScrollPanel
+        ui:field="templateListContainer"
+        addStyleNames="{style.templateList}">
+        <g:HTMLPanel>
+          <b>Templates:</b>
+          <br />
+          Drag a template over the form to the left use it.
+          <c:CellList
+            ui:field="templateList" />
+        </g:HTMLPanel>
+      </g:ScrollPanel>
+    </g:east>
+
+  </g:DockLayoutPanel>
+
 </ui:UiBinder> 
diff --git a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/MobileWebAppShellDesktop.java b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/MobileWebAppShellDesktop.java
index 49d7647..c186bd4 100644
--- a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/MobileWebAppShellDesktop.java
+++ b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/client/desktop/MobileWebAppShellDesktop.java
@@ -36,7 +36,6 @@
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
 import com.google.gwt.user.cellview.client.CellList;
-import com.google.gwt.user.cellview.client.CellList.Style;
 import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.Anchor;
@@ -82,7 +81,7 @@
      * MainMenuCellList.css.
      */
     @Source({"MainMenuCellList.css", CellList.Style.DEFAULT_CSS})
-    Style cellListStyle();
+    MainMenuStyle cellListStyle();
   }
 
   /**
diff --git a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/shared/TaskProxyImpl.java b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/shared/TaskProxyImpl.java
index 0b0572c..81f3e3e 100644
--- a/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/shared/TaskProxyImpl.java
+++ b/samples/mobilewebapp/src/main/com/google/gwt/sample/mobilewebapp/shared/TaskProxyImpl.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2011 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
@@ -31,6 +31,11 @@
   public TaskProxyImpl() {
   }
 
+  public TaskProxyImpl(String name, String notes) {
+    this.name = name;
+    this.notes = notes;
+  }
+
   public Date getDueDate() {
     return dueDate;
   }
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java
index d917be0..881aded 100644
--- a/user/src/com/google/gwt/dom/client/DOMImpl.java
+++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -367,6 +367,10 @@
     select.remove(index);
   }-*/;
 
+  public native void setDraggable(Element elem, String draggable) /*-{
+    elem.draggable = draggable;
+  }-*/;
+
   public native void setInnerText(Element elem, String text) /*-{
     // Remove all children first.
     while (elem.firstChild) {
diff --git a/user/src/com/google/gwt/dom/client/DOMImplWebkit.java b/user/src/com/google/gwt/dom/client/DOMImplWebkit.java
index cff3081..cffb2f0 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplWebkit.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplWebkit.java
@@ -16,7 +16,7 @@
 package com.google.gwt.dom.client;
 
 /**
- * WebKit based implementation of {@link com.google.gwt.user.client.impl.DOMImplStandardBase}.
+ * WebKit based implementation of {@link com.google.gwt.dom.client.DOMImplStandardBase}.
  */
 class DOMImplWebkit extends DOMImplStandardBase {
 
@@ -35,5 +35,19 @@
     }
     return false;
   }-*/;
+
+  /**
+   * Webkit based browsers require that we set the webkit-user-drag style
+   * attribute to make an element draggable.
+   */
+  @Override
+  public void setDraggable(Element elem, String draggable) {
+    super.setDraggable(elem, draggable);
+    if ("true".equals(draggable)) {
+      elem.getStyle().setProperty("webkitUserDrag", "element");
+    } else {
+      elem.getStyle().clearProperty("webkitUserDrag");
+    }
+  }
 }
 
diff --git a/user/src/com/google/gwt/dom/client/DataTransfer.java b/user/src/com/google/gwt/dom/client/DataTransfer.java
new file mode 100644
index 0000000..b7414a3
--- /dev/null
+++ b/user/src/com/google/gwt/dom/client/DataTransfer.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011 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.dom.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+/**
+ * Class representing DataTransfer interface.
+ * 
+ * <p>
+ * <span style="color:red">Experimental API: This API is still under development
+ * and is subject to change. </span>
+ * </p>
+ * 
+ * @see <a
+ *      href="http://www.w3.org/TR/html5/dnd.html#the-datatransfer-interface">W3C
+ *      HTML Specification</a>
+ */
+public class DataTransfer extends JavaScriptObject {
+
+  /**
+   * Required constructor for GWT compiler to function.
+   */
+  protected DataTransfer() {
+  }
+
+  /**
+   * Remove all data from the current drag sequence.
+   * 
+   * @see <a
+   *      href="http://www.w3.org/TR/html5/dnd.html#dom-datatransfer-cleardata">W3C
+   *      Specification</a>
+   */
+  public final native void clearData() /*-{
+    this.clearData();
+  }-*/;
+
+  /**
+   * Remove the data for the specified format for all drag events in the current
+   * drag sequence.
+   * 
+   * @param format the format, which is usually the mime-type of the associated
+   *          data
+   * @see #setData(String, String)
+   * @see <a
+   *      href="http://www.w3.org/TR/html5/dnd.html#dom-datatransfer-cleardata">W3C
+   *      Specification</a>
+   */
+  public final native void clearData(String format) /*-{
+    this.clearData(format);
+  }-*/;
+
+  /**
+   * Get the data for the specified format. The data may have been set in a
+   * previous drag event that is part of the current drag sequence.
+   * 
+   * @param format the format, which is usually the mime-type of the data
+   * @return the data for the specified format
+   * @see #setData(String, String)
+   * @see <a
+   *      href="http://www.w3.org/TR/html5/dnd.html#dom-datatransfer-getdata">W3C
+   *      Specification</a>
+   */
+  public final native String getData(String format) /*-{
+    return this.getData(format);
+  }-*/;
+
+  /**
+   * Set the data for the specified format to associate with all drag events in
+   * the current drag and drop sequence. The data can be read using
+   * {@link #getData(String)} from any subsequent drag events in this sequence
+   * (such as the drop event).
+   * 
+   * <p>
+   * The format is usually the mime-type of the data, but can also be
+   * <code>text</code>.
+   * </p>
+   * 
+   * @param format the format, which is usually the mime-type of the data
+   * @param data the data to associate with the format
+   * @see <a
+   *      href="http://www.w3.org/TR/html5/dnd.html#dom-datatransfer-setdata">W3C
+   *      Specification</a>
+   */
+  public final native void setData(String format, String data) /*-{
+    this.setData(format, data);
+  }-*/;
+
+  /**
+   * Specify the element to use to update the drag feedback.
+   * 
+   * @param element the feedback image
+   * @param x the x offset of the cursor
+   * @param y the y offset of the cursor
+   * @see <a
+   *      href="http://www.w3.org/TR/html5/dnd.html#dom-datatransfer-setdragimage">W3C
+   *      Specification</a>
+   */
+  public final native void setDragImage(Element element, int x, int y) /*-{
+    if (this.setDragImage) {
+      this.setDragImage(element, x, y);
+    }
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/dom/client/Element.java b/user/src/com/google/gwt/dom/client/Element.java
index bbcac2d..3a11935 100644
--- a/user/src/com/google/gwt/dom/client/Element.java
+++ b/user/src/com/google/gwt/dom/client/Element.java
@@ -23,6 +23,21 @@
 public class Element extends Node {
 
   /**
+   * Constant returned from {@link #getDraggable()}.
+   */
+  public static final String DRAGGABLE_AUTO = "auto";
+
+  /**
+   * Constant returned from {@link #getDraggable()}.
+   */
+  public static final String DRAGGABLE_FALSE = "false";
+
+  /**
+   * Constant returned from {@link #getDraggable()}.
+   */
+  public static final String DRAGGABLE_TRUE = "true";
+
+  /**
    * Assert that the given {@link Node} is an {@link Element} and automatically
    * typecast it.
    */
@@ -221,6 +236,16 @@
    }-*/;
 
   /**
+   * Returns the draggable attribute of this element.
+   * 
+   * @return one of {@link #DRAGGABLE_AUTO}, {@link #DRAGGABLE_FALSE}, or
+   *         {@link #DRAGGABLE_TRUE}
+   */
+  public final native String getDraggable() /*-{
+    return this.draggable || null;
+  }-*/;
+
+  /**
    * Returns a NodeList of all descendant Elements with a given tag name, in the
    * order in which they are encountered in a preorder traversal of this Element
    * tree.
@@ -597,6 +622,16 @@
    }-*/;
 
   /**
+   * Changes the draggable attribute to one of {@link #DRAGGABLE_AUTO},
+   * {@link #DRAGGABLE_FALSE}, or {@link #DRAGGABLE_TRUE}.
+   * 
+   * @param draggable a String constants
+   */
+  public final void setDraggable(String draggable) {
+    DOMImpl.impl.setDraggable(this, draggable);
+  }
+
+  /**
    * The element's identifier.
    * 
    * @see <a
diff --git a/user/src/com/google/gwt/dom/client/NativeEvent.java b/user/src/com/google/gwt/dom/client/NativeEvent.java
index af8bd8b..3954c26 100644
--- a/user/src/com/google/gwt/dom/client/NativeEvent.java
+++ b/user/src/com/google/gwt/dom/client/NativeEvent.java
@@ -120,6 +120,15 @@
   }
 
   /**
+   * Get the {@link DataTransfer} associated with the current drag event.
+   * 
+   * @return the {@link DataTransfer} object, or null if not a drag event
+   */
+  public final native DataTransfer getDataTransfer() /*-{
+    return this.dataTransfer || null;
+  }-*/;
+
+  /**
    * Returns the element that was the actual target of the given event.
    * 
    * @return the target element
diff --git a/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml b/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
index 12d921e..129f88c 100644
--- a/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
+++ b/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
@@ -1,6 +1,7 @@
 <module>
   <inherits name="com.google.gwt.dom.DOM" />
   <inherits name="com.google.gwt.event.EventBase" />
+  <inherits name="com.google.gwt.event.dom.DragEvent" />
   <inherits name="com.google.gwt.event.dom.TouchEvent" />
   <source path="client"/>
 </module>
diff --git a/user/src/com/google/gwt/event/dom/DragEvent.gwt.xml b/user/src/com/google/gwt/event/dom/DragEvent.gwt.xml
new file mode 100644
index 0000000..a785c1e
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/DragEvent.gwt.xml
@@ -0,0 +1,38 @@
+<!--                                                                        -->
+<!-- Copyright 2011 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   -->
+<!-- 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. License for the specific language governing permissions and   -->
+<!-- limitations under the License.                                         -->
+<module>
+  <inherits name="com.google.gwt.user.User" />
+
+  <!-- Define the support property -->
+  <define-property name="dragEventSupport" values="maybe,no" />
+
+  <!--
+    Modern browsers either support drag events or will probably add drag
+    support in the future.
+  -->
+  <set-property name="dragEventSupport" value="maybe" />
+
+  <!-- Older browsers do not support drag events. -->
+  <set-property name="dragEventSupport" value="no">
+    <any>
+      <when-property-is name="user.agent" value="ie6" />
+      <when-property-is name="user.agent" value="ie8" />
+    </any>
+  </set-property>
+
+  <replace-with class="com.google.gwt.event.dom.DragDropEventBase.DragSupportDetectorNo">
+    <when-type-is class="com.google.gwt.event.dom.DragDropEventBase.DragSupportDetector" />
+    <when-property-is name="dragEventSupport" value="no" />
+  </replace-with>
+</module>
diff --git a/user/src/com/google/gwt/event/dom/client/DragDropEventBase.java b/user/src/com/google/gwt/event/dom/client/DragDropEventBase.java
new file mode 100644
index 0000000..0612b3e
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/DragDropEventBase.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2011 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.event.dom.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.DataTransfer;
+import com.google.gwt.dom.client.PartialSupport;
+import com.google.gwt.event.shared.EventHandler;
+
+/**
+ * Base class for drag and drop events.
+ * 
+ * @param <H> handler type
+ */
+@PartialSupport
+public abstract class DragDropEventBase<H extends EventHandler> extends DomEvent<H> {
+
+  /**
+   * Detector for browser support of drag events.
+   */
+  static class DragSupportDetector {
+
+    private final boolean isSupported = detectDragSupport();
+
+    /**
+     * Using a run-time check, return true if drag events are supported.
+     * 
+     * @return true if supported, false otherwise.
+     */
+    public boolean isSupported() {
+      return isSupported;
+    }
+
+    private native boolean detectDragSupport() /*-{
+      var elem = document.createElement('div');
+      elem.setAttribute('ondragstart', 'return;');
+      return (typeof elem.ondragstart) == "function";
+    }-*/;
+  }
+
+  /**
+   * Detector for permutations that do not support drag events.
+   */
+  static class DragSupportDetectorNo extends DragSupportDetector {
+    @Override
+    public boolean isSupported() {
+      return false;
+    }
+  }
+
+  /**
+   * The implementation singleton.
+   */
+  private static DragSupportDetector impl;
+
+  /**
+   * Runtime check for whether drag events are supported in this browser.
+   * 
+   * @return true if supported, false if not
+   */
+  public static boolean isSupported() {
+    if (impl == null) {
+      impl = GWT.create(DragSupportDetector.class);
+    }
+    return impl.isSupported();
+  }
+
+  /**
+   * Get the data for the specified format from the {@link DataTransfer} object.
+   * 
+   * @param format the format
+   * @return the data for the specified format
+   */
+  public String getData(String format) {
+    DataTransfer dt = getDataTransfer();
+    return getDataTransfer().getData(format);
+  }
+
+  /**
+   * Get the {@link DataTransfer} associated with the current drag event.
+   * 
+   * @return the {@link DataTransfer} object
+   */
+  public DataTransfer getDataTransfer() {
+    return getNativeEvent().getDataTransfer();
+  }
+
+  /**
+   * Set the data in the {@link DataTransfer} object for the specified format.
+   * 
+   * @param format the format
+   * @param data the data to associate with the format
+   */
+  public void setData(String format, String data) {
+    getDataTransfer().setData(format, data);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/DragEndEvent.java b/user/src/com/google/gwt/event/dom/client/DragEndEvent.java
new file mode 100644
index 0000000..d351e4b
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/DragEndEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2011 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.event.dom.client;
+
+/**
+ * Represents a native drag end event.
+ */
+public class DragEndEvent extends DragDropEventBase<DragEndHandler> {
+
+  /**
+   * Event type for drag end events. Represents the meta-data associated with
+   * this event.
+   */
+  private static final Type<DragEndHandler> TYPE = new Type<DragEndHandler>("dragend",
+      new DragEndEvent());
+
+  /**
+   * Gets the event type associated with drag end events.
+   * 
+   * @return the handler type
+   */
+  public static Type<DragEndHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
+   * or
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers, com.google.gwt.dom.client.Element)}
+   * to fire drag end events.
+   */
+  protected DragEndEvent() {
+  }
+
+  @Override
+  public final Type<DragEndHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  @Override
+  protected void dispatch(DragEndHandler handler) {
+    handler.onDragEnd(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/DragExitHandler.java b/user/src/com/google/gwt/event/dom/client/DragEndHandler.java
similarity index 73%
rename from user/src/com/google/gwt/event/dom/client/DragExitHandler.java
rename to user/src/com/google/gwt/event/dom/client/DragEndHandler.java
index 8f0cb31..5a92bc9 100644
--- a/user/src/com/google/gwt/event/dom/client/DragExitHandler.java
+++ b/user/src/com/google/gwt/event/dom/client/DragEndHandler.java
@@ -18,14 +18,14 @@
 import com.google.gwt.event.shared.EventHandler;
 
 /**
- * Handler interface for {@link DragExitEvent} events.
+ * Handler interface for {@link DragEndEvent} events.
  */
-public interface DragExitHandler extends EventHandler {
+public interface DragEndHandler extends EventHandler {
 
   /**
-   * Called when a {@link DragExitEvent} is fired.
+   * Called when a {@link DragEndEvent} is fired.
    * 
-   * @param event the {@link DragExitEvent} that was fired
+   * @param event the {@link DragEndEvent} that was fired
    */
-  void onDragExit(DragExitEvent event);
+  void onDragEnd(DragEndEvent event);
 }
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/DragEnterEvent.java b/user/src/com/google/gwt/event/dom/client/DragEnterEvent.java
index 8171f8e..32ae34d 100644
--- a/user/src/com/google/gwt/event/dom/client/DragEnterEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DragEnterEvent.java
@@ -18,7 +18,7 @@
 /**
  * Represents a native drag enter event.
  */
-public class DragEnterEvent extends DomEvent<DragEnterHandler> {
+public class DragEnterEvent extends DragDropEventBase<DragEnterHandler> {
 
   /**
    * Event type for drag enter events. Represents the meta-data associated
@@ -39,6 +39,8 @@
   /**
    * Protected constructor, use
    * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
+   * or
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers, com.google.gwt.dom.client.Element)}
    * to fire drag enter events.
    */
   protected DragEnterEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/DragEvent.java b/user/src/com/google/gwt/event/dom/client/DragEvent.java
new file mode 100644
index 0000000..103ef84
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/DragEvent.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 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.event.dom.client;
+
+/**
+ * Represents a native drag event.
+ */
+public class DragEvent extends DragDropEventBase<DragHandler> {
+
+  /**
+   * Event type for drag events. Represents the meta-data associated with this
+   * event.
+   */
+  private static final Type<DragHandler> TYPE = new Type<DragHandler>("drag", new DragEvent());
+
+  /**
+   * Gets the event type associated with drag events.
+   * 
+   * @return the handler type
+   */
+  public static Type<DragHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
+   * or
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers, com.google.gwt.dom.client.Element)}
+   * to fire drag events.
+   */
+  protected DragEvent() {
+  }
+
+  @Override
+  public final Type<DragHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  @Override
+  protected void dispatch(DragHandler handler) {
+    handler.onDrag(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/DragExitEvent.java b/user/src/com/google/gwt/event/dom/client/DragExitEvent.java
deleted file mode 100644
index 6f68f3f..0000000
--- a/user/src/com/google/gwt/event/dom/client/DragExitEvent.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2011 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.event.dom.client;
-
-/**
- * Represents a native drag Exit event.
- */
-public class DragExitEvent extends DomEvent<DragExitHandler> {
-
-  /**
-   * Event type for drag exit events. Represents the meta-data associated
-   * with this event.
-   */
-  private static final Type<DragExitHandler> TYPE = new Type<DragExitHandler>(
-      "dragexit", new DragExitEvent());
-
-  /**
-   * Gets the event type associated with drag exit events.
-   * 
-   * @return the handler type
-   */
-  public static Type<DragExitHandler> getType() {
-    return TYPE;
-  }
-
-  /**
-   * Protected constructor, use
-   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent,
-   * com.google.gwt.event.shared.HasHandlers)}
-   * to fire drag exit events.
-   */
-  protected DragExitEvent() {
-  }
-
-  @Override
-  public final Type<DragExitHandler> getAssociatedType() {
-    return TYPE;
-  }
-
-  @Override
-  protected void dispatch(DragExitHandler handler) {
-    handler.onDragExit(this);
-  }
-
-}
diff --git a/user/src/com/google/gwt/event/dom/client/DragExitHandler.java b/user/src/com/google/gwt/event/dom/client/DragHandler.java
similarity index 73%
copy from user/src/com/google/gwt/event/dom/client/DragExitHandler.java
copy to user/src/com/google/gwt/event/dom/client/DragHandler.java
index 8f0cb31..5aac110 100644
--- a/user/src/com/google/gwt/event/dom/client/DragExitHandler.java
+++ b/user/src/com/google/gwt/event/dom/client/DragHandler.java
@@ -18,14 +18,14 @@
 import com.google.gwt.event.shared.EventHandler;
 
 /**
- * Handler interface for {@link DragExitEvent} events.
+ * Handler interface for {@link DragEvent} events.
  */
-public interface DragExitHandler extends EventHandler {
+public interface DragHandler extends EventHandler {
 
   /**
-   * Called when a {@link DragExitEvent} is fired.
+   * Called when a {@link DragEvent} is fired.
    * 
-   * @param event the {@link DragExitEvent} that was fired
+   * @param event the {@link DragEvent} that was fired
    */
-  void onDragExit(DragExitEvent event);
+  void onDrag(DragEvent event);
 }
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/DragLeaveEvent.java b/user/src/com/google/gwt/event/dom/client/DragLeaveEvent.java
new file mode 100644
index 0000000..5cbcb1c
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/DragLeaveEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2011 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.event.dom.client;
+
+/**
+ * Represents a native drag leave event.
+ */
+public class DragLeaveEvent extends DragDropEventBase<DragLeaveHandler> {
+
+  /**
+   * Event type for drag leave events. Represents the meta-data associated with
+   * this event.
+   */
+  private static final Type<DragLeaveHandler> TYPE = new Type<DragLeaveHandler>("dragleave",
+      new DragLeaveEvent());
+
+  /**
+   * Gets the event type associated with drag exit events.
+   * 
+   * @return the handler type
+   */
+  public static Type<DragLeaveHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
+   * or
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers, com.google.gwt.dom.client.Element)}
+   * to fire drag exit events.
+   */
+  protected DragLeaveEvent() {
+  }
+
+  @Override
+  public final Type<DragLeaveHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  @Override
+  protected void dispatch(DragLeaveHandler handler) {
+    handler.onDragLeave(this);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/DragExitHandler.java b/user/src/com/google/gwt/event/dom/client/DragLeaveHandler.java
similarity index 72%
copy from user/src/com/google/gwt/event/dom/client/DragExitHandler.java
copy to user/src/com/google/gwt/event/dom/client/DragLeaveHandler.java
index 8f0cb31..d757262 100644
--- a/user/src/com/google/gwt/event/dom/client/DragExitHandler.java
+++ b/user/src/com/google/gwt/event/dom/client/DragLeaveHandler.java
@@ -18,14 +18,14 @@
 import com.google.gwt.event.shared.EventHandler;
 
 /**
- * Handler interface for {@link DragExitEvent} events.
+ * Handler interface for {@link DragLeaveEvent} events.
  */
-public interface DragExitHandler extends EventHandler {
+public interface DragLeaveHandler extends EventHandler {
 
   /**
-   * Called when a {@link DragExitEvent} is fired.
+   * Called when a {@link DragLeaveEvent} is fired.
    * 
-   * @param event the {@link DragExitEvent} that was fired
+   * @param event the {@link DragLeaveEvent} that was fired
    */
-  void onDragExit(DragExitEvent event);
+  void onDragLeave(DragLeaveEvent event);
 }
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/DragOverEvent.java b/user/src/com/google/gwt/event/dom/client/DragOverEvent.java
index 9154808..d25c138 100644
--- a/user/src/com/google/gwt/event/dom/client/DragOverEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DragOverEvent.java
@@ -18,7 +18,7 @@
 /**
  * Represents a native drag over event.
  */
-public class DragOverEvent extends DomEvent<DragOverHandler> {
+public class DragOverEvent extends DragDropEventBase<DragOverHandler> {
 
   /**
    * Event type for drag over events. Represents the meta-data associated
@@ -39,6 +39,8 @@
   /**
    * Protected constructor, use
    * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
+   * or
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers, com.google.gwt.dom.client.Element)}
    * to fire drag over events.
    */
   protected DragOverEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/DragStartEvent.java b/user/src/com/google/gwt/event/dom/client/DragStartEvent.java
new file mode 100644
index 0000000..b4a2797
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/DragStartEvent.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011 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.event.dom.client;
+
+/**
+ * Represents a native drag start event.
+ */
+public class DragStartEvent extends DragDropEventBase<DragStartHandler> {
+
+  /**
+   * Event type for drag start events. Represents the meta-data associated with
+   * this event.
+   */
+  private static final Type<DragStartHandler> TYPE = new Type<DragStartHandler>("dragstart",
+      new DragStartEvent());
+
+  /**
+   * Gets the event type associated with drag start events.
+   * 
+   * @return the handler type
+   */
+  public static Type<DragStartHandler> getType() {
+    return TYPE;
+  }
+
+  /**
+   * Protected constructor, use
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
+   * or
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers, com.google.gwt.dom.client.Element)}
+   * to fire drag start events.
+   */
+  protected DragStartEvent() {
+  }
+
+  @Override
+  public final Type<DragStartHandler> getAssociatedType() {
+    return TYPE;
+  }
+
+  @Override
+  protected void dispatch(DragStartHandler handler) {
+    handler.onDragStart(this);
+  }
+
+}
diff --git a/user/src/com/google/gwt/event/dom/client/DragExitHandler.java b/user/src/com/google/gwt/event/dom/client/DragStartHandler.java
similarity index 72%
copy from user/src/com/google/gwt/event/dom/client/DragExitHandler.java
copy to user/src/com/google/gwt/event/dom/client/DragStartHandler.java
index 8f0cb31..47e94c4 100644
--- a/user/src/com/google/gwt/event/dom/client/DragExitHandler.java
+++ b/user/src/com/google/gwt/event/dom/client/DragStartHandler.java
@@ -18,14 +18,14 @@
 import com.google.gwt.event.shared.EventHandler;
 
 /**
- * Handler interface for {@link DragExitEvent} events.
+ * Handler interface for {@link DragStartEvent} events.
  */
-public interface DragExitHandler extends EventHandler {
+public interface DragStartHandler extends EventHandler {
 
   /**
-   * Called when a {@link DragExitEvent} is fired.
+   * Called when a {@link DragStartEvent} is fired.
    * 
-   * @param event the {@link DragExitEvent} that was fired
+   * @param event the {@link DragStartEvent} that was fired
    */
-  void onDragExit(DragExitEvent event);
+  void onDragStart(DragStartEvent event);
 }
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/DropEvent.java b/user/src/com/google/gwt/event/dom/client/DropEvent.java
index 6c2a17c..3e5416a 100644
--- a/user/src/com/google/gwt/event/dom/client/DropEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DropEvent.java
@@ -18,7 +18,7 @@
 /**
  * Represents a native drop event.
  */
-public class DropEvent extends DomEvent<DropHandler> {
+public class DropEvent extends DragDropEventBase<DropHandler> {
 
   /**
    * Event type for drop events. Represents the meta-data associated
@@ -39,6 +39,8 @@
   /**
    * Protected constructor, use
    * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
+   * or
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers, com.google.gwt.dom.client.Element)}
    * to fire drop events.
    */
   protected DropEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/HasAllDragAndDropHandlers.java b/user/src/com/google/gwt/event/dom/client/HasAllDragAndDropHandlers.java
index b16a7d3..bd73765 100644
--- a/user/src/com/google/gwt/event/dom/client/HasAllDragAndDropHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasAllDragAndDropHandlers.java
@@ -26,6 +26,7 @@
  * </span>
  * </p>
  */
-public interface HasAllDragAndDropHandlers extends HasDragEnterHandlers,
-    HasDragExitHandlers, HasDragOverHandlers, HasDropHandlers {
+public interface HasAllDragAndDropHandlers extends HasDragEndHandlers, HasDragEnterHandlers,
+    HasDragLeaveHandlers, HasDragHandlers, HasDragOverHandlers, HasDragStartHandlers,
+    HasDropHandlers {
 }
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java b/user/src/com/google/gwt/event/dom/client/HasDragEndHandlers.java
similarity index 76%
copy from user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java
copy to user/src/com/google/gwt/event/dom/client/HasDragEndHandlers.java
index 734552d..b3f8f33 100644
--- a/user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasDragEndHandlers.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2011 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,20 +20,19 @@
 
 /**
  * A widget that implements this interface provides registration for
- * {@link DragExitHandler} instances.
+ * {@link DragEndHandler} instances.
  * 
  * <p>
  * <span style="color:red">Experimental API: This API is still under development
- * and is subject to change.
- * </span>
+ * and is subject to change. </span>
  * </p>
  */
-public interface HasDragExitHandlers extends HasHandlers {
+public interface HasDragEndHandlers extends HasHandlers {
   /**
-   * Adds a {@link DragExitEvent} handler.
-   *
-   * @param handler the drag exit handler
+   * Adds a {@link DragEndEvent} handler.
+   * 
+   * @param handler the drag end handler
    * @return {@link HandlerRegistration} used to remove this handler
    */
-  HandlerRegistration addDragExitHandler(DragExitHandler handler);
+  HandlerRegistration addDragEndHandler(DragEndHandler handler);
 }
diff --git a/user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java b/user/src/com/google/gwt/event/dom/client/HasDragHandlers.java
similarity index 76%
copy from user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java
copy to user/src/com/google/gwt/event/dom/client/HasDragHandlers.java
index 734552d..a2e9dd0 100644
--- a/user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasDragHandlers.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2011 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,20 +20,19 @@
 
 /**
  * A widget that implements this interface provides registration for
- * {@link DragExitHandler} instances.
+ * {@link DragHandler} instances.
  * 
  * <p>
  * <span style="color:red">Experimental API: This API is still under development
- * and is subject to change.
- * </span>
+ * and is subject to change. </span>
  * </p>
  */
-public interface HasDragExitHandlers extends HasHandlers {
+public interface HasDragHandlers extends HasHandlers {
   /**
-   * Adds a {@link DragExitEvent} handler.
-   *
-   * @param handler the drag exit handler
+   * Adds a {@link DragEvent} handler.
+   * 
+   * @param handler the drag handler
    * @return {@link HandlerRegistration} used to remove this handler
    */
-  HandlerRegistration addDragExitHandler(DragExitHandler handler);
+  HandlerRegistration addDragHandler(DragHandler handler);
 }
diff --git a/user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java b/user/src/com/google/gwt/event/dom/client/HasDragLeaveHandlers.java
similarity index 80%
rename from user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java
rename to user/src/com/google/gwt/event/dom/client/HasDragLeaveHandlers.java
index 734552d..c886c74 100644
--- a/user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasDragLeaveHandlers.java
@@ -20,7 +20,7 @@
 
 /**
  * A widget that implements this interface provides registration for
- * {@link DragExitHandler} instances.
+ * {@link DragLeaveHandler} instances.
  * 
  * <p>
  * <span style="color:red">Experimental API: This API is still under development
@@ -28,12 +28,12 @@
  * </span>
  * </p>
  */
-public interface HasDragExitHandlers extends HasHandlers {
+public interface HasDragLeaveHandlers extends HasHandlers {
   /**
-   * Adds a {@link DragExitEvent} handler.
+   * Adds a {@link DragLeaveEvent} handler.
    *
-   * @param handler the drag exit handler
+   * @param handler the drag leave handler
    * @return {@link HandlerRegistration} used to remove this handler
    */
-  HandlerRegistration addDragExitHandler(DragExitHandler handler);
+  HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler);
 }
diff --git a/user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java b/user/src/com/google/gwt/event/dom/client/HasDragStartHandlers.java
similarity index 76%
copy from user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java
copy to user/src/com/google/gwt/event/dom/client/HasDragStartHandlers.java
index 734552d..d7648cb 100644
--- a/user/src/com/google/gwt/event/dom/client/HasDragExitHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasDragStartHandlers.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2011 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,20 +20,19 @@
 
 /**
  * A widget that implements this interface provides registration for
- * {@link DragExitHandler} instances.
+ * {@link DragStartHandler} instances.
  * 
  * <p>
  * <span style="color:red">Experimental API: This API is still under development
- * and is subject to change.
- * </span>
+ * and is subject to change. </span>
  * </p>
  */
-public interface HasDragExitHandlers extends HasHandlers {
+public interface HasDragStartHandlers extends HasHandlers {
   /**
-   * Adds a {@link DragExitEvent} handler.
-   *
-   * @param handler the drag exit handler
+   * Adds a {@link DragStartEvent} handler.
+   * 
+   * @param handler the drag start handler
    * @return {@link HandlerRegistration} used to remove this handler
    */
-  HandlerRegistration addDragExitHandler(DragExitHandler handler);
+  HandlerRegistration addDragStartHandler(DragStartHandler handler);
 }
diff --git a/user/src/com/google/gwt/user/cellview/client/CellBasedWidgetImpl.java b/user/src/com/google/gwt/user/cellview/client/CellBasedWidgetImpl.java
index a44e9bc..d04cbf8 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellBasedWidgetImpl.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellBasedWidgetImpl.java
@@ -115,9 +115,14 @@
 
     int eventsToSink = 0;
     for (String typeName : typeNames) {
-      int typeInt = sinkEvent(widget, typeName);
-      if (typeInt > 0) {
-        eventsToSink |= typeInt;
+      int typeInt = Event.getTypeInt(typeName);
+      if (typeInt < 0) {
+        widget.sinkBitlessEvent(typeName);
+      } else {
+        typeInt = sinkEvent(widget, typeName);
+        if (typeInt > 0) {
+          eventsToSink |= typeInt;
+        }
       }
     }
     if (eventsToSink > 0) {
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplIE9.java b/user/src/com/google/gwt/user/client/impl/DOMImplIE9.java
index a69fe1e..aa47aa0 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplIE9.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplIE9.java
@@ -15,8 +15,40 @@
  */
 package com.google.gwt.user.client.impl;
 
+import com.google.gwt.user.client.Element;
+
 /**
  * IE9 implementation of {@link com.google.gwt.user.client.impl.DOMImplStandardBase}.
  */
 class DOMImplIE9 extends DOMImplStandardBase {
+
+  /**
+   * IE uses a non-standard way of handling drag events.
+   */
+  @Override
+  protected void initEventSystem() {
+    super.initEventSystem();
+    initEventSystemIE();
+  }
+
+  @Override
+  protected void sinkBitlessEventImpl(Element elem, String eventTypeName) {
+    super.sinkBitlessEventImpl(elem, eventTypeName);
+
+    if ("dragover".equals(eventTypeName)) {
+      /*
+       * In IE, we have to sink dragenter with dragover in order to make an
+       * element a drop target.
+       */
+      super.sinkBitlessEventImpl(elem, "dragenter");
+    }
+  }
+
+  private native void initEventSystemIE() /*-{
+    // In IE, drag events return false instead of calling preventDefault.
+    @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent = $entry(function(evt) {
+      @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent.call(this, evt);
+      return false;
+    });
+  }-*/;
 }
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 3eddb10..9f62b5a 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
@@ -40,6 +40,16 @@
     initSyntheticMouseUpEvents();
   }
 
+  @Override
+  protected void sinkBitlessEventImpl(Element elem, String eventTypeName) {
+    if ("dragleave".equals(eventTypeName) && isGecko190OrBefore()) {
+      // Firefox 3.0- uses dragexit instead of dragleave.
+      sinkBitlessEventImplMozilla(elem, "dragexit");
+    } else {
+      super.sinkBitlessEventImpl(elem, eventTypeName);
+    }
+  }
+
   private native void initSyntheticMouseUpEvents() /*-{
     $wnd.addEventListener(
       'mouseout',
@@ -66,4 +76,16 @@
     $wnd.addEventListener('DOMMouseScroll', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent,
       true);
   }-*/;
+
+  /**
+   * Return true if using Gecko 1.9.0 (Firefox 3) or earlier.
+   */
+  private native boolean isGecko190OrBefore() /*-{
+    return @com.google.gwt.dom.client.DOMImplMozilla::isGecko190OrBefore()();
+  }-*/;
+
+  private native void sinkBitlessEventImplMozilla(Element elem, String eventTypeName) /*-{
+    if (eventTypeName == "dragexit")
+      elem.ondragexit = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent;
+  }-*/;
 }
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 bda4d69..d573da6 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
@@ -32,6 +32,8 @@
 
   private static JavaScriptObject dispatchCapturedMouseEvent;
 
+  private static JavaScriptObject dispatchDragEvent;
+
   private static JavaScriptObject dispatchEvent;
 
   private static JavaScriptObject dispatchUnhandledEvent;
@@ -170,6 +172,12 @@
       }
     });
 
+    // Some drag events must call preventDefault to prevent native text selection.
+    @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent = $entry(function(evt) {
+      evt.preventDefault();
+      @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent.call(this, evt);
+    });
+
     @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent = $entry(function(evt) {
       this.__gwtLastUnhandledEvent = evt.type;
       @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent.call(this, evt);
@@ -212,16 +220,22 @@
   }-*/;
 
   protected native void sinkBitlessEventImpl(Element elem, String eventTypeName) /*-{
-    if (eventTypeName == "dragenter")
-      elem.ondragenter = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
-    if (eventTypeName == "dragexit")
-      elem.ondragexit  = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
-    if (eventTypeName == "dragover")
-      elem.ondragover  = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
-    if (eventTypeName == "drop")
+    if (eventTypeName == "drag")
+      elem.ondrag      = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
+    else if (eventTypeName == "dragend")
+      elem.ondragend   = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
+    else if (eventTypeName == "dragenter")
+      elem.ondragenter = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent;
+    else if (eventTypeName == "dragleave")
+      elem.ondragleave = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
+    else if (eventTypeName == "dragover")
+      elem.ondragover  = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent;
+    else if (eventTypeName == "dragstart")
+      elem.ondragstart = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
+    else if (eventTypeName == "drop")
       elem.ondrop      = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
   }-*/;
-  
+
   protected native void sinkEventsImpl(Element elem, int bits) /*-{
     var chMask = (elem.__eventBits || 0) ^ bits;
     elem.__eventBits = bits;
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 8d8e359..f53317f 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
@@ -21,12 +21,18 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.DoubleClickEvent;
 import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.DragEndEvent;
+import com.google.gwt.event.dom.client.DragEndHandler;
 import com.google.gwt.event.dom.client.DragEnterEvent;
 import com.google.gwt.event.dom.client.DragEnterHandler;
-import com.google.gwt.event.dom.client.DragExitEvent;
-import com.google.gwt.event.dom.client.DragExitHandler;
+import com.google.gwt.event.dom.client.DragEvent;
+import com.google.gwt.event.dom.client.DragLeaveEvent;
+import com.google.gwt.event.dom.client.DragLeaveHandler;
+import com.google.gwt.event.dom.client.DragHandler;
 import com.google.gwt.event.dom.client.DragOverEvent;
 import com.google.gwt.event.dom.client.DragOverHandler;
+import com.google.gwt.event.dom.client.DragStartEvent;
+import com.google.gwt.event.dom.client.DragStartHandler;
 import com.google.gwt.event.dom.client.DropEvent;
 import com.google.gwt.event.dom.client.DropHandler;
 import com.google.gwt.event.dom.client.FocusEvent;
@@ -116,18 +122,30 @@
     return addDomHandler(handler, DoubleClickEvent.getType());
   }
 
+  public HandlerRegistration addDragEndHandler(DragEndHandler handler) {
+    return addBitlessDomHandler(handler, DragEndEvent.getType());
+  }
+
   public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) {
     return addBitlessDomHandler(handler, DragEnterEvent.getType());
   }
 
-  public HandlerRegistration addDragExitHandler(DragExitHandler handler) {
-    return addBitlessDomHandler(handler, DragExitEvent.getType());
+  public HandlerRegistration addDragHandler(DragHandler handler) {
+    return addBitlessDomHandler(handler, DragEvent.getType());
   }
-  
+
+  public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
+    return addBitlessDomHandler(handler, DragLeaveEvent.getType());
+  }
+
   public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
     return addBitlessDomHandler(handler, DragOverEvent.getType());
   }
 
+  public HandlerRegistration addDragStartHandler(DragStartHandler handler) {
+    return addBitlessDomHandler(handler, DragStartEvent.getType());
+  }
+
   public HandlerRegistration addDropHandler(DropHandler handler) {
     return addBitlessDomHandler(handler, DropEvent.getType());
   }
diff --git a/user/src/com/google/gwt/user/client/ui/FocusWidget.java b/user/src/com/google/gwt/user/client/ui/FocusWidget.java
index b2a8b69..7c1fa55 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusWidget.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusWidget.java
@@ -22,12 +22,18 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.DoubleClickEvent;
 import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.DragEndEvent;
+import com.google.gwt.event.dom.client.DragEndHandler;
 import com.google.gwt.event.dom.client.DragEnterEvent;
 import com.google.gwt.event.dom.client.DragEnterHandler;
-import com.google.gwt.event.dom.client.DragExitEvent;
-import com.google.gwt.event.dom.client.DragExitHandler;
+import com.google.gwt.event.dom.client.DragEvent;
+import com.google.gwt.event.dom.client.DragLeaveEvent;
+import com.google.gwt.event.dom.client.DragLeaveHandler;
+import com.google.gwt.event.dom.client.DragHandler;
 import com.google.gwt.event.dom.client.DragOverEvent;
 import com.google.gwt.event.dom.client.DragOverHandler;
+import com.google.gwt.event.dom.client.DragStartEvent;
+import com.google.gwt.event.dom.client.DragStartHandler;
 import com.google.gwt.event.dom.client.DropEvent;
 import com.google.gwt.event.dom.client.DropHandler;
 import com.google.gwt.event.dom.client.FocusEvent;
@@ -133,18 +139,30 @@
     return addDomHandler(handler, DoubleClickEvent.getType());
   }
 
+  public HandlerRegistration addDragEndHandler(DragEndHandler handler) {
+    return addBitlessDomHandler(handler, DragEndEvent.getType());
+  }
+
   public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) {
     return addBitlessDomHandler(handler, DragEnterEvent.getType());
   }
 
-  public HandlerRegistration addDragExitHandler(DragExitHandler handler) {
-    return addBitlessDomHandler(handler, DragExitEvent.getType());
+  public HandlerRegistration addDragHandler(DragHandler handler) {
+    return addBitlessDomHandler(handler, DragEvent.getType());
   }
-  
+
+  public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
+    return addBitlessDomHandler(handler, DragLeaveEvent.getType());
+  }
+
   public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
     return addBitlessDomHandler(handler, DragOverEvent.getType());
   }
 
+  public HandlerRegistration addDragStartHandler(DragStartHandler handler) {
+    return addBitlessDomHandler(handler, DragStartEvent.getType());
+  }
+
   public HandlerRegistration addDropHandler(DropHandler handler) {
     return addBitlessDomHandler(handler, DropEvent.getType());
   }
diff --git a/user/src/com/google/gwt/user/client/ui/HTMLTable.java b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
index 18fdaf5..05e528f 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLTable.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
@@ -22,12 +22,18 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.DoubleClickEvent;
 import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.DragEndEvent;
+import com.google.gwt.event.dom.client.DragEndHandler;
 import com.google.gwt.event.dom.client.DragEnterEvent;
 import com.google.gwt.event.dom.client.DragEnterHandler;
-import com.google.gwt.event.dom.client.DragExitEvent;
-import com.google.gwt.event.dom.client.DragExitHandler;
+import com.google.gwt.event.dom.client.DragEvent;
+import com.google.gwt.event.dom.client.DragLeaveEvent;
+import com.google.gwt.event.dom.client.DragLeaveHandler;
+import com.google.gwt.event.dom.client.DragHandler;
 import com.google.gwt.event.dom.client.DragOverEvent;
 import com.google.gwt.event.dom.client.DragOverHandler;
+import com.google.gwt.event.dom.client.DragStartEvent;
+import com.google.gwt.event.dom.client.DragStartHandler;
 import com.google.gwt.event.dom.client.DropEvent;
 import com.google.gwt.event.dom.client.DropHandler;
 import com.google.gwt.event.dom.client.HasAllDragAndDropHandlers;
@@ -738,18 +744,30 @@
     return addDomHandler(handler, DoubleClickEvent.getType());
   }
 
+  public HandlerRegistration addDragEndHandler(DragEndHandler handler) {
+    return addBitlessDomHandler(handler, DragEndEvent.getType());
+  }
+
   public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) {
     return addBitlessDomHandler(handler, DragEnterEvent.getType());
   }
 
-  public HandlerRegistration addDragExitHandler(DragExitHandler handler) {
-    return addBitlessDomHandler(handler, DragExitEvent.getType());
+  public HandlerRegistration addDragHandler(DragHandler handler) {
+    return addBitlessDomHandler(handler, DragEvent.getType());
   }
-  
+
+  public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
+    return addBitlessDomHandler(handler, DragLeaveEvent.getType());
+  }
+
   public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
     return addBitlessDomHandler(handler, DragOverEvent.getType());
   }
 
+  public HandlerRegistration addDragStartHandler(DragStartHandler handler) {
+    return addBitlessDomHandler(handler, DragStartEvent.getType());
+  }
+
   public HandlerRegistration addDropHandler(DropHandler handler) {
     return addBitlessDomHandler(handler, DropEvent.getType());
   }
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 45b4d42..c8da399 100644
--- a/user/src/com/google/gwt/user/client/ui/Image.java
+++ b/user/src/com/google/gwt/user/client/ui/Image.java
@@ -26,12 +26,18 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.DoubleClickEvent;
 import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.DragEndEvent;
+import com.google.gwt.event.dom.client.DragEndHandler;
 import com.google.gwt.event.dom.client.DragEnterEvent;
 import com.google.gwt.event.dom.client.DragEnterHandler;
-import com.google.gwt.event.dom.client.DragExitEvent;
-import com.google.gwt.event.dom.client.DragExitHandler;
+import com.google.gwt.event.dom.client.DragEvent;
+import com.google.gwt.event.dom.client.DragLeaveEvent;
+import com.google.gwt.event.dom.client.DragLeaveHandler;
+import com.google.gwt.event.dom.client.DragHandler;
 import com.google.gwt.event.dom.client.DragOverEvent;
 import com.google.gwt.event.dom.client.DragOverHandler;
+import com.google.gwt.event.dom.client.DragStartEvent;
+import com.google.gwt.event.dom.client.DragStartHandler;
 import com.google.gwt.event.dom.client.DropEvent;
 import com.google.gwt.event.dom.client.DropHandler;
 import com.google.gwt.event.dom.client.ErrorEvent;
@@ -554,18 +560,30 @@
     return addHandler(handler, DoubleClickEvent.getType());
   }
 
+  public HandlerRegistration addDragEndHandler(DragEndHandler handler) {
+    return addBitlessDomHandler(handler, DragEndEvent.getType());
+  }
+
   public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) {
     return addBitlessDomHandler(handler, DragEnterEvent.getType());
   }
 
-  public HandlerRegistration addDragExitHandler(DragExitHandler handler) {
-    return addBitlessDomHandler(handler, DragExitEvent.getType());
+  public HandlerRegistration addDragHandler(DragHandler handler) {
+    return addBitlessDomHandler(handler, DragEvent.getType());
   }
-  
+
+  public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
+    return addBitlessDomHandler(handler, DragLeaveEvent.getType());
+  }
+
   public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
     return addBitlessDomHandler(handler, DragOverEvent.getType());
   }
 
+  public HandlerRegistration addDragStartHandler(DragStartHandler handler) {
+    return addBitlessDomHandler(handler, DragStartEvent.getType());
+  }
+
   public HandlerRegistration addDropHandler(DropHandler handler) {
     return addBitlessDomHandler(handler, DropEvent.getType());
   }
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 c824be1..d0afd6d 100644
--- a/user/src/com/google/gwt/user/client/ui/Label.java
+++ b/user/src/com/google/gwt/user/client/ui/Label.java
@@ -24,12 +24,18 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.DoubleClickEvent;
 import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.DragEndEvent;
+import com.google.gwt.event.dom.client.DragEndHandler;
 import com.google.gwt.event.dom.client.DragEnterEvent;
 import com.google.gwt.event.dom.client.DragEnterHandler;
-import com.google.gwt.event.dom.client.DragExitEvent;
-import com.google.gwt.event.dom.client.DragExitHandler;
+import com.google.gwt.event.dom.client.DragEvent;
+import com.google.gwt.event.dom.client.DragLeaveEvent;
+import com.google.gwt.event.dom.client.DragLeaveHandler;
+import com.google.gwt.event.dom.client.DragHandler;
 import com.google.gwt.event.dom.client.DragOverEvent;
 import com.google.gwt.event.dom.client.DragOverHandler;
+import com.google.gwt.event.dom.client.DragStartEvent;
+import com.google.gwt.event.dom.client.DragStartHandler;
 import com.google.gwt.event.dom.client.DropEvent;
 import com.google.gwt.event.dom.client.DropHandler;
 import com.google.gwt.event.dom.client.GestureChangeEvent;
@@ -209,18 +215,30 @@
     return addDomHandler(handler, DoubleClickEvent.getType());
   }
 
+  public HandlerRegistration addDragEndHandler(DragEndHandler handler) {
+    return addBitlessDomHandler(handler, DragEndEvent.getType());
+  }
+
   public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) {
     return addBitlessDomHandler(handler, DragEnterEvent.getType());
   }
 
-  public HandlerRegistration addDragExitHandler(DragExitHandler handler) {
-    return addBitlessDomHandler(handler, DragExitEvent.getType());
+  public HandlerRegistration addDragHandler(DragHandler handler) {
+    return addBitlessDomHandler(handler, DragEvent.getType());
   }
-  
+
+  public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) {
+    return addBitlessDomHandler(handler, DragLeaveEvent.getType());
+  }
+
   public HandlerRegistration addDragOverHandler(DragOverHandler handler) {
     return addBitlessDomHandler(handler, DragOverEvent.getType());
   }
 
+  public HandlerRegistration addDragStartHandler(DragStartHandler handler) {
+    return addBitlessDomHandler(handler, DragStartEvent.getType());
+  }
+
   public HandlerRegistration addDropHandler(DropHandler handler) {
     return addBitlessDomHandler(handler, DropEvent.getType());
   }
diff --git a/user/src/com/google/gwt/user/client/ui/Widget.java b/user/src/com/google/gwt/user/client/ui/Widget.java
index 932aaee..758acb4 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -98,7 +98,12 @@
       final H handler, DomEvent.Type<H> type) {
     assert handler != null : "handler must not be null";
     assert type != null : "type must not be null";
-    sinkEvents(Event.getTypeInt(type.getName()));
+    int typeInt = Event.getTypeInt(type.getName());
+    if (typeInt == -1) {
+      sinkBitlessEvent(type.getName());
+    } else {
+      sinkEvents(typeInt);
+    }
     return ensureHandlers().addHandler(type, handler);
   }
 
diff --git a/user/test/com/google/gwt/user/client/DragAndDropEventsSinkTest.java b/user/test/com/google/gwt/user/client/DragAndDropEventsSinkTest.java
index 4e9fa10..c00e348 100644
--- a/user/test/com/google/gwt/user/client/DragAndDropEventsSinkTest.java
+++ b/user/test/com/google/gwt/user/client/DragAndDropEventsSinkTest.java
@@ -16,32 +16,29 @@
 
 package com.google.gwt.user.client;
 
+import com.google.gwt.event.dom.client.DragEndEvent;
+import com.google.gwt.event.dom.client.DragEndHandler;
 import com.google.gwt.event.dom.client.DragEnterEvent;
 import com.google.gwt.event.dom.client.DragEnterHandler;
-import com.google.gwt.event.dom.client.DragExitEvent;
-import com.google.gwt.event.dom.client.DragExitHandler;
+import com.google.gwt.event.dom.client.DragEvent;
+import com.google.gwt.event.dom.client.DragLeaveEvent;
+import com.google.gwt.event.dom.client.DragLeaveHandler;
+import com.google.gwt.event.dom.client.DragHandler;
 import com.google.gwt.event.dom.client.DragOverEvent;
 import com.google.gwt.event.dom.client.DragOverHandler;
+import com.google.gwt.event.dom.client.DragStartEvent;
+import com.google.gwt.event.dom.client.DragStartHandler;
 import com.google.gwt.event.dom.client.DropEvent;
 import com.google.gwt.event.dom.client.DropHandler;
 import com.google.gwt.event.dom.client.HasAllDragAndDropHandlers;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.CheckBox;
 import com.google.gwt.user.client.ui.FlexTable;
 import com.google.gwt.user.client.ui.FocusPanel;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwt.user.client.ui.PasswordTextBox;
-import com.google.gwt.user.client.ui.RichTextArea;
 import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.SimpleRadioButton;
-import com.google.gwt.user.client.ui.TextArea;
-import com.google.gwt.user.client.ui.TextBox;
-import com.google.gwt.user.client.ui.ToggleButton;
 import com.google.gwt.user.client.ui.Widget;
 
 /**
@@ -49,29 +46,43 @@
  */
 public class DragAndDropEventsSinkTest extends GWTTestCase {
 
-  private static class DragEnterHandlerImpl extends HandlerImpl implements
-      DragEnterHandler {
+  private static class DragEndHandlerImpl extends HandlerImpl implements DragEndHandler {
+    public void onDragEnd(DragEndEvent event) {
+      eventFired();
+    }
+  }
+
+  private static class DragEnterHandlerImpl extends HandlerImpl implements DragEnterHandler {
     public void onDragEnter(DragEnterEvent event) {
       eventFired();
     }
   }
 
-  private static class DragExitHandlerImpl extends HandlerImpl implements
-      DragExitHandler {
-    public void onDragExit(DragExitEvent event) {
+  private static class DragHandlerImpl extends HandlerImpl implements DragHandler {
+    public void onDrag(DragEvent event) {
       eventFired();
     }
   }
 
-  private static class DragOverHandlerImpl extends HandlerImpl implements
-      DragOverHandler {
+  private static class DragLeaveHandlerImpl extends HandlerImpl implements DragLeaveHandler {
+    public void onDragLeave(DragLeaveEvent event) {
+      eventFired();
+    }
+  }
+
+  private static class DragOverHandlerImpl extends HandlerImpl implements DragOverHandler {
     public void onDragOver(DragOverEvent event) {
       eventFired();
     }
   }
 
-  private static class DropHandlerImpl extends HandlerImpl implements
-      DropHandler {
+  private static class DragStartHandlerImpl extends HandlerImpl implements DragStartHandler {
+    public void onDragStart(DragStartEvent event) {
+      eventFired();
+    }
+  }
+
+  private static class DropHandlerImpl extends HandlerImpl implements DropHandler {
     public void onDrop(DropEvent event) {
       eventFired();
     }
@@ -89,6 +100,20 @@
     }
   }
 
+  /**
+   * Interface to create a widget.
+   * 
+   * @param <W> the widget type
+   */
+  private interface WidgetCreator<W extends Widget & HasAllDragAndDropHandlers> {
+    /**
+     * Create a widget to test.
+     * 
+     * @return the new widget
+     */
+    W createWidget();
+  }
+
   public static native boolean isEventSupported(String eventName) /*-{
     var div = $doc.createElement("div");
     return ("on" + eventName) in div;
@@ -104,11 +129,13 @@
     if (!isEventSupported("dragstart")) {
       return;
     }
-    
-    verifyDragEnterEventSink(new FocusPanel());
-    verifyDragExitEventSink(new FocusPanel());
-    verifyDragOverEventSink(new FocusPanel());
-    verifyDropEventSink(new FocusPanel());
+
+    verifyDragAndDropEventSink(new WidgetCreator<FocusPanel>() {
+      @Override
+      public FocusPanel createWidget() {
+        return new FocusPanel();
+      }
+    });
   }
 
   public void testFocusWidgetEventSink() {
@@ -116,56 +143,13 @@
     if (!isEventSupported("dragstart")) {
       return;
     }
-    
-    verifyDragEnterEventSink(new Anchor());
-    verifyDragExitEventSink(new Anchor());
-    verifyDragOverEventSink(new Anchor());
-    verifyDropEventSink(new Anchor());
 
-    verifyDragEnterEventSink(new Button());
-    verifyDragExitEventSink(new Button());
-    verifyDragOverEventSink(new Button());
-    verifyDropEventSink(new Button());
-
-    verifyDragEnterEventSink(new CheckBox());
-    verifyDragExitEventSink(new CheckBox());
-    verifyDragOverEventSink(new CheckBox());
-    verifyDropEventSink(new CheckBox());
-
-    verifyDragEnterEventSink(new ToggleButton());
-    verifyDragExitEventSink(new ToggleButton());
-    verifyDragOverEventSink(new ToggleButton());
-    verifyDropEventSink(new ToggleButton());
-
-    verifyDragEnterEventSink(new ListBox());
-    verifyDragExitEventSink(new ListBox());
-    verifyDragOverEventSink(new ListBox());
-    verifyDropEventSink(new ListBox());
-
-    verifyDragEnterEventSink(new RichTextArea());
-    verifyDragExitEventSink(new RichTextArea());
-    verifyDragOverEventSink(new RichTextArea());
-    verifyDropEventSink(new RichTextArea());
-
-    verifyDragEnterEventSink(new TextArea());
-    verifyDragExitEventSink(new TextArea());
-    verifyDragOverEventSink(new TextArea());
-    verifyDropEventSink(new TextArea());
-
-    verifyDragEnterEventSink(new PasswordTextBox());
-    verifyDragExitEventSink(new PasswordTextBox());
-    verifyDragOverEventSink(new PasswordTextBox());
-    verifyDropEventSink(new PasswordTextBox());
-
-    verifyDragEnterEventSink(new TextBox());
-    verifyDragExitEventSink(new TextBox());
-    verifyDragOverEventSink(new TextBox());
-    verifyDropEventSink(new TextBox());
-
-    verifyDragEnterEventSink(new SimpleRadioButton("foo"));
-    verifyDragExitEventSink(new SimpleRadioButton("foo"));
-    verifyDragOverEventSink(new SimpleRadioButton("foo"));
-    verifyDropEventSink(new SimpleRadioButton("foo"));
+    verifyDragAndDropEventSink(new WidgetCreator<Anchor>() {
+      @Override
+      public Anchor createWidget() {
+        return new Anchor();
+      }
+    });
   }
 
   public void testHTMLTableEventSink() {
@@ -173,16 +157,18 @@
     if (!isEventSupported("dragstart")) {
       return;
     }
-    
-    verifyDragEnterEventSink(new Grid());
-    verifyDragExitEventSink(new Grid());
-    verifyDragOverEventSink(new Grid());
-    verifyDropEventSink(new Grid());
 
-    verifyDragEnterEventSink(new FlexTable());
-    verifyDragExitEventSink(new FlexTable());
-    verifyDragOverEventSink(new FlexTable());
-    verifyDropEventSink(new FlexTable());
+    verifyDragAndDropEventSink(new WidgetCreator<Grid>() {
+      @Override
+      public Grid createWidget() {
+        return new Grid();
+      }
+    }, new WidgetCreator<FlexTable>() {
+      @Override
+      public FlexTable createWidget() {
+        return new FlexTable();
+      }
+    });
   }
 
   public void testImageEventSink() {
@@ -190,11 +176,13 @@
     if (!isEventSupported("dragstart")) {
       return;
     }
-    
-    verifyDragEnterEventSink(new Image());
-    verifyDragExitEventSink(new Image());
-    verifyDragOverEventSink(new Image());
-    verifyDropEventSink(new Image());
+
+    verifyDragAndDropEventSink(new WidgetCreator<Image>() {
+      @Override
+      public Image createWidget() {
+        return new Image();
+      }
+    });
   }
 
   public void testLabelEventSink() {
@@ -202,11 +190,13 @@
     if (!isEventSupported("dragstart")) {
       return;
     }
-    
-    verifyDragEnterEventSink(new Label());
-    verifyDragExitEventSink(new Label());
-    verifyDragOverEventSink(new Label());
-    verifyDropEventSink(new Label());
+
+    verifyDragAndDropEventSink(new WidgetCreator<Label>() {
+      @Override
+      public Label createWidget() {
+        return new Label();
+      }
+    });
   }
 
   @Override
@@ -216,6 +206,28 @@
     super.gwtTearDown();
   }
 
+  private void verifyDragAndDropEventSink(WidgetCreator<?>... creators) {
+    for (WidgetCreator<?> creator : creators) {
+      verifyDragEventSink(creator.createWidget());
+      verifyDragEndEventSink(creator.createWidget());
+      verifyDragEnterEventSink(creator.createWidget());
+      verifyDragLeaveEventSink(creator.createWidget());
+      verifyDragOverEventSink(creator.createWidget());
+      verifyDragStartEventSink(creator.createWidget());
+      verifyDropEventSink(creator.createWidget());
+    }
+  }
+
+  private <W extends Widget & HasAllDragAndDropHandlers> void verifyDragEndEventSink(W w) {
+    DragEndHandlerImpl handler = new DragEndHandlerImpl();
+    w.addDragEndHandler(handler);
+
+    assertFalse(handler.hasEventFired());
+    w.fireEvent(new DragEndEvent() {
+    });
+    assertTrue(handler.hasEventFired());
+  }
+
   private <W extends Widget & HasAllDragAndDropHandlers> void verifyDragEnterEventSink(W w) {
     DragEnterHandlerImpl handler = new DragEnterHandlerImpl();
     w.addDragEnterHandler(handler);
@@ -226,12 +238,22 @@
     assertTrue(handler.hasEventFired());
   }
 
-  private <W extends Widget & HasAllDragAndDropHandlers> void verifyDragExitEventSink(W w) {
-    DragExitHandlerImpl handler = new DragExitHandlerImpl();
-    w.addDragExitHandler(handler);
+  private <W extends Widget & HasAllDragAndDropHandlers> void verifyDragEventSink(W w) {
+    DragHandlerImpl handler = new DragHandlerImpl();
+    w.addDragHandler(handler);
 
     assertFalse(handler.hasEventFired());
-    w.fireEvent(new DragExitEvent() {
+    w.fireEvent(new DragEvent() {
+    });
+    assertTrue(handler.hasEventFired());
+  }
+
+  private <W extends Widget & HasAllDragAndDropHandlers> void verifyDragLeaveEventSink(W w) {
+    DragLeaveHandlerImpl handler = new DragLeaveHandlerImpl();
+    w.addDragLeaveHandler(handler);
+
+    assertFalse(handler.hasEventFired());
+    w.fireEvent(new DragLeaveEvent() {
     });
     assertTrue(handler.hasEventFired());
   }
@@ -246,6 +268,16 @@
     assertTrue(handler.hasEventFired());
   }
 
+  private <W extends Widget & HasAllDragAndDropHandlers> void verifyDragStartEventSink(W w) {
+    DragStartHandlerImpl handler = new DragStartHandlerImpl();
+    w.addDragStartHandler(handler);
+
+    assertFalse(handler.hasEventFired());
+    w.fireEvent(new DragStartEvent() {
+    });
+    assertTrue(handler.hasEventFired());
+  }
+
   private <W extends Widget & HasAllDragAndDropHandlers> void verifyDropEventSink(W w) {
     DropHandlerImpl handler = new DropHandlerImpl();
     w.addDropHandler(handler);