Merging releases/1.6 into trunk.
svn merge -r4511:4604 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
svn merge -r4605:4657 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4659 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/common.ant.xml b/common.ant.xml
index 2b19d63..52d6c5a 100755
--- a/common.ant.xml
+++ b/common.ant.xml
@@ -253,10 +253,12 @@
     <element name="sourcepath" implicit="yes" optional="true" />
     <sequential>
       <taskdef resource="checkstyletask.properties" classpath="${gwt.tools.antlib}/checkstyle-all-4.2.jar;${gwt.build.lib}/gwt-customchecks.jar" />
-      <checkstyle config="${gwt.root}/eclipse/settings/code-style/gwt-checkstyle.xml" maxWarnings="0">
+      <checkstyle config="${gwt.root}/eclipse/settings/code-style/gwt-checkstyle.xml" maxErrors="0">
+      	<formatter type="xml" toFile="${project.build}/checkstyle_log.xml"/>
         <property key="checkstyle.header.file" file="${gwt.root}/eclipse/settings/code-style/google.header" />
         <sourcepath />
       </checkstyle>
+     <echo message="Checkstyle messages are reported in checkstyle_log.xml located at ${project.build}" />
     </sequential>
   </macrodef>
 
diff --git a/dev/core/src/com/google/gwt/dev/Compiler.java b/dev/core/src/com/google/gwt/dev/Compiler.java
index d41debd..4a4759c 100644
--- a/dev/core/src/com/google/gwt/dev/Compiler.java
+++ b/dev/core/src/com/google/gwt/dev/Compiler.java
@@ -23,6 +23,9 @@
 import com.google.gwt.dev.cfg.ModuleDef;
 import com.google.gwt.dev.cfg.ModuleDefLoader;
 import com.google.gwt.dev.util.FileBackedObject;
+import com.google.gwt.dev.shell.CheckForUpdates;
+import com.google.gwt.dev.shell.PlatformSpecific;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
 import com.google.gwt.dev.util.PerfLogger;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
@@ -34,6 +37,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
+import java.util.concurrent.FutureTask;
 
 /**
  * The main executable entry point for the GWT Java to JavaScript compiler.
@@ -124,7 +128,16 @@
     if (new ArgProcessor(options).processArgs(args)) {
       CompileTask task = new CompileTask() {
         public boolean run(TreeLogger logger) throws UnableToCompleteException {
-          return new Compiler(options).run(logger);
+          FutureTask<UpdateResult> updater = null;
+          if (!options.isUpdateCheckDisabled()) {
+            updater = PlatformSpecific.checkForUpdatesInBackgroundThread(logger,
+                CheckForUpdates.ONE_DAY);
+          }
+          boolean success = new Compiler(options).run(logger);
+          if (success) {
+            PlatformSpecific.logUpdateAvailable(logger, updater);
+          }
+          return success;
         }
       };
       if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index 0c1097b..913785d 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -22,6 +22,9 @@
 import com.google.gwt.dev.cfg.ModuleDef;
 import com.google.gwt.dev.cfg.ModuleDefLoader;
 import com.google.gwt.dev.util.FileBackedObject;
+import com.google.gwt.dev.shell.CheckForUpdates;
+import com.google.gwt.dev.shell.PlatformSpecific;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
 import com.google.gwt.dev.util.PerfLogger;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerLocalWorkers;
@@ -33,6 +36,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
+import java.util.concurrent.FutureTask;
 
 /**
  * The main executable entry point for the GWT Java to JavaScript compiler.
@@ -111,7 +115,16 @@
     if (new ArgProcessor(options).processArgs(args)) {
       CompileTask task = new CompileTask() {
         public boolean run(TreeLogger logger) throws UnableToCompleteException {
-          return new GWTCompiler(options).run(logger);
+          FutureTask<UpdateResult> updater = null;
+          if (!options.isUpdateCheckDisabled()) {
+            updater = PlatformSpecific.checkForUpdatesInBackgroundThread(logger,
+                CheckForUpdates.ONE_DAY);
+          }
+          boolean success = new GWTCompiler(options).run(logger);
+          if (success) {
+            PlatformSpecific.logUpdateAvailable(logger, updater);
+          }
+          return success;
         }
       };
       if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 338815e..a3dfdd6 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -166,6 +166,14 @@
     return new GWTCompilerOptionsImpl(options);
   }
 
+  public WebServerRestart hasWebServer() {
+    return WebServerRestart.NONE;
+  }
+
+  public void restartServer(TreeLogger logger) throws UnableToCompleteException {
+    // Unimplemented.
+  }
+
   public void setCompilerOptions(CompilerOptions options) {
     this.options.copyFrom(options);
   }
@@ -238,6 +246,11 @@
   }
 
   @Override
+  protected String getTitleText() {
+    return "Google Web Toolkit Development Shell";
+  }
+
+  @Override
   protected boolean initModule(String moduleName) {
     /*
      * Not used in legacy mode due to GWTShellServlet playing this role.
diff --git a/dev/core/src/com/google/gwt/dev/HostedMode.java b/dev/core/src/com/google/gwt/dev/HostedMode.java
index c5da1d8..bfd5d15 100644
--- a/dev/core/src/com/google/gwt/dev/HostedMode.java
+++ b/dev/core/src/com/google/gwt/dev/HostedMode.java
@@ -281,6 +281,15 @@
   HostedMode() {
   }
 
+  public WebServerRestart hasWebServer() {
+    return options.isNoServer() ? WebServerRestart.DISABLED
+        : WebServerRestart.ENABLED;
+  }
+
+  public void restartServer(TreeLogger logger) throws UnableToCompleteException {
+    server.refresh();
+  }
+
   @Override
   protected void compile(TreeLogger logger) throws UnableToCompleteException {
     CompilerOptions newOptions = new CompilerOptionsImpl(options);
@@ -391,6 +400,11 @@
   }
 
   @Override
+  protected String getTitleText() {
+    return "Google Web Toolkit Hosted Mode";
+  }
+
+  @Override
   protected boolean initModule(String moduleName) {
     ModuleDef module = modulesByName.get(moduleName);
     if (module == null) {
@@ -432,8 +446,8 @@
    * 
    * @param logger the logger to use
    * @param module the module to link
-   * @param includePublicFiles if <code>true</code>, include public files in the
-   *          link, otherwise do not include them
+   * @param includePublicFiles if <code>true</code>, include public files in
+   *          the link, otherwise do not include them
    * @throws UnableToCompleteException
    */
   private void link(TreeLogger logger, ModuleDef module)
diff --git a/dev/core/src/com/google/gwt/dev/HostedModeBase.java b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
index 559e5d1..92b24f1 100644
--- a/dev/core/src/com/google/gwt/dev/HostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
@@ -27,7 +27,9 @@
 import com.google.gwt.dev.shell.BrowserWidgetHost;
 import com.google.gwt.dev.shell.BrowserWidgetHostChecker;
 import com.google.gwt.dev.shell.BrowserWindowController;
+import com.google.gwt.dev.shell.CheckForUpdates;
 import com.google.gwt.dev.shell.ModuleSpaceHost;
+import com.google.gwt.dev.shell.PlatformSpecific;
 import com.google.gwt.dev.shell.ShellModuleSpaceHost;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
@@ -40,9 +42,6 @@
 import com.google.gwt.dev.util.arg.OptionLogLevel;
 import com.google.gwt.util.tools.ArgHandlerFlag;
 import com.google.gwt.util.tools.ArgHandlerString;
-import com.google.gwt.util.tools.ToolBase;
-
-import org.eclipse.swt.widgets.Display;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -324,14 +323,6 @@
     }
   }
 
-  static {
-    // Force ToolBase to clinit, which causes SWT stuff to happen.
-    new ToolBase() {
-    };
-    // Correct menu on Mac OS X
-    Display.setAppName("GWT");
-  }
-
   protected final HostedModeBaseOptions options;
 
   /**
@@ -427,6 +418,13 @@
   }
 
   /**
+   * Derived classes can override to lengthen ping delay.
+   */
+  protected long checkForUpdatesInterval() {
+    return CheckForUpdates.ONE_MINUTE;
+  }
+
+  /**
    * Compiles all modules.
    */
   protected abstract void compile(TreeLogger logger)
@@ -463,13 +461,6 @@
             "gen"), doCreateArtifactAcceptor(moduleDef));
   }
 
-  /**
-   * Derived classes can override to prevent automatic update checking.
-   */
-  protected boolean doShouldCheckForUpdates() {
-    return true;
-  }
-
   protected abstract void doShutDownServer();
 
   protected boolean doStartup() {
@@ -481,6 +472,22 @@
     // Initialize the logger.
     //
     initializeLogger();
+    
+    // Check for updates
+    final TreeLogger logger = getTopLogger();
+    final CheckForUpdates updateChecker
+        = PlatformSpecific.createUpdateChecker(logger);
+    if (updateChecker != null) {
+      Thread checkerThread = new Thread("GWT Update Checker") {
+        @Override
+        public void run() {
+          PlatformSpecific.logUpdateAvailable(logger,
+              updateChecker.check(checkForUpdatesInterval()));
+        }
+      };
+      checkerThread.setDaemon(true);
+      checkerThread.start();
+    }
     return true;
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index d64c2ed..c16b494 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -37,16 +37,21 @@
 import com.google.gwt.dev.jjs.JsOutputOption;
 import com.google.gwt.dev.jjs.UnifiedAst;
 import com.google.gwt.dev.jjs.impl.FragmentLoaderCreator;
+import com.google.gwt.dev.shell.CheckForUpdates;
+import com.google.gwt.dev.shell.PlatformSpecific;
 import com.google.gwt.dev.shell.StandardRebindOracle;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
 import com.google.gwt.dev.util.PerfLogger;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
 import com.google.gwt.dev.util.arg.ArgHandlerDisableRunAsync;
 import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile;
+import com.google.gwt.dev.util.arg.ArgHandlerDisableUpdateCheck;
 import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
 import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
 import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
 import com.google.gwt.dev.util.arg.ArgHandlerValidateOnlyFlag;
+import com.google.gwt.dev.util.arg.OptionDisableUpdateCheck;
 import com.google.gwt.dev.util.arg.OptionGenDir;
 import com.google.gwt.dev.util.arg.OptionValidateOnly;
 
@@ -56,6 +61,7 @@
 import java.util.SortedMap;
 import java.util.SortedSet;
 import java.util.TreeMap;
+import java.util.concurrent.FutureTask;
 
 /**
  * Performs the first phase of compilation, generating the set of permutations
@@ -67,7 +73,7 @@
    * The set of options for the precompiler.
    */
   public interface PrecompileOptions extends JJSOptions, CompileTaskOptions,
-      OptionGenDir, OptionValidateOnly {
+      OptionGenDir, OptionValidateOnly, OptionDisableUpdateCheck {
   }
 
   static class ArgProcessor extends CompileArgProcessor {
@@ -80,6 +86,7 @@
       registerHandler(new ArgHandlerValidateOnlyFlag(options));
       registerHandler(new ArgHandlerDisableRunAsync(options));
       registerHandler(new ArgHandlerDraftCompile(options));
+      registerHandler(new ArgHandlerDisableUpdateCheck(options));
     }
 
     @Override
@@ -90,7 +97,7 @@
 
   static class PrecompileOptionsImpl extends CompileTaskOptionsImpl implements
       PrecompileOptions {
-
+    private boolean disableUpdateCheck;
     private File genDir;
     private final JJSOptionsImpl jjsOptions = new JJSOptionsImpl();
     private boolean validateOnly;
@@ -107,6 +114,7 @@
 
       jjsOptions.copyFrom(other);
 
+      setDisableUpdateCheck(other.isUpdateCheckDisabled());
       setGenDir(other.getGenDir());
       setValidateOnly(other.isValidateOnly());
     }
@@ -139,6 +147,10 @@
       return jjsOptions.isSoycEnabled();
     }
 
+    public boolean isUpdateCheckDisabled() {
+      return disableUpdateCheck;
+    }
+
     public boolean isValidateOnly() {
       return validateOnly;
     }
@@ -151,6 +163,10 @@
       jjsOptions.setDraftCompile(draft);
     }
 
+    public void setDisableUpdateCheck(boolean disabled) {
+      disableUpdateCheck = disabled;
+    }
+
     public void setEnableAssertions(boolean enableAssertions) {
       jjsOptions.setEnableAssertions(enableAssertions);
     }
@@ -257,7 +273,16 @@
     if (new ArgProcessor(options).processArgs(args)) {
       CompileTask task = new CompileTask() {
         public boolean run(TreeLogger logger) throws UnableToCompleteException {
-          return new Precompile(options).run(logger);
+          FutureTask<UpdateResult> updater = null;
+          if (!options.isUpdateCheckDisabled()) {
+            updater = PlatformSpecific.checkForUpdatesInBackgroundThread(logger,
+                CheckForUpdates.ONE_DAY);
+          }
+          boolean success = new Precompile(options).run(logger);
+          if (success) {
+            PlatformSpecific.logUpdateAvailable(logger, updater);
+          }
+          return success;
         }
       };
       if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
diff --git a/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java b/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
index bda5243..0fac666 100644
--- a/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
@@ -178,6 +178,8 @@
     return browserHost;
   }
 
+  protected abstract String getTitleText();
+
   @Override
   protected void initializeLogger() {
     final AbstractTreeLogger logger = mainWnd.getLogger();
@@ -221,10 +223,8 @@
 
     shell.setImages(ShellMainWindow.getIcons());
 
-    boolean checkForUpdates = doShouldCheckForUpdates();
-
-    mainWnd = new ShellMainWindow(this, shell, options.isNoServer() ? 0
-        : getPort(), checkForUpdates);
+    mainWnd = new ShellMainWindow(this, shell, getTitleText(),
+        options.isNoServer() ? 0 : getPort());
 
     shell.setSize(700, 600);
     if (!isHeadless()) {
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
index e2653a1..e3c2f19 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
@@ -15,11 +15,13 @@
  */
 package com.google.gwt.dev.javac;
 
+import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.dev.asm.ClassReader;
 import com.google.gwt.dev.asm.Opcodes;
 import com.google.gwt.dev.asm.commons.EmptyVisitor;
 import com.google.gwt.dev.jdt.TypeRefVisitor;
 import com.google.gwt.dev.shell.CompilingClassLoader;
+import com.google.gwt.dev.util.Util;
 
 import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
@@ -30,6 +32,9 @@
 import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
 
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -46,25 +51,129 @@
  */
 public abstract class CompilationUnit {
 
-  static class AnonymousClassVisitor extends EmptyVisitor {
-    /*
-     * array of classNames of inner clases that aren't synthetic classes.
-     */
-    List<String> classNames = new ArrayList<String>();
+  /**
+   * Encapsulates the functionality to find all nested classes of this class
+   * that have compiler-generated names. All class bytes are loaded from the
+   * disk and then analyzed using ASM.
+   */
+  static class GeneratedClassnameFinder {
+    private static class AnonymousClassVisitor extends EmptyVisitor {
+      /*
+       * array of classNames of inner clases that aren't synthetic classes.
+       */
+      List<String> classNames = new ArrayList<String>();
 
-    public List<String> getInnerClassNames() {
-      return classNames;
-    }
+      public List<String> getInnerClassNames() {
+        return classNames;
+      }
 
-    @Override
-    public void visitInnerClass(String name, String outerName,
-        String innerName, int access) {
-      if ((access & Opcodes.ACC_SYNTHETIC) == 0) {
-        classNames.add(name);
+      @Override
+      public void visitInnerClass(String name, String outerName,
+          String innerName, int access) {
+        if ((access & Opcodes.ACC_SYNTHETIC) == 0) {
+          classNames.add(name);
+        }
       }
     }
-  }
 
+    private final List<String> classesToScan;
+    private final TreeLogger logger;
+    private final String mainClass;
+    private String mainUrlBase = null;
+
+    GeneratedClassnameFinder(TreeLogger logger, String mainClass) {
+      assert mainClass != null;
+      this.mainClass = mainClass;
+      classesToScan = new ArrayList<String>();
+      classesToScan.add(mainClass);
+      this.logger = logger;
+    }
+
+    List<String> getClassNames() {
+      // using a list because presumably there will not be many generated
+      // classes
+      List<String> allGeneratedClasses = new ArrayList<String>();
+      for (int i = 0; i < classesToScan.size(); i++) {
+        String lookupName = classesToScan.get(i);
+        byte classBytes[] = getClassBytes(lookupName);
+        if (classBytes == null) {
+          /*
+           * Weird case: javac might generate a name and reference the class in
+           * the bytecode but decide later that the class is unnecessary. In the
+           * bytecode, a null is passed for the class.
+           */
+          continue;
+        }
+
+        /*
+         * Add the class to the list only if it can be loaded to get around the
+         * javac weirdness issue where javac refers a class but does not
+         * generate it.
+         */
+        if (CompilingClassLoader.isClassnameGenerated(lookupName)
+            && !allGeneratedClasses.contains(lookupName)) {
+          allGeneratedClasses.add(lookupName);
+        }
+        AnonymousClassVisitor cv = new AnonymousClassVisitor();
+        new ClassReader(classBytes).accept(cv, 0);
+        List<String> innerClasses = cv.getInnerClassNames();
+        for (String innerClass : innerClasses) {
+          // The innerClass has to be an inner class of the lookupName
+          if (!innerClass.startsWith(mainClass + "$")) {
+            continue;
+          }
+          /*
+           * TODO (amitmanjhi): consider making this a Set if necessary for
+           * performance
+           */
+          // add the class to classes
+          if (!classesToScan.contains(innerClass)) {
+            classesToScan.add(innerClass);
+          }
+        }
+      }
+      Collections.sort(allGeneratedClasses, new GeneratedClassnameComparator());
+      return allGeneratedClasses;
+    }
+
+    /*
+     * Load classBytes from disk. Check if the classBytes are loaded from the
+     * same location as the location of the mainClass.
+     */
+    private byte[] getClassBytes(String slashedName) {
+      URL url = Thread.currentThread().getContextClassLoader().getResource(
+          slashedName + ".class");
+      if (url == null) {
+        logger.log(TreeLogger.DEBUG, "Unable to find " + slashedName
+            + " on the classPath");
+        return null;
+      }
+      String urlStr = url.toExternalForm();
+      if (slashedName.equals(mainClass)) {
+        // initialize the mainUrlBase for later use.
+        mainUrlBase = urlStr.substring(0, urlStr.lastIndexOf('/'));
+      } else {
+        assert mainUrlBase != null;
+        if (!mainUrlBase.equals(urlStr.substring(0, urlStr.lastIndexOf('/')))) {
+          logger.log(TreeLogger.DEBUG, "Found " + slashedName + " at " + urlStr
+              + " The base location is different from  that of " + mainUrlBase
+              + " Not loading");
+          return null;
+        }
+      }
+
+      // url != null, we found it on the class path.
+      try {
+        URLConnection conn = url.openConnection();
+        return Util.readURLConnectionAsBytes(conn);
+      } catch (IOException ignored) {
+        logger.log(TreeLogger.DEBUG, "Unable to load " + urlStr
+            + ", in trying to load " + slashedName);
+        // Fall through.
+      }
+      return null;
+    }
+  }
   /**
    * Tracks the state of a compilation unit through the compile and recompile
    * process.
@@ -167,26 +276,31 @@
   private State state = State.FRESH;
 
   /*
-   * Check if the unit has one or more anonymous classes. 'javac' below refers
-   * to the compiler that was used to compile the java files on disk. Returns
-   * true if our heuristic for constructing the anonymous class mappings worked.
+   * Check if the unit has one or more classes with generated names. 'javac'
+   * below refers to the compiler that was used to compile the java files on
+   * disk. Returns true if our heuristic for constructing the anonymous class
+   * mappings worked.
    */
-  public boolean constructAnonymousClassMappings(byte classBytes[]) {
+  public boolean constructAnonymousClassMappings(TreeLogger logger) {
     // map from the name in javac to the name in jdt
     anonymousClassMap = new HashMap<String, String>();
-    List<String> javacClasses = getJavacClassNames(classBytes);
-    List<String> jdtClasses = getJdtClassNames();
-    if (javacClasses.size() == jdtClasses.size()) {
+    for (String topLevelClass : getTopLevelClasses()) {
+      // Generate a mapping for each top-level class separately
+      List<String> javacClasses = new GeneratedClassnameFinder(logger,
+          topLevelClass).getClassNames();
+      List<String> jdtClasses = getJdtClassNames(topLevelClass);
+      if (javacClasses.size() != jdtClasses.size()) {
+        anonymousClassMap = Collections.emptyMap();
+        return false;
+      }
       int size = javacClasses.size();
       for (int i = 0; i < size; i++) {
         if (!javacClasses.get(i).equals(jdtClasses.get(i))) {
           anonymousClassMap.put(javacClasses.get(i), jdtClasses.get(i));
         }
       }
-      return true;
     }
-    anonymousClassMap = Collections.emptyMap();
-    return false;
+    return true;
   }
 
   public boolean createdClassMapping() {
@@ -383,25 +497,11 @@
     }
   }
 
-  private List<String> getJavacClassNames(byte classBytes[]) {
-    AnonymousClassVisitor cv = new AnonymousClassVisitor();
-    new ClassReader(classBytes).accept(cv, 0);
-    List<String> classNames = cv.getInnerClassNames();
-    List<String> namesToRemove = new ArrayList<String>();
-    for (String className : classNames) {
-      if (!CompilingClassLoader.isClassnameGenerated(className)) {
-        namesToRemove.add(className);
-      }
-    }
-    classNames.removeAll(namesToRemove);
-    Collections.sort(classNames, new GeneratedClassnameComparator());
-    return classNames;
-  }
-
-  private List<String> getJdtClassNames() {
+  private List<String> getJdtClassNames(String topLevelClass) {
     List<String> classNames = new ArrayList<String>();
     for (CompiledClass cc : getCompiledClasses()) {
-      if (isAnonymousClass(cc)) {
+      if (isAnonymousClass(cc)
+          && cc.getBinaryName().startsWith(topLevelClass + "$")) {
         classNames.add(cc.getBinaryName());
       }
     }
@@ -409,6 +509,16 @@
     return classNames;
   }
 
+  private List<String> getTopLevelClasses() {
+    List<String> topLevelClasses = new ArrayList<String>();
+    for (CompiledClass cc : getCompiledClasses()) {
+      if (cc.getEnclosingClass() == null) {
+        topLevelClasses.add(cc.binaryName);
+      }
+    }
+    return topLevelClasses;
+  }
+
   /**
    * Removes all accumulated state associated with compilation.
    */
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java
index aaa46f9..5ada435 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java
@@ -17,7 +17,7 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 
-import java.util.Set;
+import java.util.Map;
 
 /**
  * A location that acts as a starting point for finding resources
@@ -30,11 +30,12 @@
    * begins with a prefix X from the path prefix set and P is allowed by the
    * filter associated with X.
    * 
-   * @return a set of zero or more resources; note no guarantees are made
-   *         regarding the identities of the returned resource objects, and the
-   *         same object may be returned across multiple calls
+   * @return a map with key as an allowed resource and value as the PathPrefix
+   *         that allows the resource; note no guarantees are made regarding the
+   *         identities of the returned resource objects, and the same object
+   *         may be returned across multiple calls
    */
-  public abstract Set<AbstractResource> findApplicableResources(
+  public abstract Map<AbstractResource, PathPrefix> findApplicableResources(
       TreeLogger logger, PathPrefixSet pathPrefixSet);
 
   /**
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java
index 7d29ca6..2fd2964 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java
@@ -19,8 +19,8 @@
 import com.google.gwt.dev.util.msg.Message1String;
 
 import java.io.File;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.IdentityHashMap;
+import java.util.Map;
 
 /**
  * TODO(bruce): write me.
@@ -48,9 +48,9 @@
   }
 
   @Override
-  public Set<AbstractResource> findApplicableResources(TreeLogger logger,
-      PathPrefixSet pathPrefixSet) {
-    Set<AbstractResource> results = new HashSet<AbstractResource>();
+  public Map<AbstractResource, PathPrefix> findApplicableResources(
+      TreeLogger logger, PathPrefixSet pathPrefixSet) {
+    Map<AbstractResource, PathPrefix> results = new IdentityHashMap<AbstractResource, PathPrefix>();
     descendToFindResources(logger, pathPrefixSet, results, dir, "");
     return results;
   }
@@ -62,14 +62,15 @@
 
   /**
    * @param logger logs progress
-   * @param resources the accumulating set of resources found
+   * @param resources the accumulating set of resources (each with the
+   *          corresponding pathPrefix) found
    * @param dir the file or directory to consider
    * @param dirPath the abstract path name associated with 'parent', which
    *          explicitly does not include the classpath entry in its path
    */
   private void descendToFindResources(TreeLogger logger,
-      PathPrefixSet pathPrefixSet, Set<AbstractResource> resources, File dir,
-      String dirPath) {
+      PathPrefixSet pathPrefixSet, Map<AbstractResource, PathPrefix> resources,
+      File dir, String dirPath) {
     assert (dir.isDirectory());
 
     // Assert: this directory is included in the path prefix set.
@@ -89,10 +90,11 @@
               null);
         }
       } else {
-        if (pathPrefixSet.includesResource(childPath)) {
+        PathPrefix prefix = null;
+        if ((prefix = pathPrefixSet.includesResource(childPath)) != null) {
           Messages.INCLUDING_FILE.log(logger, childPath, null);
           FileResource r = new FileResource(this, childPath, child);
-          resources.add(r);
+          resources.put(r, prefix);
         } else {
           Messages.EXCLUDING_FILE.log(logger, childPath, null);
         }
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java
index 25537bb..096dfb1 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java
@@ -33,6 +33,7 @@
 
   private final ResourceFilter filter;
   private final String prefix;
+  private int priority = -1;
   private final boolean shouldReroot;
 
   /**
@@ -135,6 +136,20 @@
     return shouldReroot;
   }
 
+  @Override
+  public String toString() {
+    return prefix + (shouldReroot ? "**" : "*") + (filter == null ? "" : "?");
+  }
+
+  int getPriority() {
+    return priority;
+  }
+
+  void setPriority(int priority) {
+    assert (this.priority == -1);
+    this.priority = priority;
+  }
+
   private void assertValidPrefix(String prefix) {
     assert (prefix != null);
     assert ("".equals(prefix) || (!prefix.startsWith("/") && prefix.endsWith("/"))) : "malformed prefix";
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java
index 0e72bf4..0220db6 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java
@@ -27,11 +27,22 @@
  * answer questions regarding an entire set of path prefixes.
  */
 public class PathPrefixSet {
+  /*
+   * (1) TODO(amitmanjhi): Support multiple PathPrefixes with different filters
+   * but the same "path". This could arise when client code inherits some
+   * library code and defines the same path prefix with a more specific resource
+   * filter.
+   * 
+   * (2) TODO(amitmanjhi): Improve the api of the PathPrefixSet so that with one
+   * trie-traversal, it could be found out which resources rooted at a directory
+   * are allowed?
+   */
 
   private static class TrieNode {
-    // TODO(bruce): test to see if Map would be faster; I'm on the fence
-    private final List<TrieNode> children = new ArrayList<TrieNode>();
+    // TODO(amitmanjhi): Consider the memory-speed tradeoff here
+    private final Map<String, TrieNode> children = new HashMap<String, TrieNode>();
     private final String part;
+
     private PathPrefix prefix;
 
     public TrieNode(String part) {
@@ -39,19 +50,14 @@
     }
 
     public TrieNode addChild(String part) {
-      assert (findChild(part) == null);
       TrieNode newChild = new TrieNode(part);
-      children.add(newChild);
+      TrieNode oldChild = children.put(part, newChild);
+      assert (oldChild == null);
       return newChild;
     }
 
     public TrieNode findChild(String part) {
-      for (TrieNode child : children) {
-        if (child.part.equals(part)) {
-          return child;
-        }
-      }
-      return null;
+      return children.get(part);
     }
 
     public PathPrefix getPathPrefix() {
@@ -80,14 +86,17 @@
       sb.append(indent);
       sb.append(' ');
       sb.append(part);
-      for (TrieNode child : children) {
+      for (TrieNode child : children.values()) {
         child.toString(sb, indent + "  ");
       }
     }
   }
 
-  private int modCount;
-  private final Map<String, PathPrefix> prefixes = new HashMap<String, PathPrefix>();
+  /**
+   * List of all path prefixes in priority order.
+   */
+  private final List<PathPrefix> prefixes = new ArrayList<PathPrefix>();
+
   private final TrieNode rootTrieNode = new TrieNode("/");
 
   /**
@@ -98,13 +107,14 @@
    *         wins)
    */
   public boolean add(PathPrefix prefix) {
-    ++modCount;
+    prefix.setPriority(prefixes.size());
+    prefixes.add(prefix);
+
     String pathPrefix = prefix.getPrefix();
-    prefixes.put(pathPrefix, prefix);
 
     /*
-     * An empty prefix means we have no prefix requirement, but we do attached
-     * the prefix to the root so that we can apply the filter.
+     * An empty prefix means we have no prefix requirement, but we do attach the
+     * prefix to the root so that we can apply the filter.
      */
     if ("".equals(pathPrefix)) {
       rootTrieNode.setPathPrefix(prefix);
@@ -132,8 +142,8 @@
     return didAdd;
   }
 
-  public int getModCount() {
-    return modCount;
+  public int getSize() {
+    return prefixes.size();
   }
 
   /**
@@ -141,19 +151,17 @@
    * included. The primary purpose of this method is to allow
    * {@link ClassPathEntry} subclasses to avoid descending into directory
    * hierarchies that could not possibly contain resources that would be
-   * included by {@link #includesResource(String).
+   * included by {@link #includesResource(String)}
    * 
-   * @param dirPath must be a valid abstract directory name or the empty string
-   * @return
+   * @param dirPath must be a valid abstract directory name (must not be an
+   *          empty string)
+   * @return true if some PathPrefix allows the directory
    */
   public boolean includesDirectory(String dirPath) {
     assertValidAbstractDirectoryPathName(dirPath);
 
     /*
-     * There are five cases:
-     * 
-     * (0) dirPath is the empty string, which is (a) trivially included unless
-     * (b) no prefix paths have been specified at all.
+     * There are four cases:
      * 
      * (1) The empty string was specified as a prefix, which causes everything
      * to be included.
@@ -171,22 +179,12 @@
      * includes it).
      */
 
-    // if ("".equals(dirPath)) {
-    // if (rootTrieNode.hasChildren() || rootTrieNode.getPathPrefix() != null) {
-    // // Case (0)(a): trivially true.
-    // return true;
-    // } else {
-    // // Case (0)(b): no directories are included.
-    // return false;
-    // }
-    // }
     if (rootTrieNode.getPathPrefix() != null) {
       // Case (1).
       return true;
     }
 
     TrieNode parentNode = rootTrieNode;
-
     String[] parts = dirPath.split("/");
     for (String part : parts) {
       assert (!"".equals(part));
@@ -215,10 +213,12 @@
    * prefix set and the corresponding filters.
    * 
    * @param resourceAbstractPathName
-   * @return <code>true</code> if the resource matches some specified prefix
-   *         and any associated filters don't exclude it
+   * @return matching <code>PathPrefix</code> if the resource matches some
+   *         specified prefix and any associated filters don't exclude it.
+   *         Otherwise, returns null. So it returns null if either no prefixes
+   *         match or the most specific prefix excludes the resource.
    */
-  public boolean includesResource(String resourceAbstractPathName) {
+  public PathPrefix includesResource(String resourceAbstractPathName) {
     /*
      * Algorithm: dive down the package hierarchy looking for the most specific
      * package that applies to this resource. The filter of the most specific
@@ -232,12 +232,8 @@
     TrieNode currentNode = rootTrieNode;
     PathPrefix mostSpecificPrefix = rootTrieNode.getPathPrefix();
 
-    // TODO(bruce): consider not using split for speed
-    String[] parts = resourceAbstractPathName.split("/");
-
     // Walk all but the last path part, which is assumed to be a file name.
-    for (int i = 0, n = parts.length - 1; i < n; ++i) {
-      String part = parts[i];
+    for (String part : resourceAbstractPathName.split("/")) {
       assert (!"".equals(part));
       TrieNode childNode = currentNode.findChild(part);
       if (childNode != null) {
@@ -253,17 +249,25 @@
       }
     }
 
-    if (mostSpecificPrefix == null) {
-      // Didn't match any specified prefix.
-      return false;
+    if (mostSpecificPrefix == null
+        || !mostSpecificPrefix.allows(resourceAbstractPathName)) {
+      /*
+       * Didn't match any specified prefix or the filter of the most specific
+       * prefix disallows the resource
+       */
+      return null;
     }
 
-    // Test the filter of the most specific prefix we found.
-    return mostSpecificPrefix.allows(resourceAbstractPathName);
+    return mostSpecificPrefix;
+  }
+
+  @Override
+  public String toString() {
+    return rootTrieNode.toString();
   }
 
   public Collection<PathPrefix> values() {
-    return Collections.unmodifiableCollection(prefixes.values());
+    return Collections.unmodifiableCollection(prefixes);
   }
 
   private void assertValidAbstractDirectoryPathName(String name) {
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
index 50a1985..075bc13 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
@@ -15,12 +15,6 @@
  */
 package com.google.gwt.dev.resource.impl;
 
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.dev.resource.Resource;
-import com.google.gwt.dev.resource.ResourceOracle;
-import com.google.gwt.dev.util.msg.Message0;
-import com.google.gwt.dev.util.msg.Message1String;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,9 +30,16 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Map.Entry;
 import java.util.jar.JarFile;
 import java.util.zip.ZipFile;
 
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.ResourceOracle;
+import com.google.gwt.dev.util.msg.Message0;
+import com.google.gwt.dev.util.msg.Message1String;
+
 /**
  * The normal implementation of {@link ResourceOracle}.
  * 
@@ -75,17 +76,14 @@
   }
 
   /**
-   * Used by rebasing {@link ResourceOracle ResourceOracles} to map from a full
-   * classpath-based abstract path to an abstract path within a logical package.
-   * 
-   * @see ResourceOracleImpl#shouldRebasePaths()
+   * Wrapper object around a resource to change its path when it is rerooted.
    */
-  private static class ResourceWrapper extends AbstractResource {
+  private static class RerootedResource extends AbstractResource {
     private final String path;
     private final AbstractResource resource;
 
-    public ResourceWrapper(String path, AbstractResource resource) {
-      this.path = path;
+    public RerootedResource(AbstractResource resource, PathPrefix pathPrefix) {
+      this.path = pathPrefix.getRerootedPath(resource.getPath());
       this.resource = resource;
     }
 
@@ -130,6 +128,31 @@
     }
   }
 
+  private static class ResourceData implements Comparable<ResourceData> {
+    public final PathPrefix pathPrefix;
+    public final AbstractResource resource;
+
+    public ResourceData(AbstractResource resource, PathPrefix pathPrefix) {
+      this.resource = pathPrefix.shouldReroot() ? new RerootedResource(
+          resource, pathPrefix) : resource;
+      this.pathPrefix = pathPrefix;
+    }
+
+    public int compareTo(ResourceData other) {
+      // Rerooted takes precedence over not rerooted.
+      if (this.resource.wasRerooted() != other.resource.wasRerooted()) {
+        return this.resource.wasRerooted() ? 1 : -1;
+      }
+      // Compare priorities of the path prefixes, high number == high priority.
+      return this.pathPrefix.getPriority() - other.pathPrefix.getPriority();
+    }
+
+    @Override
+    public String toString() {
+      return "{" + resource + "," + pathPrefix + "}";
+    }
+  }
+
   private static final Map<ClassLoader, List<ClassPathEntry>> classPathCache = new HashMap<ClassLoader, List<ClassPathEntry>>();
 
   public static ClassPathEntry createEntryForUrl(TreeLogger logger, URL url)
@@ -218,7 +241,7 @@
 
   private Set<Resource> exposedResources = Collections.emptySet();
 
-  private Map<String, AbstractResource> internalMap = Collections.emptyMap();
+  private Map<String, ResourceData> internalMap = Collections.emptyMap();
 
   private PathPrefixSet pathPrefixSet = new PathPrefixSet();
 
@@ -277,7 +300,7 @@
      * "new identity for the collections if anything changes" guarantee. Use a
      * LinkedHashMap because we do not want the order to change.
      */
-    final Map<String, AbstractResource> newInternalMap = new LinkedHashMap<String, AbstractResource>();
+    Map<String, ResourceData> newInternalMap = new LinkedHashMap<String, ResourceData>();
 
     /*
      * Walk across path roots (i.e. classpath entries) in priority order. This
@@ -285,65 +308,71 @@
      * a resource that has already been added to the new map under construction
      * to create the effect that resources founder earlier on the classpath take
      * precedence.
+     * 
+     * Exceptions: super has priority over non-super; and if there are two super
+     * resources with the same path, the one with the higher-priority path
+     * prefix wins.
      */
-    int changeCount = 0;
     for (ClassPathEntry pathRoot : classPath) {
       TreeLogger branchForClassPathEntry = Messages.EXAMINING_PATH_ROOT.branch(
           refreshBranch, pathRoot.getLocation(), null);
 
-      int prevChangeCount = changeCount;
-
-      Set<AbstractResource> newResources = pathRoot.findApplicableResources(
+      Map<AbstractResource, PathPrefix> resourceToPrefixMap = pathRoot.findApplicableResources(
           branchForClassPathEntry, pathPrefixSet);
-      for (AbstractResource newResource : newResources) {
-        String resourcePath = newResource.getPath();
-
-        // Make sure we don't already have a resource by this name.
-        if (newInternalMap.containsKey(resourcePath)) {
+      for (Entry<AbstractResource, PathPrefix> entry : resourceToPrefixMap.entrySet()) {
+        ResourceData newCpeData = new ResourceData(entry.getKey(),
+            entry.getValue());
+        String resourcePath = newCpeData.resource.getPath();
+        ResourceData oldCpeData = newInternalMap.get(resourcePath);
+        // Old wins unless the new resource has higher priority.
+        if (oldCpeData == null || oldCpeData.compareTo(newCpeData) < 0) {
+          newInternalMap.put(resourcePath, newCpeData);
+        } else {
           Messages.IGNORING_SHADOWED_RESOURCE.log(branchForClassPathEntry,
               resourcePath, null);
-          continue;
         }
-
-        AbstractResource oldResource = internalMap.get(resourcePath);
-        if (shouldUseNewResource(branchForClassPathEntry, oldResource,
-            newResource)) {
-          newInternalMap.put(resourcePath, newResource);
-          ++changeCount;
-        } else if (oldResource != null) {
-          // Nothing changed, so carry the identity of the old one forward.
-          newInternalMap.put(resourcePath, oldResource);
-        }
-      }
-
-      if (changeCount == prevChangeCount) {
-        Messages.NO_RESOURCES_CHANGED.log(branchForClassPathEntry, null);
       }
     }
 
-    if (changeCount == 0) {
-      /*
-       * Nothing was added or modified, but we still have to be sure we didn't
-       * lose any resources.
-       */
-      if (newInternalMap.size() == internalMap.size()) {
-        /*
-         * Exit without changing the current exposed collections to maintain the
-         * identity requirements described in the spec for ResourceOracle.
-         */
-        return;
+    /*
+     * Update the newInternalMap to preserve identity for any resources that
+     * have not changed; also record whether or not there are ANY changes.
+     * 
+     * There's definitely a change if the sizes don't match; even if the sizes
+     * do match, every new resource must match an old resource for there to be
+     * no changes.
+     */
+    boolean didChange = internalMap.size() != newInternalMap.size();
+    for (String resourcePath : newInternalMap.keySet()) {
+      ResourceData newData = newInternalMap.get(resourcePath);
+      ResourceData oldData = internalMap.get(resourcePath);
+      if (shouldUseNewResource(logger, oldData, newData)) {
+        didChange = true;
+      } else {
+        if (oldData.resource != newData.resource) {
+          newInternalMap.put(resourcePath, oldData);
+        }
       }
     }
 
+    if (!didChange) {
+      // Nothing to do, keep the same identities.
+      return;
+    }
+
     internalMap = newInternalMap;
-    Map<String, Resource> externalMap = rerootResourcePaths(newInternalMap);
 
-    // Create a constant-time set for resources.
-    Set<Resource> newResources = new HashSet<Resource>(externalMap.values());
-    assert (newResources.size() == externalMap.size());
+    Map<String, Resource> externalMap = new HashMap<String, Resource>();
+    Set<Resource> externalSet = new HashSet<Resource>();
+    for (Entry<String, ResourceData> entry : internalMap.entrySet()) {
+      String path = entry.getKey();
+      ResourceData data = entry.getValue();
+      externalMap.put(path, data.resource);
+      externalSet.add(data.resource);
+    }
 
-    // Update the gettable fields with the new (unmodifiable) data structures.
-    exposedResources = Collections.unmodifiableSet(newResources);
+    // Update exposed collections with new (unmodifiable) data structures.
+    exposedResources = Collections.unmodifiableSet(externalSet);
     exposedResourceMap = Collections.unmodifiableMap(externalMap);
     exposedPathNames = Collections.unmodifiableSet(externalMap.keySet());
   }
@@ -357,59 +386,13 @@
     return classPath;
   }
 
-  private Map<String, Resource> rerootResourcePaths(
-      Map<String, AbstractResource> newInternalMap) {
-    Map<String, Resource> externalMap;
-    // Create an external map with rebased path names.
-    externalMap = new HashMap<String, Resource>();
-    for (AbstractResource resource : newInternalMap.values()) {
-      String path = resource.getPath();
-      if (externalMap.get(path) instanceof ResourceWrapper) {
-        // A rerooted resource blocks any other resource at this path.
-        continue;
-      }
-      int hitCount = 0;
-      for (PathPrefix pathPrefix : pathPrefixSet.values()) {
-        if (pathPrefix.allows(path)) {
-          assert (path.startsWith(pathPrefix.getPrefix()));
-          if (pathPrefix.shouldReroot()) {
-            String rerootedPath = pathPrefix.getRerootedPath(path);
-            if (externalMap.get(rerootedPath) instanceof ResourceWrapper) {
-              // A rerooted instance blocks any other resource at this path.
-              ++hitCount;
-              break;
-            }
-            // Try to reuse the same wrapper.
-            Resource exposed = exposedResourceMap.get(rerootedPath);
-            if (exposed instanceof ResourceWrapper) {
-              ResourceWrapper exposedWrapper = (ResourceWrapper) exposed;
-              if (exposedWrapper.resource == resource) {
-                externalMap.put(rerootedPath, exposedWrapper);
-                ++hitCount;
-                break;
-              }
-            }
-            // Just create a new wrapper.
-            AbstractResource wrapper = new ResourceWrapper(rerootedPath,
-                resource);
-            externalMap.put(rerootedPath, wrapper);
-            ++hitCount;
-          } else {
-            externalMap.put(path, resource);
-            ++hitCount;
-          }
-        }
-      }
-      assert (hitCount > 0);
-    }
-    return externalMap;
-  }
-
-  private boolean shouldUseNewResource(TreeLogger logger,
-      AbstractResource oldResource, AbstractResource newResource) {
+  private boolean shouldUseNewResource(TreeLogger logger, ResourceData oldData,
+      ResourceData newData) {
+    AbstractResource newResource = newData.resource;
     String resourcePath = newResource.getPath();
-    if (oldResource != null) {
+    if (oldData != null) {
       // Test 1: Is the resource found in a different location than before?
+      AbstractResource oldResource = oldData.resource;
       if (oldResource.getClassPathEntry() == newResource.getClassPathEntry()) {
         // Test 2: Has the resource changed since we last found it?
         if (!oldResource.isStale()) {
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
index 6076260..f7a0420 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
@@ -21,6 +21,8 @@
 import java.io.File;
 import java.util.Enumeration;
 import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
 import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
@@ -51,9 +53,10 @@
   }
 
   private Set<ZipFileResource> allZipFileResources;
-  private Set<AbstractResource> cachedAnswers;
+  private Map<AbstractResource, PathPrefix> cachedAnswers;
   private String cachedLocation;
   private PathPrefixSet lastPrefixSet;
+  private int lastPrefixSetSize;
   private final ZipFile zipFile;
 
   public ZipFileClassPathEntry(ZipFile zipFile) {
@@ -64,18 +67,19 @@
    * Indexes the zip file on-demand, and only once over the life of the process.
    */
   @Override
-  public Set<AbstractResource> findApplicableResources(TreeLogger logger,
-      PathPrefixSet pathPrefixSet) {
+  public Map<AbstractResource, PathPrefix> findApplicableResources(
+      TreeLogger logger, PathPrefixSet pathPrefixSet) {
     // Never re-index.
     if (allZipFileResources == null) {
       allZipFileResources = buildIndex(logger);
     }
 
     if (cachedAnswers == null || lastPrefixSet != pathPrefixSet
-        || lastPrefixSet.getModCount() != pathPrefixSet.getModCount()) {
+        || lastPrefixSetSize != pathPrefixSet.getSize()) {
       cachedAnswers = computeApplicableResources(logger, pathPrefixSet);
+      lastPrefixSet = pathPrefixSet;
+      lastPrefixSetSize = pathPrefixSet.getSize();
     }
-
     return cachedAnswers;
   }
 
@@ -113,17 +117,18 @@
     return results;
   }
 
-  private Set<AbstractResource> computeApplicableResources(TreeLogger logger,
-      PathPrefixSet pathPrefixSet) {
+  private Map<AbstractResource, PathPrefix> computeApplicableResources(
+      TreeLogger logger, PathPrefixSet pathPrefixSet) {
     logger = Messages.FINDING_INCLUDED_RESOURCES.branch(logger,
         zipFile.getName(), null);
 
-    Set<AbstractResource> results = new HashSet<AbstractResource>();
+    Map<AbstractResource, PathPrefix> results = new IdentityHashMap<AbstractResource, PathPrefix>();
     for (ZipFileResource r : allZipFileResources) {
       String path = r.getPath();
-      if (pathPrefixSet.includesResource(path)) {
+      PathPrefix prefix = null;
+      if ((prefix = pathPrefixSet.includesResource(path)) != null) {
         Messages.INCLUDING_RESOURCE.log(logger, path, null);
-        results.add(r);
+        results.put(r, prefix);
       } else {
         Messages.EXCLUDING_RESOURCE.log(logger, path, null);
       }
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java b/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java
index e2bb884..ec178b1 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java
@@ -15,17 +15,29 @@
  */
 package com.google.gwt.dev.shell;
 
+import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 
 /**
  * Interface to the browser window controller.
  */
 public interface BrowserWindowController {
+  /**
+   * Whether to display server control(s).
+   */
+  enum WebServerRestart {
+    DISABLED, ENABLED, NONE
+  }
+
   void closeAllBrowserWindows();
 
   boolean hasBrowserWindowsOpen();
 
+  WebServerRestart hasWebServer();
+
   String normalizeURL(String string);
 
   BrowserWidget openNewBrowserWindow() throws UnableToCompleteException;
-}
\ No newline at end of file
+
+  void restartServer(TreeLogger logger) throws UnableToCompleteException;
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/CheckForUpdates.java b/dev/core/src/com/google/gwt/dev/shell/CheckForUpdates.java
index e9e7886..51bfbe4 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CheckForUpdates.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CheckForUpdates.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.dev.shell;
 
+import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.dev.About;
 
 import org.w3c.dom.Document;
@@ -27,8 +28,11 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PrintWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -43,18 +47,121 @@
  * Orchestrates a best-effort attempt to find out if a new version of GWT is
  * available.
  */
-public abstract class CheckForUpdates {
+public class CheckForUpdates {
 
   /**
-   * Abstract the action to take when an update is available.
+   * Represents a GWT version.
    */
-  public static interface UpdateAvailableCallback {
-    void onUpdateAvailable(String html);
+  public static class GwtVersion implements Comparable<GwtVersion> {
+
+    private final int[] version = new int[3];
+
+    /**
+     * Create a version that avoids any nagging -- "0.0.999".
+     */
+    public GwtVersion() {
+      version[2] = 999;
+    }
+
+    /**
+     * Parse a version number as a string. An empty or null string are
+     * explicitly allowed and are equivalent to "0.0.0".
+     * 
+     * @param versionString
+     * @throws NumberFormatException
+     */
+    public GwtVersion(String versionString) throws NumberFormatException {
+      if (versionString == null) {
+        return;
+      }
+      int part = 0;
+      int v = 0;
+      int len = versionString.length();
+      for (int i = 0; i < len; ++i) {
+        char ch = versionString.charAt(i);
+        if (ch == '.') {
+          if (part >= version.length) {
+            throw new NumberFormatException();
+          }
+          version[part++] = v;
+          v = 0;
+        } else if (Character.isDigit(ch)) {
+          int digit = Character.digit(ch, 10);
+          if (digit < 0) {
+            throw new NumberFormatException();
+          }
+          v = v * 10 + digit;
+        }
+      }
+      version[part++] = v;
+    }
+
+    public int compareTo(GwtVersion o) {
+      for (int i = 0; i <= 2; ++i) {
+        if (version[i] != o.version[i]) {
+          return version[i] - o.version[i];
+        }
+      }
+      return 0;
+    }
+
+    public int getPart(int part) {
+      // TODO: something besides IORE here?
+      return version[part];
+    }
+
+    public boolean isNoNagVersion() {
+      return version[2] == 999;
+    }
+
+    public boolean isUnspecified() {
+      return version[0] == 0 && version[1] == 0 && version[2] == 0;
+    }
+
+    @Override
+    public String toString() {
+      StringBuilder buf = new StringBuilder();
+      buf.append(version[0]).append('.').append(version[1]).append('.');
+      buf.append(version[2]);
+      return buf.toString();
+    }
   }
 
-  protected static final String LAST_SERVER_VERSION = "lastServerVersion";
-  private static final boolean DEBUG_VERSION_CHECK;
+  /**
+   * Returns the result of an update check.
+   */
+  public interface UpdateResult {
+    /**
+     * @return the new version of GWT available.
+     */
+    GwtVersion getNewVersion();
+
+    /**
+     * @return the URL for details about the new version.
+     */
+    URL getURL();
+  }
+
+  public static final long ONE_DAY = 24 * 60 * 60 * 1000;
+  public static final long ONE_MINUTE = 60 * 1000;
+
+  // System properties used by CheckForUpdates
+  protected static final String PROPERTY_DEBUG_HTTP_GET = "gwt.debugLowLevelHttpGet";
+  protected static final String PROPERTY_FORCE_NONNATIVE = "gwt.forceVersionCheckNonNative";
+  protected static final String PROPERTY_PREFS_NAME = "gwt.prefsPathName";
+  protected static final String PROPERTY_QUERY_URL = "gwt.forceVersionCheckURL";
+
+  // Log levels -- in general we want the logging of the update process
+  // to not be visible to normal users.
+  private static final TreeLogger.Type CHECK_ERROR = TreeLogger.DEBUG;
+  private static final TreeLogger.Type CHECK_INFO = TreeLogger.SPAM;
+  private static final TreeLogger.Type CHECK_SPAM = TreeLogger.SPAM;
+  private static final TreeLogger.Type CHECK_WARN = TreeLogger.SPAM;
+
+  // Preferences keys
   private static final String FIRST_LAUNCH = "firstLaunch";
+  private static final String HIGHEST_RUN_VERSION = "highestRunVersion";
+  private static final String LAST_PING = "lastPing";
   private static final String NEXT_PING = "nextPing";
 
   // Uncomment one of constants below to try different variations of failure to
@@ -75,74 +182,6 @@
   // The real URL that should be used.
   private static final String QUERY_URL = "http://tools.google.com/webtoolkit/currentversion.xml";
 
-  private static final int VERSION_PARTS = 3;
-  private static final String VERSION_REGEXP = "\\d+\\.\\d+\\.\\d+";
-
-  static {
-    // Do this in a static initializer so we can ignore all exceptions.
-    //
-    boolean debugVersionCheck = false;
-    try {
-      if (System.getProperty("gwt.debugVersionCheck") != null) {
-        debugVersionCheck = true;
-      }
-    } catch (Throwable e) {
-      // Always silently ignore any errors.
-      //
-    } finally {
-      DEBUG_VERSION_CHECK = debugVersionCheck;
-    }
-  }
-
-  /**
-   * Determines whether the server version is definitively newer than the client
-   * version. If any errors occur in the comparison, this method returns false
-   * to avoid unwanted erroneous notifications.
-   * 
-   * @param clientVersion The current client version
-   * @param serverVersion The current server version
-   * @return true if the server is definitely newer, otherwise false
-   */
-  protected static boolean isServerVersionNewer(String clientVersion,
-      String serverVersion) {
-    if (clientVersion == null || serverVersion == null) {
-      return false;
-    }
-
-    // must match expected format
-    if (!clientVersion.matches(VERSION_REGEXP)
-        || !serverVersion.matches(VERSION_REGEXP)) {
-      return false;
-    }
-
-    // extract the relevant parts
-    String[] clientParts = clientVersion.split("\\.");
-    String[] serverParts = serverVersion.split("\\.");
-    if (clientParts.length != VERSION_PARTS
-        || serverParts.length != VERSION_PARTS) {
-      return false;
-    }
-
-    // examine piece by piece from most significant to least significant
-    for (int i = 0; i < VERSION_PARTS; ++i) {
-      try {
-        int clientPart = Integer.parseInt(clientParts[i]);
-        int serverPart = Integer.parseInt(serverParts[i]);
-        if (serverPart < clientPart) {
-          return false;
-        }
-
-        if (serverPart > clientPart) {
-          return true;
-        }
-      } catch (NumberFormatException e) {
-        return false;
-      }
-    }
-
-    return false;
-  }
-
   private static String getTextOfLastElementHavingTag(Document doc,
       String tagName) {
     NodeList nodeList = doc.getElementsByTagName(tagName);
@@ -161,197 +200,97 @@
     return null;
   }
 
-  private static void parseResponse(Preferences prefs, byte[] response,
-      UpdateAvailableCallback callback) throws IOException,
-      ParserConfigurationException, SAXException {
+  private String entryPoint;
+  private TreeLogger logger;
+  private GwtVersion myVersion;
 
-    if (DEBUG_VERSION_CHECK) {
-      System.out.println("Parsing response (length " + response.length + ")");
-    }
+  /**
+   * Create an update checker which will poll a server URL and log a message
+   * about an update if available.
+   * 
+   * @param logger TreeLogger to use
+   */
+  public CheckForUpdates(TreeLogger logger) {
+    this(logger, null);
+  }
 
-    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-    DocumentBuilder builder = factory.newDocumentBuilder();
-    ByteArrayInputStream bais = new ByteArrayInputStream(response);
-
-    // Parse the XML.
-    //
-    builder.setErrorHandler(new ErrorHandler() {
-
-      public void error(SAXParseException exception) throws SAXException {
-        // fail quietly
-      }
-
-      public void fatalError(SAXParseException exception) throws SAXException {
-        // fail quietly
-      }
-
-      public void warning(SAXParseException exception) throws SAXException {
-        // fail quietly
-      }
-    });
-    Document doc = builder.parse(bais);
-
-    // The latest version number.
-    //
-    String version = getTextOfLastElementHavingTag(doc, "latest-version");
-    if (version == null) {
-      // Not valid; quietly fail.
-      //
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("Failed to find <latest-version>");
-      }
-      return;
-    } else {
-      version = version.trim();
-    }
-
-    String[] versionParts = version.split("\\.");
-    if (versionParts.length != 3) {
-      // Not valid; quietly fail.
-      //
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("Bad version format: " + version);
-      }
-      return;
-    }
+  /**
+   * Create an update checker which will poll a server URL and log a message
+   * about an update if available.
+   * 
+   * @param logger TreeLogger to use
+   * @param entryPoint the name of the main entry point used for this execution
+   */
+  public CheckForUpdates(TreeLogger logger, String entryPoint) {
+    this.logger = logger;
+    this.entryPoint = entryPoint;
     try {
-      Integer.parseInt(versionParts[0]);
-      Integer.parseInt(versionParts[1]);
-      Integer.parseInt(versionParts[2]);
+      myVersion = new GwtVersion(About.GWT_VERSION_NUM);
     } catch (NumberFormatException e) {
-      // Not valid; quietly fail.
-      //
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("Bad version number: " + version);
-      }
-      return;
+      // if our build version number is bogus, use one that avoids nagging
+      myVersion = new GwtVersion();
     }
-
-    // Ping delay for server-controlled throttling.
-    //
-    String pingDelaySecsStr = getTextOfLastElementHavingTag(doc,
-        "min-wait-seconds");
-    int pingDelaySecs = 0;
-    if (pingDelaySecsStr == null) {
-      // Not valid; quietly fail.
-      //
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("Missing <min-wait-seconds>");
-      }
-      return;
-    } else {
-      try {
-        pingDelaySecs = Integer.parseInt(pingDelaySecsStr.trim());
-      } catch (NumberFormatException e) {
-        // Not a valid number; quietly fail.
-        //
-        if (DEBUG_VERSION_CHECK) {
-          System.out.println("Bad min-wait-seconds number: " + pingDelaySecsStr);
-        }
-        return;
-      }
-    }
-
-    // Read the HTML.
-    //
-    String html = getTextOfLastElementHavingTag(doc, "notification");
-
-    if (html == null) {
-      // Not valid; quietly fail.
-      //
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("Missing <notification>");
-      }
-      return;
-    }
-
-    // Okay -- this is a valid response.
-    //
-    processResponse(prefs, version, pingDelaySecs, html, callback);
   }
 
-  private static void processResponse(Preferences prefs, String version,
-      int pingDelaySecs, String html, UpdateAvailableCallback callback) {
-
-    // Record a ping; don't ping again until the delay is up.
-    //
-    long nextPingTime = System.currentTimeMillis() + pingDelaySecs * 1000;
-    prefs.put(NEXT_PING, String.valueOf(nextPingTime));
-
-    if (DEBUG_VERSION_CHECK) {
-      System.out.println("Ping delay is " + pingDelaySecs + "; next ping at "
-          + new Date(nextPingTime));
-    }
-
-    /*
-     * Stash the version we got last time for comparison below, and record for
-     * next time the version we just got.
-     */
-    String lastServerVersion = prefs.get(LAST_SERVER_VERSION, null);
-    prefs.put(LAST_SERVER_VERSION, version);
-
-    // Are we up to date already?
-    //
-    if (!isServerVersionNewer(About.GWT_VERSION_NUM, version)) {
-
-      // Yes, we are.
-      //
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("Server version is not newer");
-      }
-      return;
-    }
-
-    // Have we already prompted for this particular server version?
-    //
-    if (version.equals(lastServerVersion)) {
-
-      // We've already nagged the user once. Don't do it again.
-      //
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("A notification has already been shown for "
-            + version);
-      }
-      return;
-    }
-
-    if (DEBUG_VERSION_CHECK) {
-      System.out.println("Server version has changed to " + version
-          + "; notification will be shown");
-    }
-
-    // Commence nagging.
-    //
-    callback.onUpdateAvailable(html);
+  /**
+   * Check for updates and log to the logger if they are available.
+   * 
+   * @return an UpdateResult or null if there is no new update
+   */
+  public UpdateResult check() {
+    return check(0);
   }
 
-  public void check(final UpdateAvailableCallback callback) {
-
+  /**
+   * Check for updates and log to the logger if they are available.
+   * 
+   * @return an UpdateResult or null if there is no new update
+   */
+  public UpdateResult check(long minCheckMillis) {
+    TreeLogger branch = logger.branch(CHECK_INFO, "Checking for updates");
     try {
-      String forceCheckURL = System.getProperty("gwt.forceVersionCheckURL");
+      String prefsName = System.getProperty(PROPERTY_PREFS_NAME);
+      Preferences prefs;
+      if (prefsName != null) {
+        prefs = Preferences.userRoot().node(prefsName);
+      } else {
+        prefs = Preferences.userNodeForPackage(CheckForUpdates.class);
+      }
 
-      if (forceCheckURL != null && DEBUG_VERSION_CHECK) {
-        System.out.println("Explicit version check URL: " + forceCheckURL);
+      String queryURL = QUERY_URL;
+      String forceCheckURL = System.getProperty(PROPERTY_QUERY_URL);
+
+      if (forceCheckURL != null) {
+        branch.log(CHECK_INFO, "Explicit version check URL: " + forceCheckURL);
+        queryURL = forceCheckURL;
       }
 
       // Get our unique user id (based on absolute timestamp).
       //
       long currentTimeMillis = System.currentTimeMillis();
-      Preferences prefs = Preferences.userNodeForPackage(CheckForUpdates.class);
-
-      // Get our unique user id (based on absolute timestamp).
-      //
       String firstLaunch = prefs.get(FIRST_LAUNCH, null);
       if (firstLaunch == null) {
         firstLaunch = Long.toHexString(currentTimeMillis);
         prefs.put(FIRST_LAUNCH, firstLaunch);
-
-        if (DEBUG_VERSION_CHECK) {
-          System.out.println("Setting first launch to " + firstLaunch);
-        }
+        branch.log(CHECK_SPAM, "Setting first launch to " + firstLaunch);
       } else {
-        if (DEBUG_VERSION_CHECK) {
-          System.out.println("First launch was " + firstLaunch);
+        branch.log(CHECK_SPAM, "First launch was " + firstLaunch);
+      }
+
+      // See if enough time has passed.
+      //
+      String lastPing = prefs.get(LAST_PING, "0");
+      if (lastPing != null) {
+        try {
+          long lastPingTime = Long.parseLong(lastPing);
+          if (currentTimeMillis < lastPingTime + minCheckMillis) {
+            // it's not time yet
+            branch.log(CHECK_INFO, "Last ping was " + new Date(lastPingTime)
+                + ", min wait is " + minCheckMillis + "ms");
+            return null;
+          }
+        } catch (NumberFormatException e) {
+          branch.log(CHECK_WARN, "Error parsing last ping time", e);
         }
       }
 
@@ -363,73 +302,86 @@
           long nextPingTime = Long.parseLong(nextPing);
           if (currentTimeMillis < nextPingTime) {
             // it's not time yet
-            if (DEBUG_VERSION_CHECK) {
-              System.out.println("Next ping is not until "
-                  + new Date(nextPingTime));
-            }
-            return;
+            branch.log(CHECK_INFO, "Next ping is not until "
+                + new Date(nextPingTime));
+            return null;
           }
         } catch (NumberFormatException e) {
-          // ignore
+          branch.log(CHECK_WARN, "Error parsing next ping time", e);
         }
       }
 
       // See if new version is available.
       //
-      String queryURL = forceCheckURL != null ? forceCheckURL : QUERY_URL;
       String url = queryURL + "?v=" + About.GWT_VERSION_NUM + "&id="
-          + firstLaunch;
-
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("Checking for new version at " + url);
+          + firstLaunch + "&r=" + About.GWT_SVNREV;
+      if (entryPoint != null) {
+        url += "&e=" + entryPoint;
       }
 
+      branch.log(CHECK_INFO, "Checking for new version at " + url);
+
       // Do the HTTP GET.
       //
       byte[] response;
       String fullUserAgent = makeUserAgent();
-      if (System.getProperty("gwt.forceVersionCheckNonNative") == null) {
+      if (System.getProperty(PROPERTY_FORCE_NONNATIVE) == null) {
         // Use subclass.
         //
-        response = doHttpGet(fullUserAgent, url);
+        response = doHttpGet(branch, fullUserAgent, url);
       } else {
         // Use the pure Java version, but it probably doesn't work with proxies.
         //
-        response = httpGetNonNative(fullUserAgent, url);
+        response = httpGetNonNative(branch, fullUserAgent, url);
       }
 
       if (response == null || response.length == 0) {
         // Problem. Quietly fail.
         //
-        if (DEBUG_VERSION_CHECK) {
-          System.out.println("Failed to obtain current version info via HTTP");
-        }
-        return;
+        branch.log(CHECK_ERROR,
+            "Failed to obtain current version info via HTTP");
+        return null;
       }
 
       // Parse and process the response.
       // Bad responses will be silently ignored.
       //
-      parseResponse(prefs, response, callback);
+      return parseResponse(branch, prefs, response);
 
     } catch (Throwable e) {
       // Always silently ignore any errors.
       //
-      if (DEBUG_VERSION_CHECK) {
-        System.out.println("Exception while processing version info");
-        e.printStackTrace();
-      }
+      branch.log(CHECK_INFO, "Exception while processing version info", e);
     }
+    return null;
   }
 
-  protected abstract byte[] doHttpGet(String userAgent, String url);
+  /**
+   * Default implementation just uses the platform-independent method. A
+   * subclass should override this method for platform-dependent proxy handling,
+   * for example.
+   * 
+   * @param branch TreeLogger to use
+   * @param userAgent user agent string to send in request
+   * @param url URL to fetch
+   * @return byte array of response, or null if an error
+   */
+  protected byte[] doHttpGet(TreeLogger branch, String userAgent, String url) {
+    return httpGetNonNative(branch, userAgent, url);
+  }
 
   /**
    * This default implementation uses regular Java HTTP, which doesn't deal with
    * proxies automagically. See the IE6 subclasses for an implementation that
    * does deal with proxies.
+   * 
+   * @param branch TreeLogger to use
+   * @param userAgent user agent string to send in request
+   * @param url URL to fetch
+   * @return byte array of response, or null if an error
    */
-  protected byte[] httpGetNonNative(String userAgent, String url) {
+  protected byte[] httpGetNonNative(TreeLogger branch, String userAgent,
+      String url) {
     Throwable caught;
     InputStream is = null;
     try {
@@ -458,8 +410,8 @@
       }
     }
 
-    if (System.getProperty("gwt.debugLowLevelHttpGet") != null) {
-      caught.printStackTrace();
+    if (System.getProperty(PROPERTY_DEBUG_HTTP_GET) != null) {
+      branch.log(CHECK_ERROR, "Exception in HTTP request", caught);
     }
 
     return null;
@@ -496,4 +448,165 @@
 
     return ua;
   }
+
+  private UpdateResult parseResponse(TreeLogger branch, Preferences prefs,
+      byte[] response) throws IOException, ParserConfigurationException,
+      SAXException {
+
+    branch.log(CHECK_SPAM, "Parsing response (length " + response.length + ")");
+
+    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+    DocumentBuilder builder = factory.newDocumentBuilder();
+    ByteArrayInputStream bais = new ByteArrayInputStream(response);
+
+    // Parse the XML.
+    //
+    builder.setErrorHandler(new ErrorHandler() {
+
+      public void error(SAXParseException exception) throws SAXException {
+        // fail quietly
+      }
+
+      public void fatalError(SAXParseException exception) throws SAXException {
+        // fail quietly
+      }
+
+      public void warning(SAXParseException exception) throws SAXException {
+        // fail quietly
+      }
+    });
+    Document doc = builder.parse(bais);
+
+    // The latest version number.
+    //
+    String versionString = getTextOfLastElementHavingTag(doc, "latest-version");
+    if (versionString == null) {
+      // Not valid; quietly fail.
+      //
+      branch.log(CHECK_ERROR, "Failed to find <latest-version>");
+      return null;
+    }
+    GwtVersion currentReleasedVersion;
+    try {
+      currentReleasedVersion = new GwtVersion(versionString.trim());
+    } catch (NumberFormatException e) {
+      branch.log(CHECK_ERROR, "Bad version: " + versionString, e);
+      return null;
+    }
+
+    // Ping delay for server-controlled throttling.
+    //
+    String pingDelaySecsStr = getTextOfLastElementHavingTag(doc,
+        "min-wait-seconds");
+    int pingDelaySecs = 0;
+    if (pingDelaySecsStr == null) {
+      // Not valid; quietly fail.
+      //
+      branch.log(CHECK_ERROR, "Missing <min-wait-seconds>");
+      return null;
+    }
+    try {
+      pingDelaySecs = Integer.parseInt(pingDelaySecsStr.trim());
+    } catch (NumberFormatException e) {
+      // Not a valid number; quietly fail.
+      //
+      branch.log(CHECK_ERROR, "Bad min-wait-seconds number: "
+          + pingDelaySecsStr);
+      return null;
+    }
+
+    String url = getTextOfLastElementHavingTag(doc, "notification-url");
+
+    if (url == null) {
+      // no URL, so write the HTML locally and provide a URL from that
+
+      // Read the HTML.
+      //
+      String html = getTextOfLastElementHavingTag(doc, "notification");
+
+      if (html == null) {
+        // Not valid; quietly fail.
+        //
+        branch.log(CHECK_ERROR, "Missing <notification>");
+        return null;
+      }
+      PrintWriter writer = null;
+      try {
+        String tempDir = System.getProperty("java.io.tmpdir");
+        File updateHtml = new File(tempDir, "gwt-update-"
+            + currentReleasedVersion + ".html");
+        writer = new PrintWriter(new FileOutputStream(updateHtml));
+        writer.print(html);
+        url = "file://" + updateHtml.getAbsolutePath();
+      } finally {
+        if (writer != null) {
+          writer.close();
+        }
+      }
+    }
+
+    // Okay -- this is a valid response.
+    //
+    return processResponse(branch, prefs, currentReleasedVersion,
+        pingDelaySecs, url);
+  }
+
+  private UpdateResult processResponse(TreeLogger branch, Preferences prefs,
+      final GwtVersion serverVersion, int pingDelaySecs, final String notifyUrl) {
+
+    // Record a ping; don't ping again until the delay is up.
+    //
+    long currentTimeMillis = System.currentTimeMillis();
+    long nextPingTime = currentTimeMillis + pingDelaySecs * 1000;
+    prefs.put(NEXT_PING, String.valueOf(nextPingTime));
+    prefs.put(LAST_PING, String.valueOf(currentTimeMillis));
+
+    branch.log(CHECK_INFO, "Ping delay is " + pingDelaySecs + "; next ping at "
+        + new Date(nextPingTime));
+
+    if (myVersion.isNoNagVersion()) {
+      // If the version number indicates no nagging about updates, exit here
+      // once we have recorded the next ping time. No-nag versions (ie,
+      // trunk builds) should also not update the highest version that has been
+      // run.
+      return null;
+    }
+
+    // Update the highest version of GWT that has been run if we are later.
+    GwtVersion highestRunVersion = new GwtVersion(prefs.get(
+        HIGHEST_RUN_VERSION, null));
+    if (myVersion.compareTo(highestRunVersion) > 0) {
+      highestRunVersion = myVersion;
+      prefs.put(HIGHEST_RUN_VERSION, highestRunVersion.toString());
+    }
+
+    // Are we up to date already?
+    //
+    if (highestRunVersion.compareTo(serverVersion) >= 0) {
+      // Yes, we are.
+      //
+      branch.log(CHECK_INFO, "Server version (" + serverVersion
+          + ") is not newer than " + highestRunVersion);
+      return null;
+    }
+
+    // Commence nagging.
+    //
+    URL url = null;
+    try {
+      url = new URL(notifyUrl);
+    } catch (MalformedURLException e) {
+      logger.log(CHECK_ERROR, "Malformed notify URL: " + notifyUrl, e);
+    }
+    final URL finalUrl = url;
+    return new UpdateResult() {
+      public GwtVersion getNewVersion() {
+        return serverVersion;
+      }
+
+      public URL getURL() {
+        return finalUrl;
+      }
+    };
+  }
 }
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 90e5ebe..ebc2778 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -360,7 +360,7 @@
 
   private static EmmaStrategy emmaStrategy;
 
-  private static final Pattern GENERATED_CLASSNAME_PATTERN = Pattern.compile(".+\\$\\d+(\\$.*)?");
+  private static final Pattern GENERATED_CLASSNAME_PATTERN = Pattern.compile(".+\\$\\d.*");
 
   /**
    * Caches the byte code for {@link JavaScriptHost}.
@@ -390,9 +390,10 @@
 
   /**
    * Checks if the class names is generated. Accepts any classes whose names
-   * match .+$\d+($.*)? (handling named classes within anonymous classes).
-   * Checks if the class or any of its enclosing classes are anonymous or
-   * synthetic.
+   * match .+$\d.* (handling named classes within anonymous classes and
+   * multiple named classes of the same name in a class, but in different
+   * methods). Checks if the class or any of its enclosing classes are anonymous
+   * or synthetic.
    * <p>
    * If new compilers have different conventions for anonymous and synthetic
    * classes, this code needs to be updated.
@@ -744,7 +745,7 @@
         lookupClassName);
 
     CompilationUnit unit = (compiledClass == null)
-        ? getUnitForClassName(className) : compiledClass.getUnit();
+        ? getUnitForClassName(lookupClassName) : compiledClass.getUnit();
     if (emmaAvailable) {
       /*
        * build the map for anonymous classes. Do so only if unit has anonymous
@@ -756,20 +757,12 @@
       if (unit != null && !unit.isSuperSource() && unit.hasAnonymousClasses()
           && jsniMethods != null && jsniMethods.size() > 0
           && !unit.createdClassMapping()) {
-        String mainLookupClassName = unit.getTypeName().replace('.', '/');
-        byte mainClassBytes[] = emmaStrategy.getEmmaClassBytes(null,
-            mainLookupClassName, 0);
-        if (mainClassBytes != null) {
-          if (!unit.constructAnonymousClassMappings(mainClassBytes)) {
-            logger.log(TreeLogger.ERROR,
-                "Our heuristic for mapping anonymous classes between compilers "
-                    + "failed. Unsafe to continue because the wrong jsni code "
-                    + "could end up running. className = " + className);
-            return null;
-          }
-        } else {
-          logger.log(TreeLogger.ERROR, "main class bytes is null for unit = "
-              + unit + ", mainLookupClassName = " + mainLookupClassName);
+        if (!unit.constructAnonymousClassMappings(logger)) {
+          logger.log(TreeLogger.ERROR,
+              "Our heuristic for mapping anonymous classes between compilers "
+                  + "failed. Unsafe to continue because the wrong jsni code "
+                  + "could end up running. className = " + className);
+          return null;
         }
       }
     }
@@ -791,7 +784,8 @@
        * find it on disk. Typically this is a synthetic class added by the
        * compiler.
        */
-      if (typeHasCompilationUnit(className) && isClassnameGenerated(className)) {
+      if (typeHasCompilationUnit(lookupClassName)
+          && isClassnameGenerated(className)) {
         /*
          * modification time = 0 ensures that whatever is on the disk is always
          * loaded.
@@ -827,17 +821,19 @@
   /**
    * Returns the compilationUnit corresponding to the className. For nested
    * classes, the unit corresponding to the top level type is returned.
+   * 
+   * Since a file might have several top-level types, search using classFileMap.
    */
   private CompilationUnit getUnitForClassName(String className) {
     String mainTypeName = className;
     int index = mainTypeName.length();
-    CompilationUnit unit = null;
-    while (unit == null && index != -1) {
+    CompiledClass cc = null;
+    while (cc == null && index != -1) {
       mainTypeName = mainTypeName.substring(0, index);
-      unit = compilationState.getCompilationUnitMap().get(mainTypeName);
+      cc = compilationState.getClassFileMap().get(mainTypeName);
       index = mainTypeName.lastIndexOf('$');
     }
-    return unit;
+    return cc == null ? null : cc.getUnit();
   }
 
   private void injectJsniMethods(CompilationUnit unit) {
diff --git a/dev/core/src/com/google/gwt/dev/shell/LowLevel.java b/dev/core/src/com/google/gwt/dev/shell/LowLevel.java
index 9469c01..40f962f 100644
--- a/dev/core/src/com/google/gwt/dev/shell/LowLevel.java
+++ b/dev/core/src/com/google/gwt/dev/shell/LowLevel.java
@@ -103,7 +103,6 @@
             + "'.  Detailed error:\n");
         sb.append(e.getMessage() + ")\n\n");
         sb.append("Your GWT installation may be corrupt");
-        System.err.println(sb.toString());
         throw new UnsatisfiedLinkError(sb.toString());
       }
       sInitialized = true;
diff --git a/dev/core/src/com/google/gwt/dev/shell/PlatformSpecific.java b/dev/core/src/com/google/gwt/dev/shell/PlatformSpecific.java
index 30a834d..cd25809 100644
--- a/dev/core/src/com/google/gwt/dev/shell/PlatformSpecific.java
+++ b/dev/core/src/com/google/gwt/dev/shell/PlatformSpecific.java
@@ -17,12 +17,20 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.TreeLogger.HelpInfo;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
 
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Shell;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Performs platform-specific class selection.
@@ -38,12 +46,51 @@
       "com.google.gwt.dev.shell.mac.BrowserWidgetSaf"};
 
   /**
-   * All of these classes must extend CheckForUpdates.
+   * All of these classes must extend CheckForUpdates. Note that currently only
+   * IE has a custom implementation (to handle proxies) and that CheckForUpdates
+   * must be the last one in the list.
    */
   private static final String[] updaterClassNames = new String[] {
       "com.google.gwt.dev.shell.ie.CheckForUpdatesIE6",
-      "com.google.gwt.dev.shell.moz.CheckForUpdatesMoz",
-      "com.google.gwt.dev.shell.mac.CheckForUpdatesSaf"};
+      "com.google.gwt.dev.shell.CheckForUpdates"};
+
+  public static FutureTask<UpdateResult> checkForUpdatesInBackgroundThread(
+      final TreeLogger logger, final long minCheckMillis) {
+    final String entryPoint = PlatformSpecific.computeEntryPoint();
+    FutureTask<UpdateResult> task = new FutureTask<UpdateResult>(
+        new Callable<UpdateResult>() {
+          public UpdateResult call() throws Exception {
+            final CheckForUpdates updateChecker = createUpdateChecker(logger,
+                entryPoint);
+            return updateChecker == null ? null
+                : updateChecker.check(minCheckMillis);
+          }
+        });
+    Thread checkerThread = new Thread(task, "GWT Update Checker");
+    checkerThread.setDaemon(true);
+    checkerThread.start();
+    return task;
+  }
+
+  /**
+   * Find the first method named "main" on the call stack and use its class as
+   * the entry point.
+   */
+  public static String computeEntryPoint() {
+    Throwable t = new Throwable();
+    for (StackTraceElement stackTrace : t.getStackTrace()) {
+      if (stackTrace.getMethodName().equals("main")) {
+        // Strip package name from main's class
+        String className = stackTrace.getClassName();
+        int i = className.lastIndexOf('.');
+        if (i >= 0) {
+          return className.substring(i + 1);
+        }
+        return className;
+      }
+    }
+    return null;
+  }
 
   public static BrowserWidget createBrowserWidget(TreeLogger logger,
       Composite parent, BrowserWidgetHost host)
@@ -51,10 +98,11 @@
     Throwable caught = null;
     try {
       for (int i = 0; i < browserClassNames.length; i++) {
-        Class<BrowserWidget> clazz = null;
+        Class<? extends BrowserWidget> clazz = null;
         try {
-          clazz = (Class<BrowserWidget>) Class.forName(browserClassNames[i]);
-          Constructor<BrowserWidget> ctor = clazz.getDeclaredConstructor(new Class[] {
+          clazz = Class.forName(browserClassNames[i]).asSubclass(
+              BrowserWidget.class);
+          Constructor<? extends BrowserWidget> ctor = clazz.getDeclaredConstructor(new Class[] {
               Shell.class, BrowserWidgetHost.class});
           BrowserWidget bw = ctor.newInstance(new Object[] {parent, host});
           return bw;
@@ -85,16 +133,25 @@
     throw new UnableToCompleteException();
   }
 
-  public static CheckForUpdates createUpdateChecker() {
+  public static CheckForUpdates createUpdateChecker(TreeLogger logger) {
+    return createUpdateChecker(logger, computeEntryPoint());
+  }
+
+  public static CheckForUpdates createUpdateChecker(TreeLogger logger,
+      String entryPoint) {
     try {
       for (int i = 0; i < updaterClassNames.length; i++) {
         try {
-          Class<CheckForUpdates> clazz = (Class<CheckForUpdates>) Class.forName(updaterClassNames[i]);
-          Constructor<CheckForUpdates> ctor = clazz.getDeclaredConstructor(new Class[] {});
-          CheckForUpdates checker = ctor.newInstance(new Object[] {});
+          Class<? extends CheckForUpdates> clazz = Class.forName(
+              updaterClassNames[i]).asSubclass(CheckForUpdates.class);
+          Constructor<? extends CheckForUpdates> ctor = clazz.getDeclaredConstructor(new Class[] {
+              TreeLogger.class, String.class});
+          CheckForUpdates checker = ctor.newInstance(new Object[] {
+              logger, entryPoint});
           return checker;
-        } catch (ClassNotFoundException e) {
-          // keep trying
+        } catch (Exception e) {
+          // Other exceptions can occur besides ClassNotFoundException,
+          // so ignore them all so we can find a functional updater.
         }
       }
     } catch (Throwable e) {
@@ -102,4 +159,34 @@
     }
     return null;
   }
+
+  public static void logUpdateAvailable(TreeLogger logger,
+      FutureTask<UpdateResult> updater) {
+    if (updater != null && updater.isDone()) {
+      UpdateResult result = null;
+      try {
+        result = updater.get(0, TimeUnit.MILLISECONDS);
+      } catch (InterruptedException e) {
+        // Silently ignore exception
+      } catch (ExecutionException e) {
+        // Silently ignore exception
+      } catch (TimeoutException e) {
+        // Silently ignore exception
+      }
+      logUpdateAvailable(logger, result);
+    }
+  }
+
+  public static void logUpdateAvailable(TreeLogger logger, UpdateResult result) {
+    if (result != null) {
+      final URL url = result.getURL();
+      logger.log(TreeLogger.WARN, "A new version of GWT ("
+          + result.getNewVersion() + ") is available", null, new HelpInfo() {
+        @Override
+        public URL getURL() {
+          return url;
+        }
+      });
+    }
+  }
 }
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java b/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
index 031cc44..e9a1e5e 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.shell.BrowserWindowController.WebServerRestart;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.log.AbstractTreeLogger;
 import com.google.gwt.dev.util.log.TreeLoggerWidget;
@@ -50,6 +51,7 @@
     private ToolItem collapseAll;
     private ToolItem expandAll;
     private ToolItem newWindow;
+    private ToolItem restartServer;
 
     public Toolbar(Composite parent) {
       super(parent);
@@ -69,9 +71,27 @@
           }
         }
       });
-
       newSeparator();
 
+      if (browserWindowController.hasWebServer() != WebServerRestart.NONE) {
+        restartServer = newItem("reload-server.gif", "&Restart Server",
+            "Restart the embedded web server to pick up code changes");
+        restartServer.addSelectionListener(new SelectionAdapter() {
+          @Override
+          public void widgetSelected(SelectionEvent event) {
+            try {
+              browserWindowController.restartServer(getLogger());
+            } catch (UnableToCompleteException e) {
+              getLogger().log(TreeLogger.ERROR, "Unable to restart server", e);
+            }
+          }
+        });
+        newSeparator();
+        if (browserWindowController.hasWebServer() == WebServerRestart.DISABLED) {
+          restartServer.setEnabled(false);
+        }
+      }
+
       collapseAll = newItem("collapse.gif", "&Collapse All",
           "Collapses all log entries");
       collapseAll.addSelectionListener(new SelectionAdapter() {
@@ -181,9 +201,8 @@
   private Toolbar toolbar;
 
   public ShellMainWindow(BrowserWindowController browserWindowController,
-      final Shell parent, int serverPort, boolean checkForUpdates) {
+      Shell parent, String titleText, int serverPort) {
     super(parent, SWT.NONE);
-
     this.browserWindowController = browserWindowController;
 
     colorWhite = new Color(null, 255, 255, 255);
@@ -193,10 +212,9 @@
 
     setLayout(new FillLayout());
     if (serverPort > 0) {
-      parent.setText("Google Web Toolkit Development Shell / Port "
-          + serverPort);
+      parent.setText(titleText + " / Port " + serverPort);
     } else {
-      parent.setText("Google Web Toolkit Development Shell");
+      parent.setText(titleText);
     }
 
     GridLayout gridLayout = new GridLayout(1, true);
@@ -207,7 +225,6 @@
     setLayout(gridLayout);
 
     // Create the toolbar.
-    //
     {
       toolbar = new Toolbar(this);
       GridData data = new GridData();
@@ -217,7 +234,6 @@
     }
 
     // Create the log pane.
-    //
     {
       logPane = new TreeLoggerWidget(this);
       GridData data = new GridData();
@@ -227,41 +243,6 @@
       data.verticalAlignment = GridData.FILL;
       logPane.setLayoutData(data);
     }
-
-    // check for updates
-    if (checkForUpdates) {
-      try {
-        final CheckForUpdates updateChecker = PlatformSpecific.createUpdateChecker();
-        if (updateChecker != null) {
-          final CheckForUpdates.UpdateAvailableCallback callback = new CheckForUpdates.UpdateAvailableCallback() {
-            public void onUpdateAvailable(final String html) {
-              // Do this on the main thread.
-              //
-              parent.getDisplay().asyncExec(new Runnable() {
-                public void run() {
-                  new BrowserDialog(parent, getLogger(), html).open(true);
-                }
-
-              });
-            }
-          };
-
-          // Run the update checker on a background thread.
-          //
-          Thread checkerThread = new Thread() {
-            @Override
-            public void run() {
-              updateChecker.check(callback);
-            }
-          };
-
-          checkerThread.setDaemon(true);
-          checkerThread.start();
-        }
-      } catch (Throwable e) {
-        // Always silently ignore any errors.
-      }
-    }
   }
 
   public AbstractTreeLogger getLogger() {
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
index 58ed521..d47b05b 100644
--- a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
@@ -23,6 +23,7 @@
 
 import org.mortbay.jetty.Server;
 import org.mortbay.jetty.nio.SelectChannelConnector;
+import org.mortbay.jetty.webapp.WebAppClassLoader;
 import org.mortbay.jetty.webapp.WebAppContext;
 import org.mortbay.log.Log;
 import org.mortbay.log.Logger;
@@ -137,8 +138,8 @@
     private final int actualPort;
     private final File appRootDir;
     private final TreeLogger logger;
-    private final WebAppContext wac;
     private final Server server;
+    private final WebAppContext wac;
 
     public JettyServletContainer(TreeLogger logger, Server server,
         WebAppContext wac, int actualPort, File appRootDir) {
@@ -188,7 +189,61 @@
     }
   }
 
-  @SuppressWarnings("unchecked")
+  /**
+   * A {@link WebAppContext} tailored to GWT hosted mode. Features hot-reload
+   * with a new {@link WebAppClassLoader} to pick up disk changes. The default
+   * Jetty {@code WebAppContext} will create new instances of servlets, but it
+   * will not create a brand new {@link ClassLoader}. By creating a new
+   * {@code ClassLoader} each time, we re-read updated classes from disk.
+   * 
+   * Also provides special class filtering to isolate the web app from the GWT
+   * hosting environment.
+   */
+  private final class WebAppContextWithReload extends WebAppContext {
+    /**
+     * Ensures that only Jetty and other server classes can be loaded into the
+     * {@link WebAppClassLoader}. This forces the user to put any necessary
+     * dependencies into WEB-INF/lib.
+     */
+    private final ClassLoader parentClassLoader = new ClassLoader(null) {
+      private final ClassLoader delegateTo = Thread.currentThread().getContextClassLoader();
+
+      @Override
+      protected Class<?> findClass(String name) throws ClassNotFoundException {
+        if (webAppClassLoader != null
+            && (webAppClassLoader.isServerPath(name) || webAppClassLoader.isSystemPath(name))) {
+          return delegateTo.loadClass(name);
+        }
+        throw new ClassNotFoundException();
+      }
+
+    };
+
+    private WebAppClassLoader webAppClassLoader;
+
+    @SuppressWarnings("unchecked")
+    private WebAppContextWithReload(String webApp, String contextPath) {
+      super(webApp, contextPath);
+      // Prevent file locking on Windows; pick up file changes.
+      getInitParams().put(
+          "org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+      webAppClassLoader = new WebAppClassLoader(parentClassLoader, this);
+      setClassLoader(webAppClassLoader);
+      super.doStart();
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+      super.doStop();
+      webAppClassLoader = null;
+      setClassLoader(null);
+    }
+  }
+
   public ServletContainer start(TreeLogger logger, int port, File appRootDir)
       throws Exception {
     checkStartParams(logger, port, appRootDir);
@@ -221,11 +276,8 @@
     server.addConnector(connector);
 
     // Create a new web app in the war directory.
-    WebAppContext wac = new WebAppContext(appRootDir.getAbsolutePath(), "/");
-
-    // Prevent file locking on Windows; pick up file changes.
-    wac.getInitParams().put(
-        "org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
+    WebAppContext wac = new WebAppContextWithReload(
+        appRootDir.getAbsolutePath(), "/");
 
     server.setHandler(wac);
     server.start();
diff --git a/dev/core/src/com/google/gwt/dev/shell/reload-server.gif b/dev/core/src/com/google/gwt/dev/shell/reload-server.gif
new file mode 100644
index 0000000..129f92b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/reload-server.gif
Binary files differ
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableUpdateCheck.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableUpdateCheck.java
new file mode 100644
index 0000000..142f69c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableUpdateCheck.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2009 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.dev.util.arg;
+
+import com.google.gwt.util.tools.ArgHandlerFlag;
+
+/**
+ * Handles the -XdisableUpdateCheck command line flag.
+ */
+public final class ArgHandlerDisableUpdateCheck extends ArgHandlerFlag {
+
+  private final OptionDisableUpdateCheck option;
+
+  public ArgHandlerDisableUpdateCheck(OptionDisableUpdateCheck option) {
+    this.option = option;
+  }
+
+  @Override
+  public String getPurpose() {
+    return "Disable the check to see if an update version of GWT is available";
+  }
+
+  @Override
+  public String getTag() {
+    return "-XdisableUpdateCheck";
+  }
+
+  @Override
+  public boolean isUndocumented() {
+    return true;
+  }
+  
+  @Override
+  public boolean setFlag() {
+    option.setDisableUpdateCheck(true);
+    return true;
+  }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableUpdateCheck.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableUpdateCheck.java
new file mode 100644
index 0000000..085d0d2
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableUpdateCheck.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2009 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.dev.util.arg;
+
+/**
+ * Option to set the compiler working directory.
+ */
+public interface OptionDisableUpdateCheck {
+
+  /**
+   * Check to see if update checks are disabled.
+   */
+  boolean isUpdateCheckDisabled();
+
+  /**
+   * Sets the disable update check flag.
+   */
+  void setDisableUpdateCheck(boolean disabled);
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameComparatorTest.java b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameComparatorTest.java
index 630d438..3af1a6a 100644
--- a/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameComparatorTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameComparatorTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2008 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.dev.javac;
 
 import junit.framework.TestCase;
@@ -38,8 +53,21 @@
   }
 
   public void testMixedNames() {
-    String original[] = {"Foo", "Foo$1", "Foo$1xyz", "Foo$2", "Foo$xyz"};
-    String expected[] = {"Foo", "Foo$1", "Foo$2", "Foo$1xyz", "Foo$xyz"};
+    String original[] = {
+        "Foo", "Foo$1", "Foo$1Bar", "Foo$2Bar", "Foo$2", "Foo$xyz"};
+    String expected[] = {
+        "Foo", "Foo$1", "Foo$2", "Foo$1Bar", "Foo$2Bar", "Foo$xyz"};
+    Arrays.sort(original, new GeneratedClassnameComparator());
+    for (int i = 0; i < original.length; i++) {
+      assertEquals("index = " + i, expected[i], original[i]);
+    }
+  }
+
+  public void testMultipleToplevelClasses() {
+    String original[] = {
+        "Foo$1", "Foo$2", "Bar$1", "Bar$3", "Foo$2$1", "Bar$2$1"};
+    String expected[] = {
+        "Bar$1", "Bar$3", "Foo$1", "Foo$2", "Bar$2$1", "Foo$2$1"};
     Arrays.sort(original, new GeneratedClassnameComparator());
     for (int i = 0; i < original.length; i++) {
       assertEquals("index = " + i, expected[i], original[i]);
diff --git a/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
new file mode 100644
index 0000000..0f428e2
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2008 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.dev.javac;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.javac.CompilationUnit.GeneratedClassnameFinder;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+
+/**
+ * Test-cases to check that we indeed obtain the correct list of nested types
+ * with generated classNames by examining bytecodes using ASM.
+ * 
+ */
+public class GeneratedClassnameFinderTest extends TestCase {
+  enum EnumClass {
+    A, B, C,
+  }
+
+  static class MainClass {
+    static class NestedClass {
+      void foo() {
+        TestInterface c = new TestInterface() {
+          public void foo() {
+          }
+        };
+        EnumClass et = EnumClass.A;
+        switch (et) {
+          case A:
+            break;
+        }
+        TestInterface d = new TestInterface() {
+          public void foo() {
+          }
+        };
+      }
+    }
+
+    void foo() {
+      TestInterface a = new TestInterface() {
+        public void foo() {
+        }
+      };
+      EnumClass et = EnumClass.A;
+      switch (et) {
+        case A:
+          break;
+      }
+      TestInterface b = new TestInterface() {
+        public void foo() {
+        }
+      };
+    }
+  }
+  interface TestInterface {
+    void foo();
+  }
+
+  static final TreeLogger logger = new PrintWriterTreeLogger();
+
+  public void test() {
+    String mainClassName = this.getClass().getName().replace('.', '/');
+    assertEquals(
+        4,
+        new GeneratedClassnameFinder(logger, mainClassName).getClassNames().size());
+    assertEquals(0, new GeneratedClassnameFinder(logger, mainClassName
+        + "$EnumClass").getClassNames().size());
+    assertEquals(0, new GeneratedClassnameFinder(logger, mainClassName
+        + "$TestInterface").getClassNames().size());
+    assertEquals(4, new GeneratedClassnameFinder(logger, mainClassName
+        + "$MainClass").getClassNames().size());
+    assertEquals(2, new GeneratedClassnameFinder(logger, mainClassName
+        + "$MainClass$NestedClass").getClassNames().size());
+  }
+
+  public void testAnonymous() {
+    assertEquals(1, new AnonymousTester().getGeneratedClasses().size());
+  }
+
+  public void testEnum() {
+    assertEquals(0, new EnumTester().getGeneratedClasses().size());
+  }
+
+  public void testJavacWeirdness() {
+    List<String> classNames = new JavacWeirdnessTester().getGeneratedClasses();
+    assertEquals(3, classNames.size());
+    assertTrue(classNames.get(0) + " should not contain Foo",
+        classNames.get(0).indexOf("Foo") == -1);
+    assertTrue(classNames.get(1) + " should contain Foo",
+        classNames.get(1).indexOf("Foo") != -1);
+    assertTrue(classNames.get(2) + " should contain Foo",
+        classNames.get(2).indexOf("Foo") != -1);
+  }
+
+  public void testNamedLocal() {
+    assertEquals(2, new NamedLocalTester().getGeneratedClasses().size());
+  }
+
+  public void testNested() {
+    assertEquals(2, new NestedTester().getGeneratedClasses().size());
+  }
+
+  public void testStatic() {
+    assertEquals(0, new StaticTester().getGeneratedClasses().size());
+  }
+
+  public void testTopLevel() {
+    assertEquals(1, new TopLevelTester().getGeneratedClasses().size());
+  }
+
+}
+
+/**
+ * For testing a class containing an anonymous inner class.
+ */
+class AnonymousTester {
+  interface TestInterface {
+    void foo();
+  }
+
+  void foo() {
+    TestInterface a = new TestInterface() {
+      public void foo() {
+      }
+    };
+    a.foo();
+  }
+
+  List<String> getGeneratedClasses() {
+    return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+        this.getClass().getName().replace('.', '/'))).getClassNames();
+  }
+}
+
+/**
+ * For testing a class with an Enum (for which javac generates a synthetic
+ * class).
+ */
+class EnumTester {
+  enum EnumClass {
+    A, B, C,
+  }
+
+  void foo() {
+    EnumClass et = EnumClass.A;
+    switch (et) {
+      case A:
+        break;
+    }
+  }
+
+  List<String> getGeneratedClasses() {
+    return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+        this.getClass().getName().replace('.', '/'))).getClassNames();
+  }
+}
+
+/**
+ * Javac generates weird code for the following class. It passes a synthetic
+ * class ...Tester$1 as a first parameter to constructors of Fuji and Granny.
+ * Normally, it generates the synthetic class, but in this case, it decides not
+ * to generate the class. However, the bytecode still has reference to the
+ * synthetic class -- it just passes null for the synthetic class.
+ * 
+ * This code also tests for an anonymous class extending a named local class.
+ */
+class JavacWeirdnessTester {
+  private abstract static class Apple implements Fruit {
+  }
+
+  private static interface Fruit {
+  }
+
+  private static class Fuji extends Apple {
+  }
+
+  private static class Granny extends Apple {
+  }
+
+  private static volatile boolean TRUE = true;
+
+  List<String> getGeneratedClasses() {
+    return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+        this.getClass().getName().replace('.', '/'))).getClassNames();
+  }
+
+  private void assertEquals(Object a, Object b) {
+  }
+
+  private void testArrayStore() {
+    Apple[] apple = TRUE ? new Granny[3] : new Apple[3];
+    Apple g = TRUE ? (Apple) new Granny() : (Apple) new Fuji();
+    Apple a = apple[0] = g;
+    assertEquals(g, a);
+  }
+
+  private void testDeadTypes() {
+    if (false) {
+      new Object() {
+      }.toString();
+
+      class Foo {
+        void a() {
+        }
+      }
+      new Foo().a();
+    }
+  }
+
+  private void testLocalClasses() {
+    class Foo {
+      public Foo(int j) {
+        assertEquals(1, j);
+      };
+    }
+    final int i;
+    new Foo(i = 1) {
+      {
+        assertEquals(1, i);
+      }
+    };
+    assertEquals(1, i);
+  }
+
+  private void testReturnStatementInCtor() {
+    class Foo {
+      int i;
+
+      Foo(int i) {
+        this.i = i;
+        if (i == 0) {
+          return;
+        } else if (i == 1) {
+          return;
+        }
+        return;
+      }
+    }
+    assertEquals(new Foo(0).i, 0);
+  }
+}
+
+/**
+ * For testing a class with a generated name like $1Foo.
+ */
+class NamedLocalTester {
+  void foo1() {
+    if (false) {
+      class Foo {
+        void foo() {
+        }
+      }
+      new Foo().foo();
+    }
+  }
+
+  void foo2() {
+    class Foo {
+      void foo() {
+      }
+    }
+    new Foo().foo();
+  }
+
+  void foo3() {
+    class Foo {
+      void foo() {
+      }
+    }
+    new Foo().foo();
+  }
+
+  List<String> getGeneratedClasses() {
+    return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+        this.getClass().getName().replace('.', '/'))).getClassNames();
+  }
+}
+
+/**
+ * For testing that nested classes are examined recursively for classes with
+ * generated names.
+ */
+class NestedTester {
+  class MainClass {
+    class NestedClass {
+      void foo() {
+        class Foo {
+          void bar() {
+          }
+        }
+        new Foo().bar();
+      }
+    }
+
+    void foo() {
+      class Foo {
+        void bar() {
+        }
+      }
+      new Foo().bar();
+    }
+  }
+
+  List<String> getGeneratedClasses() {
+    return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+        this.getClass().getName().replace('.', '/'))).getClassNames();
+  }
+}
+
+/**
+ * For testing classes with private static members (javac generates a synthetic
+ * class here but the jdt does not).
+ */
+class StaticTester {
+  private abstract static class Apple implements Fruit {
+  }
+
+  private static interface Fruit {
+    void bar();
+  }
+
+  private static class Fuji extends Apple {
+    public void bar() {
+    }
+  }
+
+  private static class Granny extends Apple {
+    public void bar() {
+    }
+  }
+
+  List<String> getGeneratedClasses() {
+    return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+        this.getClass().getName().replace('.', '/'))).getClassNames();
+  }
+
+}
+
+/**
+ * For testing that a class with a generated name inside another top-level class
+ * is found.
+ */
+class TopLevelTester {
+  public void foo() {
+    GeneratedClassnameFinderTest.TestInterface a = new GeneratedClassnameFinderTest.TestInterface() {
+      public void foo() {
+      }
+    };
+  }
+
+  List<String> getGeneratedClasses() {
+    return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+        this.getClass().getName().replace('.', '/'))).getClassNames();
+  }
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
index c72d651..c42d98e 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
@@ -25,7 +25,8 @@
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
 import java.util.Set;
 import java.util.jar.JarFile;
 
@@ -67,14 +68,14 @@
     }
 
     @Override
-    public Set<AbstractResource> findApplicableResources(TreeLogger logger,
-        PathPrefixSet pathPrefixSet) {
-      Set<AbstractResource> results = new HashSet<AbstractResource>();
-      Set<AbstractResource> rs = cpe.findApplicableResources(logger,
-          pathPrefixSet);
-      for (AbstractResource r : rs) {
+    public Map<AbstractResource, PathPrefix> findApplicableResources(
+        TreeLogger logger, PathPrefixSet pathPrefixSet) {
+      Map<AbstractResource, PathPrefix> results = new IdentityHashMap<AbstractResource, PathPrefix>();
+      Map<AbstractResource, PathPrefix> rs = cpe.findApplicableResources(
+          logger, pathPrefixSet);
+      for (AbstractResource r : rs.keySet()) {
         if (r.getPath().indexOf(".svn/") < 0) {
-          results.add(r);
+          results.put(r, rs.get(r));
         }
       }
       return results;
@@ -114,6 +115,7 @@
       addResource("com/google/gwt/i18n/rebind/LocalizableGenerator.java");
       addResource("org/example/bar/client/BarClient2.txt");
       addResource("org/example/bar/client/BarClient3.txt");
+      addResource("org/example/foo/client/BarClient1.txt");
     }
   }
 
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java
index 3454176..5bfddad 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java
@@ -81,7 +81,7 @@
 
     {
       // Examine cpe1.
-      Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+      Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
 
       assertEquals(3, r.size());
       assertPathIncluded(r, "com/google/gwt/user/client/Command.java");
@@ -91,7 +91,7 @@
 
     {
       // Examine cpe2.
-      Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+      Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
 
       assertEquals(1, r.size());
       assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
@@ -106,7 +106,7 @@
     PathPrefixSet pps = new PathPrefixSet();
     pps.add(new PathPrefix("", null));
 
-    Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+    Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
 
     assertEquals(9, r.size());
     assertPathIncluded(r, "com/google/gwt/user/User.gwt.xml");
@@ -127,15 +127,16 @@
 
     PathPrefixSet pps = new PathPrefixSet();
     pps.add(new PathPrefix("", null));
-    Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+    Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
 
-    assertEquals(5, r.size());
+    assertEquals(6, r.size());
     assertPathIncluded(r, "com/google/gwt/i18n/I18N.gwt.xml");
     assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
     assertPathIncluded(r,
         "com/google/gwt/i18n/rebind/LocalizableGenerator.java");
     assertPathIncluded(r, "org/example/bar/client/BarClient2.txt");
     assertPathIncluded(r, "org/example/bar/client/BarClient3.txt");
+    assertPathIncluded(r, "org/example/foo/client/BarClient1.txt");
   }
 
   private void testPathPrefixSetChanges(ClassPathEntry cpe1, ClassPathEntry cpe2) {
@@ -148,7 +149,7 @@
       pps.add(new PathPrefix("com/google/gwt/i18n/", null));
 
       // Examine cpe1 in the absence of the filter.
-      Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+      Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
 
       assertEquals(4, r1.size());
       assertPathIncluded(r1, "com/google/gwt/user/User.gwt.xml");
@@ -157,7 +158,7 @@
       assertPathIncluded(r1, "com/google/gwt/user/client/ui/Widget.java");
 
       // Examine cpe2 in the absence of the filter.
-      Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+      Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
 
       assertEquals(3, r2.size());
       assertPathIncluded(r2, "com/google/gwt/i18n/I18N.gwt.xml");
@@ -179,7 +180,7 @@
       pps.add(new PathPrefix("com/google/gwt/i18n/", excludeXmlFiles));
 
       // Examine cpe1 in the presence of the filter.
-      Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+      Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
 
       assertEquals(3, r1.size());
       assertPathNotIncluded(r1, "com/google/gwt/user/User.gwt.xml");
@@ -188,7 +189,7 @@
       assertPathIncluded(r1, "com/google/gwt/user/client/ui/Widget.java");
 
       // Examine cpe2 in the presence of the filter.
-      Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+      Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
 
       assertEquals(2, r2.size());
       assertPathNotIncluded(r1, "com/google/gwt/user/User.gwt.xml");
@@ -211,12 +212,12 @@
       }));
 
       // Examine cpe1 in the presence of the filter.
-      Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+      Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
 
       assertEquals(0, r1.size());
 
       // Examine cpe2 in the presence of the filter.
-      Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+      Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
 
       assertEquals(0, r2.size());
     }
@@ -238,7 +239,7 @@
 
     {
       // Examine cpe1.
-      Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+      Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
 
       assertEquals(3, r.size());
       // User.gwt.xml would be included but for the filter.
@@ -249,7 +250,7 @@
 
     {
       // Examine cpe2.
-      Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+      Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
 
       assertEquals(2, r.size());
       // I18N.gwt.xml would be included but for the filter.
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java b/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java
index 913b071..254c0f9 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java
@@ -21,9 +21,8 @@
 import junit.framework.Assert;
 
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.Map;
-import java.util.Set;
 
 public class MockClassPathEntry extends ClassPathEntry {
 
@@ -46,14 +45,15 @@
   }
 
   @Override
-  public Set<AbstractResource> findApplicableResources(TreeLogger logger,
-      PathPrefixSet pathPrefixes) {
+  public Map<AbstractResource, PathPrefix> findApplicableResources(
+      TreeLogger logger, PathPrefixSet pathPrefixes) {
     // Only include resources that have the prefix and pass its filter.
-    HashSet<AbstractResource> results = new HashSet<AbstractResource>();
+    Map<AbstractResource, PathPrefix> results = new IdentityHashMap<AbstractResource, PathPrefix>();
     for (Map.Entry<String, MockAbstractResource> entry : resourceMap.entrySet()) {
       String path = entry.getKey();
-      if (pathPrefixes.includesResource(path)) {
-        results.add(entry.getValue());
+      PathPrefix prefix = null;
+      if ((prefix = pathPrefixes.includesResource(path)) != null) {
+        results.put(entry.getValue(), prefix);
       }
     }
 
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java
index e9d581c..8c73c99 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java
@@ -24,154 +24,181 @@
 
   public void testEmptyPrefixSet() {
     PathPrefixSet pps = new PathPrefixSet();
-    assertFalse(pps.includesResource("com/google/gwt/user/client/Command.java"));
+    assertNull(pps.includesResource("com/google/gwt/user/client/Command.java"));
   }
 
-  public void testNonOverlappingPrefixes() {
-    {
-      /*
-       * Test with null filters to ensure nothing gets filtered out.
-       */
-      PathPrefixSet pps = new PathPrefixSet();
-      pps.add(new PathPrefix("com/google/gwt/user/client/", null));
-      pps.add(new PathPrefix("com/google/gwt/i18n/client/", null));
-      pps.add(new PathPrefix("com/google/gwt/dom/client/", null));
+  public void testNonOverlappingPrefixesEmptyFilter() {
+    /*
+     * Test with null filters to ensure nothing gets filtered out.
+     */
+    PathPrefixSet pps = new PathPrefixSet();
+    PathPrefix pp1 = new PathPrefix("com/google/gwt/user/client/", null);
+    PathPrefix pp2 = new PathPrefix("com/google/gwt/i18n/client/", null);
+    PathPrefix pp3 = new PathPrefix("com/google/gwt/dom/client/", null);
+    pps.add(pp1);
+    pps.add(pp2);
+    pps.add(pp3);
 
-      assertTrue(pps.includesDirectory("com/"));
-      assertTrue(pps.includesDirectory("com/google/"));
-      assertTrue(pps.includesDirectory("com/google/gwt/"));
-      assertTrue(pps.includesDirectory("com/google/gwt/user/"));
-      assertTrue(pps.includesDirectory("com/google/gwt/user/client/"));
-      assertTrue(pps.includesDirectory("com/google/gwt/user/client/ui/"));
+    assertTrue(pps.includesDirectory("com/"));
+    assertTrue(pps.includesDirectory("com/google/"));
+    assertTrue(pps.includesDirectory("com/google/gwt/"));
+    assertTrue(pps.includesDirectory("com/google/gwt/user/"));
+    assertTrue(pps.includesDirectory("com/google/gwt/user/client/"));
+    assertTrue(pps.includesDirectory("com/google/gwt/user/client/ui/"));
 
-      assertFalse(pps.includesDirectory("org/"));
-      assertFalse(pps.includesDirectory("org/example/"));
-      assertFalse(pps.includesDirectory("com/google/gwt/user/server/"));
-      assertFalse(pps.includesDirectory("com/google/gwt/xml/client/"));
+    assertFalse(pps.includesDirectory("org/"));
+    assertFalse(pps.includesDirectory("org/example/"));
+    assertFalse(pps.includesDirectory("com/google/gwt/user/server/"));
+    assertFalse(pps.includesDirectory("com/google/gwt/xml/client/"));
 
-      assertTrue(pps.includesResource("com/google/gwt/user/client/Command.java"));
-      assertTrue(pps.includesResource("com/google/gwt/user/client/Timer.java"));
-      assertTrue(pps.includesResource("com/google/gwt/i18n/client/Messages.java"));
-      assertTrue(pps.includesResource("com/google/gwt/dom/client/DivElement.java"));
+    assertEquals(pp1,
+        pps.includesResource("com/google/gwt/user/client/Command.java"));
+    assertEquals(pp1,
+        pps.includesResource("com/google/gwt/user/client/Timer.java"));
+    assertEquals(pp2,
+        pps.includesResource("com/google/gwt/i18n/client/Messages.java"));
+    assertEquals(pp3,
+        pps.includesResource("com/google/gwt/dom/client/DivElement.java"));
 
-      assertFalse(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
-      assertFalse(pps.includesResource("com/google/gwt/sample/hello/client/Hello.java"));
-      assertFalse(pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
-    }
-
-    {
-      /*
-       * Test with a real filter to ensure it does have an effect.
-       */
-      PathPrefixSet pps = new PathPrefixSet();
-      ResourceFilter allowsGifs = new ResourceFilter() {
-        public boolean allows(String path) {
-          return path.toLowerCase().endsWith(".gif");
-        }
-      };
-
-      pps.add(new PathPrefix("com/google/gwt/user/public/", allowsGifs));
-      pps.add(new PathPrefix("com/google/gwt/sample/mail/public/", allowsGifs));
-
-      // Correct prefix, and filter should allow .
-      assertTrue(pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
-      assertTrue(pps.includesResource("com/google/gwt/sample/mail/public/inboxIcon.gif"));
-
-      // Correct prefix, but filter should exclude.
-      assertFalse(pps.includesResource("com/google/gwt/user/public/README.txt"));
-      assertFalse(pps.includesResource("com/google/gwt/sample/mail/public/README.txt"));
-
-      // Wrong prefix, and filter would have excluded.
-      assertFalse(pps.includesResource("com/google/gwt/user/client/Command.java"));
-      assertFalse(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
-
-      // Wrong prefix, but filter would have allowed it.
-      assertFalse(pps.includesResource("com/google/gwt/i18n/public/flags.gif"));
-    }
+    assertNull(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
+    assertNull(pps.includesResource("com/google/gwt/sample/hello/client/Hello.java"));
+    assertNull(pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
   }
 
-  public void testOverlappingPrefixes() {
-    {
-      /*
-       * Without a filter.
-       */
-      PathPrefixSet pps = new PathPrefixSet();
-      pps.add(new PathPrefix("", null));
-      pps.add(new PathPrefix("a/", null));
-      pps.add(new PathPrefix("a/b/", null));
-      pps.add(new PathPrefix("a/b/c/", null));
+  public void testNonOverlappingPrefixesNonEmptyFilter() {
+    /*
+     * Test with a real filter to ensure it does have an effect.
+     */
+    PathPrefixSet pps = new PathPrefixSet();
+    ResourceFilter allowsGifs = new ResourceFilter() {
+      public boolean allows(String path) {
+        return path.toLowerCase().endsWith(".gif");
+      }
+    };
 
-      assertTrue(pps.includesResource("W.java"));
-      assertTrue(pps.includesResource("a/X.java"));
-      assertTrue(pps.includesResource("a/b/Y.java"));
-      assertTrue(pps.includesResource("a/b/c/Z.java"));
-      assertTrue(pps.includesResource("a/b/c/d/V.java"));
-    }
+    PathPrefix pp1 = new PathPrefix("com/google/gwt/user/public/", allowsGifs);
+    PathPrefix pp2 = new PathPrefix("com/google/gwt/sample/mail/public/",
+        allowsGifs);
+    pps.add(pp1);
+    pps.add(pp2);
 
-    {
-      /*
-       * Ensure the right filter applies.
-       */
-      PathPrefixSet pps = new PathPrefixSet();
-      pps.add(new PathPrefix("", null));
-      pps.add(new PathPrefix("a/", null));
-      pps.add(new PathPrefix("a/b/", new ResourceFilter() {
-        public boolean allows(String path) {
-          // Disallow anything ending with "FILTERMEOUT".
-          return !path.endsWith("FILTERMEOUT");
-        }
-      }));
-      pps.add(new PathPrefix("a/b/c/", null));
+    // Correct prefix, and filter should allow .
+    assertEquals(pp1,
+        pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
+    assertEquals(pp2,
+        pps.includesResource("com/google/gwt/sample/mail/public/inboxIcon.gif"));
 
-      assertTrue(pps.includesResource("W.java"));
-      assertTrue(pps.includesResource("a/X.java"));
-      assertTrue(pps.includesResource("a/b/Y.java"));
-      // This should be gone, since it is found in b.
-      assertFalse(pps.includesResource("a/b/FILTERMEOUT"));
-      /*
-       * This should not be gone, because it is using c's (null) filter instead
-       * of b's. The logic here is that the prefix including c is more specific
-       * and seemed to want c's resources to be included.
-       */
-      assertTrue(pps.includesResource("a/b/c/DONT_FILTERMEOUT"));
-      assertTrue(pps.includesResource("a/b/c/Z.java"));
-      assertTrue(pps.includesResource("a/b/c/d/V.java"));
-    }
+    // Correct prefix, but filter should exclude.
+    assertNull(pps.includesResource("com/google/gwt/user/public/README.txt"));
+    assertNull(pps.includesResource("com/google/gwt/sample/mail/public/README.txt"));
+
+    // Wrong prefix, and filter would have excluded.
+    assertNull(pps.includesResource("com/google/gwt/user/client/Command.java"));
+    assertNull(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
+
+    // Wrong prefix, but filter would have allowed it.
+    assertNull(pps.includesResource("com/google/gwt/i18n/public/flags.gif"));
+  }
+
+  public void testOverlappingPrefixesEmptyFilter() {
+    /*
+     * Without a filter.
+     */
+    PathPrefixSet pps = new PathPrefixSet();
+    PathPrefix pp1 = new PathPrefix("a/b/", null);
+    PathPrefix pp2 = new PathPrefix("a/", null);
+    PathPrefix pp3 = new PathPrefix("", null);
+    PathPrefix pp4 = new PathPrefix("a/b/c/", null);
+    PathPrefix pp5 = new PathPrefix("a/", null);
+    pps.add(pp1);
+    pps.add(pp2);
+    pps.add(pp3);
+    pps.add(pp4);
+    // pp5 now overrides pp2
+    pps.add(pp5);
+
+    assertEquals(pp3, pps.includesResource("W.java"));
+    assertEquals(pp5, pps.includesResource("a/X.java"));
+    assertEquals(pp1, pps.includesResource("a/b/Y.java"));
+    assertEquals(pp4, pps.includesResource("a/b/c/Z.java"));
+    assertEquals(pp4, pps.includesResource("a/b/c/d/V.java"));
+  }
+
+  public void testOverlappingPrefixesNonEmptyFilter() {
+    /*
+     * Ensure the right filter applies.
+     */
+    PathPrefixSet pps = new PathPrefixSet();
+    PathPrefix pp1 = new PathPrefix("", null);
+    PathPrefix pp2 = new PathPrefix("a/", null);
+    PathPrefix pp3 = new PathPrefix("a/b/", new ResourceFilter() {
+      public boolean allows(String path) {
+        // Disallow anything ending with "FILTERMEOUT".
+        return !path.endsWith("FILTERMEOUT");
+      }
+    });
+    PathPrefix pp4 = new PathPrefix("a/b/c/", null);
+    PathPrefix pp5 = new PathPrefix("a/", new ResourceFilter() {
+      public boolean allows(String path) {
+        return !path.endsWith("X.java");
+      }
+    });
+    pps.add(pp1);
+    pps.add(pp2);
+    pps.add(pp3);
+    pps.add(pp4);
+    pps.add(pp5);
+
+    assertEquals(pp1, pps.includesResource("W.java"));
+
+    // see TODO in the implementation note for PathPrefixSet.java
+    // assertEquals(pp2, pps.includesResource("a/X.java"));
+    assertEquals(pp5, pps.includesResource("a/Y.java"));
+    assertEquals(pp3, pps.includesResource("a/b/Y.java"));
+    // This should be gone, since it is found in b.
+    assertNull(pps.includesResource("a/b/FILTERMEOUT"));
+    /*
+     * This should not be gone, because it is using c's (null) filter instead of
+     * b's. The logic here is that the prefix including c is more specific and
+     * seemed to want c's resources to be included.
+     */
+    assertEquals(pp4, pps.includesResource("a/b/c/DONT_FILTERMEOUT"));
+    assertEquals(pp4, pps.includesResource("a/b/c/Z.java"));
+    assertEquals(pp4, pps.includesResource("a/b/c/d/V.java"));
   }
 
   /**
-   * In essense, this tests support for the default package in Java.
+   * In essence, this tests support for the default package in Java.
    */
-  public void testZeroLengthPrefix() {
-    {
-      /*
-       * Without a filter.
-       */
-      PathPrefixSet pps = new PathPrefixSet();
-      pps.add(new PathPrefix("", null));
+  public void testZeroLengthPrefixEmptyFilter() {
+    /*
+     * Without a filter.
+     */
+    PathPrefixSet pps = new PathPrefixSet();
+    PathPrefix pp1 = new PathPrefix("", null);
+    pps.add(pp1);
 
-      assertTrue(pps.includesResource("W.java"));
-      assertTrue(pps.includesResource("a/X.java"));
-      assertTrue(pps.includesResource("a/b/Y.java"));
-      assertTrue(pps.includesResource("a/b/c/Z.java"));
-    }
+    assertEquals(pp1, pps.includesResource("W.java"));
+    assertEquals(pp1, pps.includesResource("a/X.java"));
+    assertEquals(pp1, pps.includesResource("a/b/Y.java"));
+    assertEquals(pp1, pps.includesResource("a/b/c/Z.java"));
+  }
 
-    {
-      /*
-       * With a filter.
-       */
-      PathPrefixSet pps = new PathPrefixSet();
-      pps.add(new PathPrefix("", new ResourceFilter() {
-        public boolean allows(String path) {
-          return path.endsWith("Y.java");
-        }
-      }));
+  public void testZeroLengthPrefixNonEmptyFilter() {
+    /*
+     * With a filter.
+     */
+    PathPrefixSet pps = new PathPrefixSet();
+    PathPrefix pp1 = new PathPrefix("", new ResourceFilter() {
+      public boolean allows(String path) {
+        return path.endsWith("Y.java");
+      }
+    });
+    pps.add(pp1);
 
-      assertFalse(pps.includesResource("W.java"));
-      assertFalse(pps.includesResource("a/X.java"));
-      assertTrue(pps.includesResource("a/b/Y.java"));
-      assertFalse(pps.includesResource("a/b/c/Z.java"));
-
-    }
+    assertNull(pps.includesResource("W.java"));
+    assertNull(pps.includesResource("a/X.java"));
+    assertEquals(pp1, pps.includesResource("a/b/Y.java"));
+    assertNull(pps.includesResource("a/b/c/Z.java"));
   }
 }
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
index 8449d7d..560ed05 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
@@ -15,10 +15,6 @@
  */
 package com.google.gwt.dev.resource.impl;
 
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.dev.resource.Resource;
-import com.google.gwt.util.tools.Utility;
-
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -33,6 +29,10 @@
 import java.util.Map;
 import java.util.Set;
 
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.util.tools.Utility;
+
 /**
  * Tests {@link ResourceOracleImpl}.
  * 
@@ -153,10 +153,10 @@
     PathPrefix pathPrefixReroot = new PathPrefix("org/example/bar/client",
         null, true);
 
-    testClassPathOrderIsHonored(logger, resKeyNormal, cp12, pathPrefixNormal);
-    testClassPathOrderIsHonored(logger, resKeyReroot, cp12, pathPrefixReroot);
-    testClassPathOrderIsHonored(logger, resKeyNormal, cp21, pathPrefixNormal);
-    testClassPathOrderIsHonored(logger, resKeyReroot, cp21, pathPrefixReroot);
+    testResourceInCPE(logger, resKeyNormal, cpe1jar, cp12, pathPrefixNormal);
+    testResourceInCPE(logger, resKeyReroot, cpe1jar, cp12, pathPrefixReroot);
+    testResourceInCPE(logger, resKeyNormal, cpe2jar, cp21, pathPrefixNormal);
+    testResourceInCPE(logger, resKeyReroot, cpe2jar, cp21, pathPrefixReroot);
   }
 
   public void testNoClassPathEntries() {
@@ -167,6 +167,41 @@
   }
 
   /**
+   * Test that ResourceOracleImpl prefers the order of path prefixes over
+   * ClassPathEntries.
+   * <p>
+   * cpe1 contains org/example/bar/client/BarClient1.txt and cpe2 contains
+   * org/example/foo/client/BarClient1.txt
+   * 
+   * @throws URISyntaxException
+   * @throws IOException
+   */
+  public void testPathPrefixOrderPreferredOverClasspath() throws IOException,
+      URISyntaxException {
+    TreeLogger logger = createTestTreeLogger();
+    ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+    ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+
+    ClassPathEntry[] cp12 = new ClassPathEntry[] {cpe1jar, cpe2jar};
+    ClassPathEntry[] cp21 = new ClassPathEntry[] {cpe2jar, cpe1jar};
+
+    String keyReroot = "/BarClient1.txt";
+
+    PathPrefix pp1 = new PathPrefix("org/example/bar/client", null, true);
+    PathPrefix pp2 = new PathPrefix("org/example/foo/client", null, true);
+
+    // Resource in cpe2 wins because pp2 comes later.
+    testResourceInCPE(logger, keyReroot, cpe2jar, cp12, pp1, pp2);
+    // Order of specifying classpath is reversed, it still matches cpe2.
+    testResourceInCPE(logger, keyReroot, cpe2jar, cp21, pp1, pp2);
+
+    // Resource in cpe1 wins because pp1 comes later.
+    testResourceInCPE(logger, keyReroot, cpe1jar, cp12, pp2, pp1);
+    // Order of specifying classpath is reversed, it still matches cpe1.
+    testResourceInCPE(logger, keyReroot, cpe1jar, cp21, pp2, pp1);
+  }
+
+  /**
    * Tests the actual reading of resources.
    * 
    * @throws URISyntaxException
@@ -284,6 +319,49 @@
   }
 
   /**
+   * Ensure refresh is stable when multiple classpaths + multiple path prefixes
+   * all include the same resource.
+   */
+  public void testStableRefreshOnBlot() {
+    TreeLogger logger = createTestTreeLogger();
+    ClassPathEntry cpe1 = getClassPathEntry1AsMock();
+    ClassPathEntry cpe2 = getClassPathEntry2AsMock();
+    PathPrefix pp1 = new PathPrefix("org/example/bar/client", null, false);
+    PathPrefix pp2 = new PathPrefix("org/example/bar", null, false);
+    testResourceInCPE(logger, "org/example/bar/client/BarClient2.txt", cpe1,
+        new ClassPathEntry[] {cpe1, cpe2}, pp1, pp2);
+  }
+
+  /**
+   * Ensure refresh is stable when multiple classpaths + multiple path prefixes
+   * all include the same resource.
+   */
+  public void testSuperSourceSupercedesSource() {
+    TreeLogger logger = createTestTreeLogger();
+
+    MockClassPathEntry cpe1 = new MockClassPathEntry("/cpe1/");
+    cpe1.addResource("java/lang/Object.java");
+
+    MockClassPathEntry cpe2 = new MockClassPathEntry("/cpe2/");
+    cpe2.addResource("translatable/java/lang/Object.java");
+
+    PathPrefix pp1 = new PathPrefix("java/lang/", null, false);
+    PathPrefix pp2 = new PathPrefix("translatable/", null, true);
+
+    // Ensure the translatable overrides the basic despite swapping CPE order.
+    testResourceInCPE(logger, "java/lang/Object.java", cpe2,
+        new ClassPathEntry[] {cpe1, cpe2}, pp1, pp2);
+    testResourceInCPE(logger, "java/lang/Object.java", cpe2,
+        new ClassPathEntry[] {cpe2, cpe1}, pp1, pp2);
+
+    // Ensure the translatable overrides the basic despite swapping PPS order.
+    testResourceInCPE(logger, "java/lang/Object.java", cpe2,
+        new ClassPathEntry[] {cpe1, cpe2}, pp2, pp1);
+    testResourceInCPE(logger, "java/lang/Object.java", cpe2,
+        new ClassPathEntry[] {cpe2, cpe1}, pp2, pp1);
+  }
+
+  /**
    * @param classPathEntry
    * @param string
    */
@@ -318,17 +396,11 @@
   private ResourceOracleSnapshot refreshAndSnapshot(TreeLogger logger,
       ResourceOracleImpl oracle) {
     oracle.refresh(logger);
-    return new ResourceOracleSnapshot(oracle);
-  }
-
-  private void testClassPathOrderIsHonored(TreeLogger logger,
-      String resourceKey, ClassPathEntry[] classPath, PathPrefix pathPrefix) {
-    PathPrefixSet pps = new PathPrefixSet();
-    pps.add(pathPrefix);
-    ResourceOracleImpl oracle = new ResourceOracleImpl(Arrays.asList(classPath));
-    oracle.setPathPrefixes(pps);
-    ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
-    s.assertPathIncluded(resourceKey, classPath[0]);
+    ResourceOracleSnapshot snapshot1 = new ResourceOracleSnapshot(oracle);
+    oracle.refresh(logger);
+    ResourceOracleSnapshot snapshot2 = new ResourceOracleSnapshot(oracle);
+    snapshot1.assertSameCollections(snapshot2);
+    return snapshot1;
   }
 
   private void testReadingResource(ClassPathEntry cpe1, ClassPathEntry cpe2)
@@ -337,7 +409,7 @@
 
     ResourceOracleImpl oracle = createResourceOracle(cpe1, cpe2);
     ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
-    s.assertCollectionsConsistent(9);
+    s.assertCollectionsConsistent(10);
     s.assertPathIncluded("com/google/gwt/user/client/Command.java", cpe1);
     s.assertPathIncluded("com/google/gwt/i18n/client/Messages.java", cpe2);
 
@@ -395,7 +467,7 @@
        * assumptions about the contents of each classpath entry.
        */
       ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
-      s.assertCollectionsConsistent(9);
+      s.assertCollectionsConsistent(10);
       s.assertPathIncluded("com/google/gwt/user/client/Command.java");
       s.assertPathIncluded("com/google/gwt/user/client/Timer.java");
       s.assertPathIncluded("com/google/gwt/user/client/ui/Widget.java");
@@ -418,7 +490,7 @@
 
       ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
       ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
-      after.assertCollectionsConsistent(9);
+      after.assertCollectionsConsistent(10);
       after.assertSameCollections(before);
     }
 
@@ -431,7 +503,7 @@
 
       ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
       ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
-      after.assertCollectionsConsistent(10);
+      after.assertCollectionsConsistent(11);
       after.assertNotSameCollections(before);
       after.assertPathIncluded("com/google/gwt/i18n/client/Constants.java");
     }
@@ -458,7 +530,7 @@
        * assumptions about the contents of each classpath entry.
        */
       ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
-      s.assertCollectionsConsistent(10);
+      s.assertCollectionsConsistent(11);
       s.assertPathIncluded("com/google/gwt/user/client/Command.java");
       s.assertPathIncluded("com/google/gwt/user/client/Timer.java");
       s.assertPathIncluded("com/google/gwt/user/client/ui/Widget.java");
@@ -481,7 +553,7 @@
 
       ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
       ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
-      after.assertCollectionsConsistent(10);
+      after.assertCollectionsConsistent(11);
       after.assertSameCollections(before);
     }
 
@@ -496,13 +568,26 @@
 
       ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
       ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
-      after.assertCollectionsConsistent(10);
+      after.assertCollectionsConsistent(11);
       after.assertNotSameCollections(before);
       after.assertPathIncluded("com/google/gwt/user/client/Window.java");
       after.assertPathNotIncluded("com/google/gwt/i18n/client/Constants.java");
     }
   }
 
+  private void testResourceInCPE(TreeLogger logger, String resourceKey,
+      ClassPathEntry expectedCPE, ClassPathEntry[] classPath,
+      PathPrefix... pathPrefixes) {
+    ResourceOracleImpl oracle = new ResourceOracleImpl(Arrays.asList(classPath));
+    PathPrefixSet pps = new PathPrefixSet();
+    for (PathPrefix pathPrefix : pathPrefixes) {
+      pps.add(pathPrefix);
+    }
+    oracle.setPathPrefixes(pps);
+    ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
+    s.assertPathIncluded(resourceKey, expectedCPE);
+  }
+
   private void testResourceModification(ClassPathEntry cpe1, ClassPathEntry cpe2) {
     TreeLogger logger = createTestTreeLogger();
 
@@ -538,7 +623,7 @@
        * isn't observed.
        */
       ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
-      before.assertCollectionsConsistent(9);
+      before.assertCollectionsConsistent(10);
 
       cpe3.updateResource("com/google/gwt/user/client/Timer.java");
 
@@ -552,7 +637,7 @@
        * is observed.
        */
       ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
-      before.assertCollectionsConsistent(9);
+      before.assertCollectionsConsistent(10);
 
       cpe0.updateResource("com/google/gwt/user/client/Command.java");
 
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar
index 5045c12..c5127c9 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar
Binary files differ
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar
index 08761bb..2e6663b 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar
Binary files differ
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/foo/client/BarClient1.txt b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/foo/client/BarClient1.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/foo/client/BarClient1.txt
@@ -0,0 +1 @@
+
diff --git a/dev/core/test/com/google/gwt/dev/shell/CheckForUpdatesTest.java b/dev/core/test/com/google/gwt/dev/shell/CheckForUpdatesTest.java
index c3255c1..dad4351 100644
--- a/dev/core/test/com/google/gwt/dev/shell/CheckForUpdatesTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/CheckForUpdatesTest.java
@@ -1,56 +1,80 @@
 package com.google.gwt.dev.shell;
 
 import junit.framework.TestCase;
+import com.google.gwt.dev.shell.CheckForUpdates.GwtVersion;
 
 public class CheckForUpdatesTest extends TestCase {
 
   /*
-   * Test method for
-   * 'com.google.gwt.dev.shell.CheckForUpdates.isServerVersionNewer(String,
-   * String)'
+   * Test GwtVersion comparisons
    */
-  public final void testIsServerVersionNewer() {
-    assertFalse(CheckForUpdates.isServerVersionNewer(null, null));
+  public final void testVersionComparison() {
+    GwtVersion v1 = new GwtVersion(null);
+    assertEquals(0, v1.compareTo(v1));
 
-    assertFalse(CheckForUpdates.isServerVersionNewer("1", "2"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("2", "1"));
+    v1 = new GwtVersion("1");
+    assertEquals(0, v1.compareTo(v1));
+    GwtVersion v2 = new GwtVersion("2");
+    assertTrue(v1.compareTo(v2) < 0);
+    assertTrue(v2.compareTo(v1) > 0);
 
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", null));
-    assertFalse(CheckForUpdates.isServerVersionNewer(null, "1.2.3"));
+    v1 = new GwtVersion("1.2.3");
+    v2 = new GwtVersion(null);
+    assertTrue(v1.compareTo(v2) > 0);
+    assertTrue(v2.compareTo(v1) < 0);
 
-    assertFalse(CheckForUpdates.isServerVersionNewer("2", "1.2.3"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "2"));
+    v1 = new GwtVersion("1.2.3");
+    v2 = new GwtVersion("2.0.0");
+    assertTrue(v1.compareTo(v2) < 0);
+    assertTrue(v2.compareTo(v1) > 0);
 
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "2.3.4.5"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3.4", "2.3.4"));
+    v1 = new GwtVersion("1.2.99");
+    v2 = new GwtVersion("2.0.0");
+    assertTrue(v1.compareTo(v2) < 0);
+    assertTrue(v2.compareTo(v1) > 0);
 
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "1.2.3"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
-      "1000.2000.3000"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("001.002.003", "1.2.3"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "001.002.003"));
+    v1 = new GwtVersion("1.2.99");
+    v2 = new GwtVersion("1.3.0");
+    assertTrue(v1.compareTo(v2) < 0);
+    assertTrue(v2.compareTo(v1) > 0);
 
-    assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "2.2.3"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("2.2.3", "1.2.3"));
+    v1 = new GwtVersion("001.002.099");
+    v2 = new GwtVersion("1.2.99");
+    assertEquals(0, v1.compareTo(v2));
 
-    assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "1.3.3"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.3.3", "1.2.3"));
-
-    assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "1.2.4"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.4", "1.2.3"));
-
-    assertTrue(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
-      "1000.2000.4000"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.4000",
-      "1000.2000.3000"));
-
-    assertTrue(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
-      "1000.2000.3001"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.3001",
-      "1000.2000.3000"));
-
-    assertTrue(CheckForUpdates.isServerVersionNewer("0.2.3", "1.1.3"));
-    assertFalse(CheckForUpdates.isServerVersionNewer("1.1.3", "0.2.3"));
+    // TODO: more tests
+//    assertFalse(CheckForUpdates.isServerVersionNewer("2", "1.2.3"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "2"));
+//
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "2.3.4.5"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3.4", "2.3.4"));
+//
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "1.2.3"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
+//      "1000.2000.3000"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("001.002.003", "1.2.3"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "001.002.003"));
+//
+//    assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "2.2.3"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("2.2.3", "1.2.3"));
+//
+//    assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "1.3.3"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1.3.3", "1.2.3"));
+//
+//    assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "1.2.4"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1.2.4", "1.2.3"));
+//
+//    assertTrue(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
+//      "1000.2000.4000"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.4000",
+//      "1000.2000.3000"));
+//
+//    assertTrue(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
+//      "1000.2000.3001"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.3001",
+//      "1000.2000.3000"));
+//
+//    assertTrue(CheckForUpdates.isServerVersionNewer("0.2.3", "1.1.3"));
+//    assertFalse(CheckForUpdates.isServerVersionNewer("1.1.3", "0.2.3"));
   }
-
 }
diff --git a/dev/core/test/com/google/gwt/dev/shell/GeneratedClassnameTest.java b/dev/core/test/com/google/gwt/dev/shell/GeneratedClassnameTest.java
index b5040c1..ecf7087 100644
--- a/dev/core/test/com/google/gwt/dev/shell/GeneratedClassnameTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/GeneratedClassnameTest.java
@@ -11,8 +11,8 @@
   public void testGeneratedClassnames() {
     String namesToAccept[] = {
         "Test$1", "Test$10", "Test$Foo$1", "Test$1$Foo", "Test$10$Foo",
-        "$$345", "Test$1$Foo$"};
-    String namesToReject[] = {"Test1", "$345", "Test$2Foo", "Test$Foo$1Bar"};
+        "$$345", "Test$1$Foo$", "Test$1Foo", "Test$2Foo", "Test$Foo$1Bar"};
+    String namesToReject[] = {"Test1", "TestFoo", "Test$Foo$Bar", "$345"};
 
     for (String name : namesToAccept) {
       assertTrue("className = " + name + " should have been accepted",
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/CheckForUpdatesMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/CheckForUpdatesMoz.java
deleted file mode 100644
index a1ba73d..0000000
--- a/dev/linux/src/com/google/gwt/dev/shell/moz/CheckForUpdatesMoz.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.dev.shell.moz;
-
-import com.google.gwt.dev.shell.CheckForUpdates;
-
-/**
- * Mozilla specific implementation of CheckForUpdates.
- */
-public class CheckForUpdatesMoz extends CheckForUpdates {
-
-  @Override
-  protected byte[] doHttpGet(String userAgent, String url) {
-    // Don't attempt to support proxies on Linux.
-    //
-    return httpGetNonNative(userAgent, url);
-  }
-}
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/CheckForUpdatesSaf.java b/dev/mac/src/com/google/gwt/dev/shell/mac/CheckForUpdatesSaf.java
deleted file mode 100644
index 34ad6e2..0000000
--- a/dev/mac/src/com/google/gwt/dev/shell/mac/CheckForUpdatesSaf.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.dev.shell.mac;
-
-import com.google.gwt.dev.shell.CheckForUpdates;
-
-/**
- * Safari specific implementation of CheckForUpdates.
- */
-public class CheckForUpdatesSaf extends CheckForUpdates {
-
-  @Override
-  protected byte[] doHttpGet(String userAgent, String url) {
-    // Don't attempt to support proxies on Linux.
-    //
-    return httpGetNonNative(userAgent, url);
-  }
-}
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/CheckForUpdatesIE6.java b/dev/windows/src/com/google/gwt/dev/shell/ie/CheckForUpdatesIE6.java
index fd71509..cdd1637 100644
--- a/dev/windows/src/com/google/gwt/dev/shell/ie/CheckForUpdatesIE6.java
+++ b/dev/windows/src/com/google/gwt/dev/shell/ie/CheckForUpdatesIE6.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.dev.shell.ie;
 
+import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.dev.shell.CheckForUpdates;
 
 /**
@@ -22,13 +23,15 @@
  */
 public class CheckForUpdatesIE6 extends CheckForUpdates {
 
-  public CheckForUpdatesIE6() {
+  public CheckForUpdatesIE6(TreeLogger logger, String entryPoint) {
+    super(logger, entryPoint);
     LowLevelIE6.init();
   }
 
   @Override
-  protected byte[] doHttpGet(String userAgent, String url) {
-    byte[] response = LowLevelIE6.httpGet(userAgent, url);
+  protected byte[] doHttpGet(TreeLogger branch, String userAgent, String url) {
+    byte[] response = LowLevelIE6.httpGet(branch, userAgent, url,
+        System.getProperty(PROPERTY_DEBUG_HTTP_GET) != null);
     return response;
   }
 
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/LowLevelIE6.java b/dev/windows/src/com/google/gwt/dev/shell/ie/LowLevelIE6.java
index 0a95c60..19b0613 100644
--- a/dev/windows/src/com/google/gwt/dev/shell/ie/LowLevelIE6.java
+++ b/dev/windows/src/com/google/gwt/dev/shell/ie/LowLevelIE6.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.dev.shell.ie;
 
+import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.dev.shell.LowLevel;
 
 /**
@@ -32,15 +33,17 @@
    * @return the bytes of the full response (including headers), or
    *         <code>null</code> if there's a problem
    */
-  public static byte[] httpGet(String userAgent, String url) {
+  public static byte[] httpGet(TreeLogger branch, String userAgent, String url,
+      boolean debugFlag) {
     init();
     byte[][] out = new byte[1][];
     int status = _httpGet(userAgent, url, out);
     if (status == 0) {
       return out[0];
     } else {
-      if (System.getProperty("gwt.debugLowLevelHttpGet") != null) {
-        System.err.println("GET failed with status " + status + " for " + url);
+      if (debugFlag) {
+        branch.log(TreeLogger.ERROR, "GET failed with status " + status
+            + " for " + url);
       }
       return null;
     }
diff --git a/distro-source/core/src/samples/build.xml b/distro-source/core/src/samples/build.xml
new file mode 100644
index 0000000..0a77f56
--- /dev/null
+++ b/distro-source/core/src/samples/build.xml
@@ -0,0 +1,30 @@
+<project name="samples" default="build" basedir=".">
+
+  <target name="-do">
+    <ant target="${target}" dir="DynaTable"/>
+    <ant target="${target}" dir="Hello"/>
+    <ant target="${target}" dir="I18N"/>
+    <ant target="${target}" dir="JSON"/>
+    <ant target="${target}" dir="Mail"/>
+    <ant target="${target}" dir="Showcase"/>
+    <ant target="${target}" dir="SimpleXML"/>
+  </target>
+
+  <target name="build" description="Build all samples">
+    <antcall target="-do">
+      <param name="target" value="build" />
+    </antcall>
+  </target>
+
+  <target name="eclipse.generate" description="Generate eclipse projects for all samples">
+    <antcall target="-do">
+      <param name="target" value="eclipse.generate" />
+    </antcall>
+  </target>
+
+  <target name="clean" description="Clean all samples">
+    <antcall target="-do">
+      <param name="target" value="clean" />
+    </antcall>
+  </target>
+</project>
diff --git a/doc/build.xml b/doc/build.xml
index 4974e02..8bfb704 100644
--- a/doc/build.xml
+++ b/doc/build.xml
@@ -10,7 +10,7 @@
   <property.ensure name="gwt.dev.jar" location="${gwt.build.lib}/gwt-dev-linux.jar" />
 
   <property name="USER_PKGS"
-          value="com.google.gwt.core.client;com.google.gwt.core.ext;com.google.gwt.core.ext.soyc;com.google.gwt.core.ext.linker;com.google.gwt.core.ext.typeinfo;com.google.gwt.dom.client;com.google.gwt.i18n.client;com.google.gwt.i18n.rebind.format;com.google.gwt.i18n.rebind.keygen;com.google.gwt.json.client;com.google.gwt.junit.client;com.google.gwt.benchmarks.client;com.google.gwt.user.client;com.google.gwt.user.client.rpc;com.google.gwt.user.client.ui;com.google.gwt.user.server.rpc;com.google.gwt.xml.client;com.google.gwt.http.client;com.google.gwt.animation.client;com.google.gwt.event.dom.client;com.google.gwt.event.logical.shared;com.google.gwt.event.shared;com.google.gwt.debug.client;com.google.gwt.user.datepicker.client" />
+          value="com.google.gwt.animation.client;com.google.gwt.benchmarks.client;com.google.gwt.core.client;com.google.gwt.core.ext;com.google.gwt.core.ext.soyc;com.google.gwt.core.ext.linker;com.google.gwt.core.ext.typeinfo;com.google.gwt.debug.client;com.google.gwt.dom.client;com.google.gwt.event.dom.client;com.google.gwt.event.logical.shared;com.google.gwt.event.shared;com.google.gwt.http.client;com.google.gwt.i18n.client;com.google.gwt.i18n.rebind.format;com.google.gwt.i18n.rebind.keygen;com.google.gwt.json.client;com.google.gwt.junit.client;com.google.gwt.benchmarks.client;com.google.gwt.user.client;com.google.gwt.user.client.rpc;com.google.gwt.user.client.ui;com.google.gwt.user.server.rpc;com.google.gwt.xml.client;com.google.gwt.user.datepicker.client"/>
   <property name="LANG_PKGS" value="java.lang;java.lang.annotation;java.util;java.io;java.sql" />
 
   <!--	Individual classes to include when we don't want to 
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/common/SimpleLogger.java b/reference/code-museum/src/com/google/gwt/museum/client/common/SimpleLogger.java
index eeba505..4642cdd 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/common/SimpleLogger.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/common/SimpleLogger.java
@@ -25,13 +25,10 @@
 import com.google.gwt.user.client.ui.VerticalPanel;
 
 /**
- * Helper class to create visual tests.
- * 
- * @param <V> value type
- * @param <T> target type
+ * Simple logging class.
  */
 @SuppressWarnings("deprecation")
-public class SimpleLogger<V, T> extends Composite {
+public class SimpleLogger extends Composite {
 
   private VerticalPanel panel = new VerticalPanel();
 
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
index e51c222..4a13b2f 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
@@ -16,6 +16,7 @@
 package com.google.gwt.museum.client.defaultmuseum;
 
 import com.google.gwt.dom.client.Element;
+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.museum.client.common.AbstractIssue;
@@ -120,15 +121,15 @@
     Event.addNativePreviewHandler(new NativePreviewHandler() {
       public void onPreviewNativeEvent(NativePreviewEvent event) {
         // Ignore events outside of the sandbox
-        Event nativeEvent = event.getNativeEvent();
+        NativeEvent nativeEvent = event.getNativeEvent();
         Element target = nativeEvent.getTarget();
         if (!sandbox.getElement().isOrHasChild(target)
             && !positioner.getElement().isOrHasChild(target)) {
           positioner.removeFromParent();
           return;
         }
-
-        switch (nativeEvent.getTypeInt()) {
+                
+        switch (Event.as(nativeEvent).getTypeInt()) {
           case Event.ONMOUSEMOVE:
             int absX = nativeEvent.getClientX() + Window.getScrollLeft();
             int absY = nativeEvent.getClientY() + Window.getScrollTop();
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForEventsFiring.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForEventsFiring.java
index 07efe27..cc82e43 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForEventsFiring.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForEventsFiring.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.museum.client.defaultmuseum;
 
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.dom.client.BlurEvent;
 import com.google.gwt.event.dom.client.BlurHandler;
 import com.google.gwt.event.dom.client.ChangeEvent;
@@ -134,7 +135,7 @@
 
     prepMouseEvents();
     prepKeyboardEvents();
-    prepSrollAndMouseWheelEvents();
+    prepScrollAndMouseWheelEvents();
     prepLoadEvents();
     prepWindowEvents();
 
@@ -213,8 +214,8 @@
    * 
    * @param event the event that was triggered
    */
-  private void passTest(Event event) {
-    passTest(event.getTypeInt());
+  private void passTest(NativeEvent event) {
+    passTest(Event.as(event).getTypeInt());
   }
 
   /**
@@ -247,7 +248,7 @@
     // Add event handlers
     textBox.addKeyDownHandler(new KeyDownHandler() {
       public void onKeyDown(KeyDownEvent event) {
-        event.isAutoRepeat();
+
         event.isAltKeyDown();
         event.isControlKeyDown();
         event.isShiftKeyDown();
@@ -332,7 +333,7 @@
 
   private void prepMouseEvents() {
     // Create a button to trigger events
-    Button button = new Button("Click me") {
+    final Button button = new Button("Click me, move over me") {
       @Override
       public void onBrowserEvent(Event event) {
         super.onBrowserEvent(event);
@@ -386,19 +387,28 @@
       public void onMouseOut(MouseOutEvent event) {
         assert event.getFromElement() != null;
         assert event.getToElement() != null;
-        passTest(event.getNativeEvent());
+        if (button.getElement().equals(event.getFromElement())
+            && button.getElement().getParentElement().equals(
+                event.getToElement())) {
+          passTest(event.getNativeEvent());
+        }
       }
     });
     button.addMouseOverHandler(new MouseOverHandler() {
       public void onMouseOver(MouseOverEvent event) {
         assert event.getFromElement() != null;
         assert event.getToElement() != null;
-        passTest(event.getNativeEvent());
+
+        if (button.getElement().equals(event.getToElement())
+            && button.getElement().getParentElement().equals(
+                event.getFromElement())) {
+          passTest(event.getNativeEvent());
+        }
       }
     });
   }
 
-  private void prepSrollAndMouseWheelEvents() {
+  private void prepScrollAndMouseWheelEvents() {
     // Create a widget to trigger events
     String scrollableMessage = "Scroll to the bottom<br>(using mouse wheel<br>"
         + "if supported)";
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
index 8a280c1..c317aa2 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
@@ -76,9 +76,11 @@
     TreeItem d = new TreeItem(new RadioButton("myradio",
         "I should line up nicely"));
     TreeItem e = new TreeItem(new CheckBox("I should line up nicely"));
+    TreeItem f = new TreeItem(new CheckBox("I should also line up nicely"));
+    f.addItem(new CheckBox("me to"));
     SimplePanel panel = new SimplePanel();
     panel.setWidget(new Label("There should not be any space above me"));
-    TreeItem f = new TreeItem(panel);
+    TreeItem g = new TreeItem(panel);
 
     tree.setSelectedItem(b);
     tree.addItem(a);
@@ -87,6 +89,7 @@
     tree.addItem(d);
     tree.addItem(e);
     tree.addItem(f);
+    tree.addItem(g);
     b.addItem(ba);
     b.addItem(bb);
     bb.addItem(bba);
diff --git a/samples/common.ant.xml b/samples/common.ant.xml
index ef167f4..248acd2 100755
--- a/samples/common.ant.xml
+++ b/samples/common.ant.xml
@@ -77,6 +77,7 @@
           <java classname="com.google.gwt.user.tools.WebAppCreator" classpath="${gwt.user.jar}:${gwt.dev.jar}" failonerror="true">
             <!-- Relative path is important! Paths will be relative in final distro -->
             <sysproperty key="gwt.devjar" value="../../gwt-dev-@{platform}.jar" />
+            <arg value="-XnoEclipse" />
             <arg value="-overwrite" />
             <arg value="-out" />
             <arg file="${samples.scripts}/@{platform}/${sample.upper}" />
diff --git a/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml b/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml
index 137a008..93ee3a3 100644
--- a/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml
+++ b/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml
@@ -13,9 +13,10 @@
 <!-- limitations under the License.                                         -->
 
 <module rename-to="dynatable">
-	<inherits name='com.google.gwt.user.User'/>
-	<entry-point class='com.google.gwt.sample.dynatable.client.DynaTable'/>
-	<servlet path='/calendar' class='com.google.gwt.sample.dynatable.server.SchoolCalendarServiceImpl'/>
+	<inherits name='com.google.gwt.user.User' />
+	<entry-point class='com.google.gwt.sample.dynatable.client.DynaTable' />
+	<!--
+		Re-enable this when we have web.xml validation.
+		<servlet path='/calendar' class='com.google.gwt.sample.dynatable.server.SchoolCalendarServiceImpl'/>
+	-->
 </module>
-
-
diff --git a/samples/dynatable/src/com/google/gwt/sample/dynatable/client/DayFilterWidget.java b/samples/dynatable/src/com/google/gwt/sample/dynatable/client/DayFilterWidget.java
index 674d739..efbf4e5 100644
--- a/samples/dynatable/src/com/google/gwt/sample/dynatable/client/DayFilterWidget.java
+++ b/samples/dynatable/src/com/google/gwt/sample/dynatable/client/DayFilterWidget.java
@@ -44,7 +44,7 @@
       addClickHandler(dayCheckBoxHandler);
 
       // Initialize based on the calendar's current value.
-      setChecked(calendar.getDayIncluded(day));
+      setValue(calendar.getDayIncluded(day));
     }
   }
 
@@ -52,9 +52,9 @@
     public void onClick(ClickEvent event) {
       onClick((DayCheckBox) event.getSource());
     }
-    
+
     public void onClick(DayCheckBox dayCheckBox) {
-      calendar.setDayIncluded(dayCheckBox.day, dayCheckBox.isChecked());
+      calendar.setDayIncluded(dayCheckBox.day, dayCheckBox.getValue());
     }
   }
 
@@ -102,7 +102,7 @@
     for (int i = 0, n = outer.getWidgetCount(); i < n; ++i) {
       Widget w = outer.getWidget(i);
       if (w instanceof DayCheckBox) {
-        ((DayCheckBox) w).setChecked(checked);
+        ((DayCheckBox) w).setValue(checked);
         dayCheckBoxHandler.onClick((DayCheckBox) w);
       }
     }
diff --git a/samples/dynatable/war/DynaTable.css b/samples/dynatable/war/DynaTable.css
index ab81abf..038e964 100644
--- a/samples/dynatable/war/DynaTable.css
+++ b/samples/dynatable/war/DynaTable.css
@@ -43,15 +43,15 @@
 }
 
 .DynaTable-DynaTableWidget .table td.name {
-	width: 10em;
+	width: 20%;
 }
 
 .DynaTable-DynaTableWidget .table td.desc {
-	width: 20em;
+	width: 30%;
 }
 
 .DynaTable-DynaTableWidget .table td.sched {
-	width: 20em;
+	width: 50%;
 }
 
 .DynaTable-DynaTableWidget .table td {
diff --git a/samples/i18n/src/com/google/gwt/sample/i18n/client/AbstractFormatExampleConstants_fr.properties b/samples/i18n/src/com/google/gwt/sample/i18n/client/AbstractFormatExampleConstants_fr.properties
index 0149b32..efd7ffb 100644
--- a/samples/i18n/src/com/google/gwt/sample/i18n/client/AbstractFormatExampleConstants_fr.properties
+++ b/samples/i18n/src/com/google/gwt/sample/i18n/client/AbstractFormatExampleConstants_fr.properties
@@ -14,7 +14,7 @@
 # the License.
 # 
 
-inputValue = Valeur a composer
+inputValue = Valeur à composer
 formattedOutput = Valeur composée
 pattern = Format
 invalidPattern = Format invalide
diff --git a/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsExampleConstants_fr.properties b/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsExampleConstants_fr.properties
index 9c060ad..9bb9b45 100644
--- a/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsExampleConstants_fr.properties
+++ b/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsExampleConstants_fr.properties
@@ -16,7 +16,7 @@
 
 firstName = Prénom
 lastName = Nom 
-favoriteColor = Coleur préférée
+favoriteColor = Couleur préférée
 
 black = Noir
 blue = Bleu
diff --git a/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsWithLookupExampleConstants_fr.properties b/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsWithLookupExampleConstants_fr.properties
index 96aa502..26f8d23 100644
--- a/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsWithLookupExampleConstants_fr.properties
+++ b/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsWithLookupExampleConstants_fr.properties
@@ -15,6 +15,6 @@
 # 
 
 input = Nom de méthode
-noInputResult = <Veuillez écrire un nom de méthode ci-dessus> 
+noInputResult = <Veuillez tapez un des noms de méthodes ci-dessus> 
 noMatchingResult = <Non trouvé>
 result = Resultat de cherche 
diff --git a/samples/i18n/war/I18N.css b/samples/i18n/war/I18N.css
index d8d8033..09e2029 100644
--- a/samples/i18n/war/I18N.css
+++ b/samples/i18n/war/I18N.css
@@ -133,7 +133,7 @@
 }
 
 .col2 {
-  width: 20em;
+  width: 32em;
 }
 
 .col2 * {
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java b/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
index 92f8330..43fa86a 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
@@ -21,6 +21,7 @@
 import com.google.gwt.user.client.ui.FlexTable;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.HTMLTable.Cell;
 
 /**
  * A composite that displays a list of emails that can be selected.
@@ -91,9 +92,12 @@
       }
     } else if (sender == table) {
       // Select the row that was clicked (-1 to account for header row).
-      int row = table.getCellForEvent(event).getRowIndex();
-      if (row > 0) {
-        selectRow(row - 1);
+      Cell cell = table.getCellForEvent(event);
+      if (cell != null) {
+        int row = cell.getRowIndex();
+        if (row > 0) {
+          selectRow(row - 1);
+        }
       }
     }
   }
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/Application.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/Application.java
index 2791dcc..27a7b0a 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/Application.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/Application.java
@@ -62,8 +62,7 @@
  * 
  * <li>.Application-menu { The main menu }</li>
  * 
- * <li>.Application-content-wrapper { The scrollable element around the content
- * }</li>
+ * <li>.Application-content-wrapper { The scrollable element around the content }</li>
  * 
  * </ul>
  */
@@ -293,8 +292,8 @@
 
   protected void onWindowResizedImpl(int width) {
     int menuWidth = mainMenu.getOffsetWidth();
-    int contentWidth = width - menuWidth - 30;
-    int contentWidthInner = contentWidth - 10;
+    int contentWidth = Math.max(width - menuWidth - 30, 1);
+    int contentWidthInner = Math.max(contentWidth - 10, 1);
     bottomPanel.setCellWidth(mainMenu, menuWidth + "px");
     bottomPanel.setCellWidth(contentDecorator, contentWidth + "px");
     contentLayout.getCellFormatter().setWidth(0, 0, contentWidthInner + "px");
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
index a4378e3..ee1f6a2 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.sample.showcase.client;
 
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.logical.shared.SelectionEvent;
 import com.google.gwt.event.logical.shared.SelectionHandler;
 import com.google.gwt.http.client.Request;
@@ -323,7 +324,7 @@
   /**
    * Load the contents of a remote file into the specified widget.
    * 
-   * @param url the URL of the file relative to the source directory in public
+   * @param url a partial path relative to the module base URL
    * @param target the target Widget to place the contents
    * @param callback the callback when the call completes
    */
@@ -331,14 +332,16 @@
       final RequestCallback callback) {
     // Show the loading image
     if (loadingImage == null) {
-      loadingImage = "<img src=\"images/loading.gif\">";
+      loadingImage = "<img src=\"" + GWT.getModuleBaseURL()
+          + "images/loading.gif\">";
     }
     target.setDirection(HasDirection.Direction.LTR);
     DOM.setStyleAttribute(target.getElement(), "textAlign", "left");
     target.setHTML("&nbsp;&nbsp;" + loadingImage);
 
     // Request the contents of the file
-    RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
+    RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
+        GWT.getModuleBaseURL() + url);
     RequestCallback realCallback = new RequestCallback() {
       public void onError(Request request, Throwable exception) {
         target.setHTML("Cannot find resource");
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
index 5d586d7..9829e3e 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
@@ -125,6 +125,7 @@
     // Add a text area
     TextArea textArea = new TextArea();
     textArea.ensureDebugId("cwBasicText-textarea");
+    textArea.setVisibleLines(5);
     vpanel.add(new HTML("<br><br>" + constants.cwBasicTextAreaLabel()));
     vpanel.add(createTextExample(textArea, true));
 
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
index 2a9abfe..2ed3d5a 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
@@ -94,6 +94,7 @@
     vPanel.add(getHyperlink(CwCustomButton.class,
         allConstants.cwCustomButtonName()));
     vPanel.add(getHyperlink(CwFileUpload.class, allConstants.cwFileUploadName()));
+    vPanel.add(getHyperlink(CwDatePicker.class, allConstants.cwDatePickerName()));
 
     // Return the panel
     return vPanel;
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
index dd5f1b8..c59aa79 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
@@ -111,7 +111,7 @@
       radioButton.ensureDebugId("cwRadioButton-sport-"
           + sport.replaceAll(" ", ""));
       if (i == 2) {
-        radioButton.setChecked(true);
+        radioButton.setValue(true);
       }
       vPanel.add(radioButton);
     }
diff --git a/tools/api-checker/config/gwt15_16userApi.conf b/tools/api-checker/config/gwt15_16userApi.conf
index 020f74a..922379c 100644
--- a/tools/api-checker/config/gwt15_16userApi.conf
+++ b/tools/api-checker/config/gwt15_16userApi.conf
@@ -98,6 +98,5 @@
 # to be hard. Come back and fix this issue, if more such cases come up. 
 java.lang.StringBuilder::append(Ljava/lang/StringBuffer;) OVERRIDABLE_METHOD_ARGUMENT_TYPE_CHANGE
 com.google.gwt.user.client.ui.Button::Button(Ljava/lang/String;Lcom/google/gwt/user/client/ui/ClickListener;) OVERLOADED_METHOD_CALL
-com.google.gwt.user.client.ui.MultiWordSuggestOracle::addAll(Ljava/util/Collection;) FINAL_ADDED
 com.google.gwt.user.client.ui.ToggleButton::ToggleButton(Lcom/google/gwt/user/client/ui/Image;Lcom/google/gwt/user/client/ui/Image;Lcom/google/gwt/user/client/ui/ClickListener;) OVERLOADED_METHOD_CALL 
 com.google.gwt.user.client.ui.Tree::setImageBase(Ljava/lang/String;) MISSING
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClass.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClass.java
index 4e04f5d..616a3f0 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClass.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClass.java
@@ -225,8 +225,7 @@
     JField fields[] = getAccessibleFields();
     for (JField field : fields) {
       if (isApiMember(field)) {
-        apiFields.put(ApiField.computeApiSignature(field), new ApiField(field,
-            this));
+        apiFields.put(field.getName(), new ApiField(field, this));
       } else {
         notAddedFields.add(field.toString());
       }
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClassDiffGenerator.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClassDiffGenerator.java
index 9a2c5b1..59a65df 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClassDiffGenerator.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClassDiffGenerator.java
@@ -190,21 +190,57 @@
     return collection;
   }
 
-  private boolean isIncompatibileDueToMethodOverloading(
+  /**
+   * Attempts to find out if a methodName(null) call previously succeeded, and
+   * would fail with the new Api. Currently, this method is simple.
+   * TODO(amitmanjhi): generalize this method.
+   * 
+   * @param methodsInNew Candidate methods in the new Api
+   * @param methodsInExisting Candidate methods in the existing Api.
+   * @return the possible incompatibilities due to method overloading.
+   */
+  private Map<ApiAbstractMethod, ApiChange> getOverloadedMethodIncompatibility(
       Set<ApiAbstractMethod> methodsInNew,
       Set<ApiAbstractMethod> methodsInExisting) {
     if (!ApiCompatibilityChecker.API_SOURCE_COMPATIBILITY
         || methodsInExisting.size() != 1 || methodsInNew.size() <= 1) {
-      return false;
+      return Collections.emptyMap();
     }
-    String signature = methodsInExisting.toArray(new ApiAbstractMethod[0])[0].getCoarseSignature();
-    int numMatchingSignature = 0;
+    ApiAbstractMethod existingMethod = methodsInExisting.toArray(new ApiAbstractMethod[0])[0];
+    String signature = existingMethod.getCoarseSignature();
+    List<ApiAbstractMethod> matchingMethods = new ArrayList<ApiAbstractMethod>();
     for (ApiAbstractMethod current : methodsInNew) {
       if (current.getCoarseSignature().equals(signature)) {
-        ++numMatchingSignature;
+        matchingMethods.add(current);
       }
     }
-    return numMatchingSignature > 1;
+    if (isPairwiseCompatible(matchingMethods)) {
+      return Collections.emptyMap();
+    }
+    Map<ApiAbstractMethod, ApiChange> incompatibilities = new HashMap<ApiAbstractMethod, ApiChange>();
+    incompatibilities.put(existingMethod, new ApiChange(existingMethod,
+        ApiChange.Status.OVERLOADED_METHOD_CALL,
+        "Many methods in the new API with similar signatures. Methods = "
+            + methodsInNew + " This might break API source compatibility"));
+    return incompatibilities;
+  }
+
+  /**
+   * @return true if each pair of methods within the list is compatibile.
+   */
+  private boolean isPairwiseCompatible(List<ApiAbstractMethod> methods) {
+    int length = methods.size();
+    for (int i = 0; i < length - 1; i++) {
+      for (int j = i + 1; j < length; j++) {
+        ApiAbstractMethod firstMethod = methods.get(i);
+        ApiAbstractMethod secondMethod = methods.get(j);
+        if (!firstMethod.isCompatible(secondMethod)
+            && !secondMethod.isCompatible(firstMethod)) {
+          return false;
+        }
+      }
+    }
+    return true;
   }
 
   /**
@@ -230,12 +266,11 @@
           elementName, methodType);
       onlyInNew.addAll(methodsInNew);
       onlyInExisting.addAll(methodsInExisting);
-      if (isIncompatibileDueToMethodOverloading(methodsInNew, methodsInExisting)) {
-        ApiAbstractMethod methodInExisting = methodsInExisting.toArray(new ApiAbstractMethod[0])[0];
-        addProperty(intersectingElements, methodInExisting, new ApiChange(
-            methodInExisting, ApiChange.Status.OVERLOADED_METHOD_CALL,
-            "Many methods in the new API with similar signatures. Methods = "
-                + methodsInNew + " This might break API source compatibility"));
+      Map<ApiAbstractMethod, ApiChange> incompatibilityMap = getOverloadedMethodIncompatibility(
+          methodsInNew, methodsInExisting);
+      for (ApiAbstractMethod existingMethod : incompatibilityMap.keySet()) {
+        addProperty(intersectingElements, existingMethod,
+            incompatibilityMap.get(existingMethod));
       }
 
       /*
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiMethod.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiMethod.java
index d911d3a..1667a2d 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiMethod.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiMethod.java
@@ -175,7 +175,8 @@
           + getApiSignature());
     }
     List<ApiChange.Status> statuses = new ArrayList<ApiChange.Status>();
-    if (!oldjmethod.isFinal() && newjmethod.isFinal()) {
+    if (!oldjmethod.isFinal() && !apiClass.getClassObject().isFinal()
+        && newjmethod.isFinal()) {
       statuses.add(ApiChange.Status.FINAL_ADDED);
     }
     if (!oldjmethod.isAbstract() && newjmethod.isAbstract()) {
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
index 54117a9..5a2357e 100644
--- a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
@@ -38,6 +38,10 @@
  * to both ApiClass, apiMethods.
  * 
  * test white-list support.
+ * 
+ * TODO(amitmanjhi): (1) Re-factor this code as much as possible into smaller
+ * separate components similar to the ApiCompatibilityUnit class. (2) Use
+ * MockApiElement instead of String comparisons.
  */
 public class ApiCompatibilityTest extends TestCase {
 
@@ -76,8 +80,8 @@
     StringBuffer sb = new StringBuffer();
     sb.append("package test.apicontainer;\n");
     sb.append("class NonApiClass extends java.lang.Object {\n");
-    sb.append("\tpublic void methodInNonApiClass(java.lang.Object o) { };\n");
-    sb.append("\tpublic void methodInNonApiClass(test.apicontainer.NonApiClass t) { };\n");
+    sb.append("\tpublic void methodInNonApiClass(ApiClassInNonApiClass o) { };\n");
+    sb.append("\tpublic void methodInNonApiClass(NonApiClass t) { };\n");
     sb.append("\tpublic int fieldInNonApiClass = 3;\n");
     sb.append("\tprotected abstract class ApiClassInNonApiClass {\n");
     sb.append("\tprotected ApiClassInNonApiClass() { }\n");
@@ -246,7 +250,7 @@
     assertEquals(2, countPresence(finalMethodSignature, strWithoutDuplicates));
 
     // test method_overloading
-    finalMethodSignature = "methodInNonApiClass(Ljava/lang/Object;)";
+    finalMethodSignature = "methodInNonApiClass(Ltest/apicontainer/NonApiClass;)";
     assertEquals(1, countPresence(finalMethodSignature + delimiter
         + ApiChange.Status.OVERLOADED_METHOD_CALL, strWithoutDuplicates));
 
@@ -264,9 +268,6 @@
           strWithoutDuplicates));
     }
 
-    assertEquals(1, countPresence(methodSignature + delimiter
-        + ApiChange.Status.OVERLOADED_METHOD_CALL, strWithoutDuplicates));
-
     // the method should be satisfied by the method in the super-class
     methodSignature = "test.apicontainer.OneMoreApiClass::checkOverloadedMethodAccounted(Ltest/apicontainer/OneMoreApiClass;)";
     assertEquals(0, countPresence(methodSignature + delimiter
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityUnitTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityUnitTest.java
new file mode 100644
index 0000000..073b3ae
--- /dev/null
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityUnitTest.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2008 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.tools.apichecker;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.util.log.AbstractTreeLogger;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.tools.apichecker.ApiCompatibilityChecker.StaticCompilationUnit;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Base class for all the ApiCompatibility Testing. Encapsulates two api
+ * containers and a test method.
+ * 
+ */
+public class ApiCompatibilityUnitTest extends TestCase {
+
+  /**
+   * Mock class to test if the correct ApiChange(s) are being returned.
+   * 
+   */
+  static class MockApiElement implements ApiElement {
+
+    final String signature;
+
+    public MockApiElement(String signature) {
+      this.signature = signature;
+    }
+
+    public String getRelativeSignature() {
+      return signature;
+    }
+  }
+
+  private static class FinalKeywordRefactoring {
+    private static String getFirstApiSourceForObject() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("package java.lang;\n");
+      sb.append("public final class Object {\n");
+      sb.append("\tpublic Object foo;\n");
+      sb.append("\tpublic void bar() {}\n");
+      sb.append("}\n");
+      return sb.toString();
+    }
+
+    private static String getSecondApiSourceForObject() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("package java.lang;\n");
+      sb.append("public class Object {\n");
+      sb.append("\tpublic final Object foo;\n");
+      sb.append("\tpublic final void bar() {}\n");
+      sb.append("}\n");
+      return sb.toString();
+    }
+
+    void testBothWays() throws NotFoundException, UnableToCompleteException {
+      Map<String, String> firstApi = new HashMap<String, String>();
+      firstApi.put("java.lang.Object", getFirstApiSourceForObject());
+      Map<String, String> secondApi = new HashMap<String, String>();
+      secondApi.put("java.lang.Object", getSecondApiSourceForObject());
+
+      // firstApi is the reference Api
+      Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
+      assertEquals(Arrays.asList(new ApiChange[] {new ApiChange(
+          new MockApiElement("java.lang.Object::foo"),
+          ApiChange.Status.FINAL_ADDED),}), apiChanges);
+
+      // secondApi is the reference Api
+      apiChanges = getApiChanges(secondApi, firstApi);
+      assertEquals(
+          Arrays.asList(new ApiChange[] {new ApiChange(new MockApiElement(
+              "java.lang.Object"), ApiChange.Status.FINAL_ADDED),}), apiChanges);
+    }
+  }
+
+  /**
+   * Test when method overloading results in Api incompatibilities.
+   * <p>
+   * Imagine a class Foo had a method foo(String ..). If in the new Api, a
+   * method foo(Integer ..) is added, ApiChecker should output a
+   * OVERLOADED_METHOD_CALL Api change (because foo(null) cannot be compiled).
+   * However, if foo(Object ..) is added, it should be okay since JLS matches
+   * from the most specific to the least specific.
+   */
+  private static class OverloadedMethodRefactoring {
+    private static String getFirstApiSourceForObject() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("package java.lang;\n");
+      sb.append("public class Object {\n");
+      sb.append("\tstatic class Foo extends java.lang.Object {\n");
+      sb.append("\t}\n");
+      sb.append("\tstatic class Bar extends java.lang.Object {\n");
+      sb.append("\t}\n");
+      sb.append("\tpublic void fooObject(Foo x){}\n");
+      sb.append("\tpublic void fooBar(Foo y){}\n");
+      sb.append("}\n");
+      return sb.toString();
+    }
+
+    private static String getSecondApiSourceForObject() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("package java.lang;\n");
+      sb.append("public class Object {\n");
+      sb.append("\tstatic class Foo extends java.lang.Object {\n");
+      sb.append("\t}\n");
+      sb.append("\tstatic class Bar extends java.lang.Object {\n");
+      sb.append("\t}\n");
+      sb.append("\tpublic void fooObject(Foo x){}\n");
+      sb.append("\tpublic void fooObject(Object x){}\n");
+      sb.append("\tpublic void fooBar(Foo y){}\n");
+      sb.append("\tpublic void fooBar(Bar y){}\n");
+      sb.append("}\n");
+      return sb.toString();
+    }
+
+    void testBothWays() throws NotFoundException, UnableToCompleteException {
+      Map<String, String> firstApi = new HashMap<String, String>();
+      firstApi.put("java.lang.Object", getFirstApiSourceForObject());
+      Map<String, String> secondApi = new HashMap<String, String>();
+      secondApi.put("java.lang.Object", getSecondApiSourceForObject());
+
+      // firstApi is the reference Api
+      Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
+      assertEquals(
+          Arrays.asList(new ApiChange[] {new ApiChange(new MockApiElement(
+              "java.lang.Object::fooBar(Ljava/lang/Object$Foo;)"),
+              ApiChange.Status.OVERLOADED_METHOD_CALL),}), apiChanges);
+
+      // secondApi is the reference Api
+      apiChanges = getApiChanges(secondApi, firstApi);
+      assertEquals(Arrays.asList(new ApiChange[] {
+          new ApiChange(new MockApiElement(
+              "java.lang.Object::fooBar(Ljava/lang/Object$Bar;)"),
+              ApiChange.Status.MISSING),
+          new ApiChange(new MockApiElement(
+              "java.lang.Object::fooObject(Ljava/lang/Object;)"),
+              ApiChange.Status.MISSING),}), apiChanges);
+    }
+  }
+
+  /**
+   * Test whether the ApiChecker correctly identifies moving fields and methods
+   * to a super class.
+   * 
+   */
+  private static class SuperClassRefactoring {
+    private static String getFirstApiSourceForObject() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("package java.lang;\n");
+      sb.append("public class Object {\n");
+      sb.append("\t\tpublic static void staticMethod(){}\n");
+      sb.append("\t\tpublic static int staticField = 1;\n");
+      sb.append("\t\tpublic int instanceField = 2;\n");
+      sb.append("\tpublic static class Foo extends java.lang.Object {\n");
+      sb.append("\t}\n");
+      sb.append("}\n");
+      return sb.toString();
+    }
+
+    private static String getSecondApiSourceForObject() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("package java.lang;\n");
+      sb.append("public class Object {\n");
+      sb.append("\tpublic static class Foo extends java.lang.Object {\n");
+      sb.append("\t\tpublic static void staticMethod(){}\n");
+      sb.append("\t\tpublic static int staticField = 1;\n");
+      sb.append("\t\tpublic int instanceField = 2;\n");
+      sb.append("\t}\n");
+      sb.append("}\n");
+      return sb.toString();
+    }
+
+    void testBothWays() throws NotFoundException, UnableToCompleteException {
+      Map<String, String> firstApi = new HashMap<String, String>();
+      firstApi.put("java.lang.Object", getFirstApiSourceForObject());
+      Map<String, String> secondApi = new HashMap<String, String>();
+      secondApi.put("java.lang.Object", getSecondApiSourceForObject());
+
+      // firstApi is the reference Api
+      Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
+      assertEquals(Arrays.asList(new ApiChange[] {
+          new ApiChange(new MockApiElement("java.lang.Object::instanceField"),
+              ApiChange.Status.MISSING),
+          new ApiChange(new MockApiElement("java.lang.Object::staticField"),
+              ApiChange.Status.MISSING),
+          new ApiChange(new MockApiElement("java.lang.Object::staticMethod()"),
+              ApiChange.Status.MISSING),}), apiChanges);
+
+      // secondApi is the reference Api
+      apiChanges = getApiChanges(secondApi, firstApi);
+      assertEquals(0, apiChanges.size());
+    }
+  }
+
+  /**
+   * Assert that two ApiChanges are equal.
+   */
+  static void assertEquals(ApiChange apiChange1, ApiChange apiChange2) {
+    assert apiChange1 != null;
+    assert apiChange2 != null;
+    assertEquals(apiChange1.getStatus(), apiChange2.getStatus());
+    assertEquals(apiChange1.getApiElement().getRelativeSignature(),
+        apiChange2.getApiElement().getRelativeSignature());
+  }
+
+  /**
+   * Assert that two sets of ApiChanges are equal.
+   */
+  static void assertEquals(Collection<ApiChange> collection1,
+      Collection<ApiChange> collection2) {
+    assertEquals(collection1.size(), collection2.size());
+
+    List<ApiChange> list1 = new ArrayList<ApiChange>();
+    list1.addAll(collection1);
+    Collections.sort(list1);
+
+    List<ApiChange> list2 = new ArrayList<ApiChange>();
+    list2.addAll(collection2);
+    Collections.sort(list2);
+
+    for (int i = 0; i < list1.size(); i++) {
+      assertEquals(list1.get(i), list2.get(i));
+    }
+  }
+
+  /**
+   * Returns the apiChanges from moving to an existing api to a new Api.
+   * 
+   * @param existingTypesToSourcesMap existing Api
+   * @param newTypesToSourcesMap new Api
+   * @return A collection of ApiChange
+   */
+  static Collection<ApiChange> getApiChanges(
+      Map<String, String> existingTypesToSourcesMap,
+      Map<String, String> newTypesToSourcesMap)
+      throws UnableToCompleteException, NotFoundException {
+
+    AbstractTreeLogger logger = new PrintWriterTreeLogger();
+    logger.setMaxDetail(TreeLogger.ERROR);
+
+    Set<CompilationUnit> set1 = new HashSet<CompilationUnit>();
+    for (String type : existingTypesToSourcesMap.keySet()) {
+      set1.add(new StaticCompilationUnit(type,
+          existingTypesToSourcesMap.get(type)));
+    }
+    Set<String> emptyList = Collections.emptySet();
+    Set<CompilationUnit> set2 = new HashSet<CompilationUnit>();
+    for (String type : existingTypesToSourcesMap.keySet()) {
+      set2.add(new StaticCompilationUnit(type, newTypesToSourcesMap.get(type)));
+    }
+
+    ApiContainer existingApi = new ApiContainer("existingApi", set1, emptyList,
+        logger);
+    ApiContainer newApi = new ApiContainer("newApi", set2, emptyList, logger);
+    return ApiCompatibilityChecker.getApiDiff(newApi, existingApi, emptyList);
+  }
+
+  public void testFinalKeywordRefactoring() throws NotFoundException,
+      UnableToCompleteException {
+    new FinalKeywordRefactoring().testBothWays();
+  }
+
+  public void testMethodOverloading() throws NotFoundException,
+      UnableToCompleteException {
+    new OverloadedMethodRefactoring().testBothWays();
+  }
+
+  public void testSuperClassRefactoring() throws NotFoundException,
+      UnableToCompleteException {
+    new SuperClassRefactoring().testBothWays();
+  }
+
+}
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
index 90deed9..f21a63b 100644
--- a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
@@ -95,7 +95,7 @@
     StringBuffer sb = new StringBuffer();
     sb.append("package test.apicontainer;\n");
     sb.append("class NonApiClass extends java.lang.Object {\n");
-    sb.append("\tpublic void methodInNonApiClass(java.lang.Object a) { };\n");
+    sb.append("\tpublic void methodInNonApiClass(NonApiClass a) { };\n");
     sb.append("\tpublic int fieldInNonApiClass = 3;\n");
     sb.append("\tprotected class ApiClassInNonApiClass {\n");
     sb.append("\tprotected ApiClassInNonApiClass() { }\n");
diff --git a/user/build.xml b/user/build.xml
index 31fe611..f18d8f7 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -12,6 +12,11 @@
 
   <fileset id="default.emma.tests" dir="${javac.junit.out}" 
        includes="**/EmmaClassLoadingTest.class" />
+  
+  <fileset id="default.hosted.emma.tests" dir="${javac.junit.out}" 
+      excludes="**/CoverageTest.class" includes="**/*Test.class" />
+  <!-- everything succeeds except CoverageTest.java. It fails due to a javac bug in sun/OpenJDK's Java. See the file contents for details -->
+  
   <!--
     Default web mode test cases
   -->
@@ -96,6 +101,15 @@
     </gwt.junit>
   </target>
 
+  <target name="test.hosted.emma" depends="compile, compile.tests" description="Run all hosted-mode tests in emma mode.">
+    <gwt.junit test.args="${test.args}" test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.emma.tests" >
+      <extraclasspaths>
+        <pathelement location="${gwt.build}/out/dev/core/bin-test" />
+        <pathelement location="${gwt.tools.redist}/emma/emma.jar" />
+      </extraclasspaths>
+    </gwt.junit>
+  </target>
+
   <target name="test.hosted" depends="compile, compile.tests" description="Run only hosted-mode tests for this project.">
     <gwt.junit test.args="${test.args}" test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.tests" >
       <extraclasspaths>
@@ -107,7 +121,7 @@
         <pathelement location="${gwt.build}/out/dev/core/bin-test" />
         <pathelement location="${gwt.tools.redist}/emma/emma.jar" />
       </extraclasspaths>
-    </gwt.junit>
+    </gwt.junit> 
   </target>
 
   <target name="test.web" depends="compile, compile.tests" description="Run only web-mode tests for this project.">
@@ -150,5 +164,7 @@
     <delete dir="${project.build}" />
     <delete file="${project.lib}" />
   </target>
-
+  <target name="presubmit" depends="test, checkstyle" description="runs the gwt api checker, user checkstyle, and user tests">
+   <gwt.ant dir=".." target="apicheck-nobuild"/>
+  </target>
 </project>
diff --git a/user/src/com/google/gwt/dom/client/ButtonElement.java b/user/src/com/google/gwt/dom/client/ButtonElement.java
index 5823486..f5eb93a 100644
--- a/user/src/com/google/gwt/dom/client/ButtonElement.java
+++ b/user/src/com/google/gwt/dom/client/ButtonElement.java
@@ -40,9 +40,9 @@
   /**
    * Simulate a mouse-click.
    */
-  public final native void click() /*-{
-    this.click();
-  }-*/;
+  public final void click() {
+    DOMImpl.impl.buttonClick(this);
+  }
 
   /**
    * A single character access key to give access to the form control.
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java
index c4a10d1..738849d 100644
--- a/user/src/com/google/gwt/dom/client/DOMImpl.java
+++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -21,10 +21,17 @@
 
   static final DOMImpl impl = GWT.create(DOMImpl.class);
 
+  public native void buttonClick(ButtonElement button) /*-{
+    button.click();
+  }-*/;
+
   public native Element createElement(String tag) /*-{
     return $doc.createElement(tag);
   }-*/;
 
+  public abstract NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable);
+
   public native InputElement createInputElement(String type) /*-{
     var e = $doc.createElement("INPUT");
     e.type = type;
@@ -33,6 +40,15 @@
 
   public abstract InputElement createInputRadioElement(String name);
 
+  public abstract NativeEvent createKeyEvent(Document doc, String type,
+      boolean canBubble, boolean cancelable, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int keyCode, int charCode);
+
+  public abstract NativeEvent createMouseEvent(Document doc, String type,
+      boolean canBubble, boolean cancelable, int detail, int screenX,
+      int screenY, int clientX, int clientY, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int button, Element relatedTarget);
+
   public ScriptElement createScriptElement(String source) {
     ScriptElement elem = (ScriptElement) createElement("script");
     elem.setText(source);
@@ -47,6 +63,73 @@
     return select;
   }
 
+  public abstract void dispatchEvent(Element target, NativeEvent evt);
+
+  public native boolean eventGetAltKey(NativeEvent evt) /*-{
+    return !!evt.altKey;
+  }-*/;
+
+  public native int eventGetButton(NativeEvent evt) /*-{
+    return evt.button || 0;
+  }-*/;
+
+  public native int eventGetClientX(NativeEvent evt) /*-{
+    return evt.clientX || 0;
+  }-*/;
+
+  public native int eventGetClientY(NativeEvent evt) /*-{
+    return evt.clientY || 0;
+  }-*/;
+
+  public native boolean eventGetCtrlKey(NativeEvent evt) /*-{
+    return !!evt.ctrlKey;
+  }-*/;
+
+  public final native int eventGetKeyCode(NativeEvent evt) /*-{
+    // 'which' gives the right key value, except when it doesn't -- in which
+    // case, keyCode gives the right value on all browsers.
+    // If all else fails, return an error code
+    return evt.which || evt.keyCode || 0;
+  }-*/;
+
+  public native boolean eventGetMetaKey(NativeEvent evt) /*-{
+    return !!evt.metaKey;
+  }-*/;
+
+  public abstract int eventGetMouseWheelVelocityY(NativeEvent evt);
+
+  public abstract Element eventGetRelatedTarget(NativeEvent nativeEvent);
+
+  public native int eventGetScreenX(NativeEvent evt) /*-{
+    return evt.screenX || 0;
+  }-*/;
+
+  public native int eventGetScreenY(NativeEvent evt) /*-{
+    return evt.screenY || 0;
+  }-*/;
+
+  public native boolean eventGetShiftKey(NativeEvent evt) /*-{
+    return !!evt.shiftKey;
+  }-*/;
+
+  public abstract Element eventGetTarget(NativeEvent evt);
+
+  public final native String eventGetType(NativeEvent evt) /*-{
+    return evt.type;
+  }-*/;
+
+  public abstract void eventPreventDefault(NativeEvent evt);
+
+  public native void eventSetKeyCode(NativeEvent evt, char key) /*-{
+    evt.keyCode = key;
+  }-*/;
+
+  public native void eventStopPropagation(NativeEvent evt) /*-{
+    evt.stopPropagation();
+  }-*/;
+
+  public abstract String eventToString(NativeEvent evt);
+
   public native int getAbsoluteLeft(Element elem) /*-{
     var left = 0;
     var curr = elem;
diff --git a/user/src/com/google/gwt/dom/client/DOMImplIE6.java b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
index ba1dfaa..fa32bdb 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplIE6.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
@@ -22,8 +22,65 @@
 class DOMImplIE6 extends DOMImpl {
 
   @Override
+  public native NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable) /*-{
+    // NOTE: IE doesn't support changing bubbling and canceling behavior (this
+    // is documented publicly in Document.createHtmlEvent()).
+    var evt = doc.createEventObject();
+    evt.type = type;
+    return evt;
+  }-*/;
+
+  @Override
   public native InputElement createInputRadioElement(String name) /*-{
     return $doc.createElement("<INPUT type='RADIO' name='" + name + "'>");
+  }-*/; 
+
+  @Override
+  public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+      boolean metaKey, int keyCode, int charCode) /*-{
+    // NOTE: IE doesn't support changing bubbling and canceling behavior (this
+    // is documented publicly in Document.createKeyEvent()).
+    var evt = doc.createEventObject();
+    evt.type = type;
+    evt.ctrlKey = ctrlKey;
+    evt.altKey = altKey;
+    evt.shiftKey = shiftKey;
+    evt.metaKey = metaKey;
+    evt.keyCode = keyCode;
+    evt.charCode = charCode;
+
+    return evt;
+  }-*/;
+
+  @Override
+  public native NativeEvent createMouseEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable, int detail, int screenX, int screenY, int clientX,
+      int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey,
+      boolean metaKey, int button, Element relatedTarget) /*-{
+    // NOTE: IE doesn't support changing bubbling and canceling behavior (this
+    // is documented publicly in Document.createMouseEvent()).
+    var evt = doc.createEventObject();
+    evt.type = type;
+    evt.detail = detail;
+    evt.screenX = screenX;
+    evt.screenY = screenY;
+    evt.clientX = clientX;
+    evt.clientY = clientY;
+    evt.ctrlKey = ctrlKey;
+    evt.altKey = altKey;
+    evt.shiftKey = shiftKey;
+    evt.metaKey = metaKey;
+    evt.button = button;
+
+    // It would make sense to set evt.[fromElement | toElement] here, because
+    // that's what IE uses. However, setting these properties has no effect for
+    // some reason. So instead we set releatedTarget, and explicitly check for
+    // its existence in eventGetFromElement() and eventGetToElement().
+    evt.relatedTarget = relatedTarget;
+
+    return evt;
   }-*/;
 
   /**
@@ -39,14 +96,52 @@
     return $doc.createElement(html);
   }-*/;
 
+  public native void dispatchEvent(Element target, NativeEvent evt) /*-{
+    target.fireEvent("on" + evt.type, evt);
+  }-*/;
+
+  @Override
+  public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
+    return Math.round(-evt.wheelDelta / 40) || 0;
+  }-*/;
+
+  @Override
+  public native Element eventGetRelatedTarget(NativeEvent evt) /*-{
+    // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which
+    // explicitly sets relatedTarget when synthesizing mouse events).
+    return evt.relatedTarget ||
+           (evt.type == "mouseout" ? evt.toElement:evt.fromElement);
+  }-*/;
+
+  @Override
+  public native Element eventGetTarget(NativeEvent evt) /*-{
+    return evt.srcElement;
+  }-*/;
+
+  @Override
+  public native void eventPreventDefault(NativeEvent evt) /*-{
+    evt.returnValue = false;
+  }-*/;
+
+  @Override
+  public native void eventStopPropagation(NativeEvent evt) /*-{
+    evt.cancelBubble = true;
+  }-*/;
+
+  @Override
+  public native String eventToString(NativeEvent evt) /*-{
+    if (evt.toString) return evt.toString();
+      return "[event" + evt.type + "]";
+  }-*/;
+
   @Override
   public native int getAbsoluteLeft(Element elem) /*-{
     // getBoundingClientRect() throws a JS exception if the elem is not attached
     // to the document, so we wrap it in a try/catch block
     try {
-      return (elem.getBoundingClientRect().left /
+      return Math.floor((elem.getBoundingClientRect().left /
         this.@com.google.gwt.dom.client.DOMImplIE6::getZoomMultiple()()) +
-        @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft;
+        @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft);
     } catch (e) {
       return 0;
     }
@@ -57,18 +152,20 @@
     // getBoundingClientRect() throws a JS exception if the elem is not attached
     // to the document, so we wrap it in a try/catch block
     try {
-      return (elem.getBoundingClientRect().top /
+      return Math.floor((elem.getBoundingClientRect().top /
         this.@com.google.gwt.dom.client.DOMImplIE6::getZoomMultiple()()) +
-        @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop;
+        @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop);
     } catch (e) {
       return 0;
     }
   }-*/;
 
+  @Override
   public native int getBodyOffsetLeft() /*-{
     return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.clientLeft;
   }-*/;
 
+  @Override
   public native int getBodyOffsetTop() /*-{
     return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.clientTop;
   }-*/;
@@ -128,8 +225,8 @@
   }-*/;
 
   /**
-   * Get the zoom multiple based on the current IE zoom level.  A multiple of
-   * 2.0 means that the user has zoomed in to 200%.
+   * Get the zoom multiple based on the current IE zoom level. A multiple of 2.0
+   * means that the user has zoomed in to 200%.
    * 
    * @return the zoom multiple
    */
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
index 0d1d36b..49519e0 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 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,6 +21,11 @@
 class DOMImplMozilla extends DOMImplStandard {
 
   @Override
+  public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
+    return evt.detail || 0;
+  }-*/;
+
+  @Override
   public native int getAbsoluteLeft(Element elem) /*-{
     // Firefox 3 is actively throwing errors when getBoxObjectFor() is called,
     // so we use getBoundingClientRect() whenever possible (but it's not
@@ -67,13 +72,13 @@
     var style = $wnd.getComputedStyle($doc.documentElement, '');
     return parseInt(style.marginLeft) + parseInt(style.borderLeftWidth);
   }-*/;
-  
+
   @Override
   public native int getBodyOffsetTop() /*-{
     var style = $wnd.getComputedStyle($doc.documentElement, '');
     return parseInt(style.marginTop) + parseInt(style.borderTopWidth);
   }-*/;
-  
+
   @Override
   public native String getInnerText(Element elem) /*-{
     return elem.textContent;
@@ -83,9 +88,9 @@
   public native boolean isOrHasChild(Element parent, Element child) /*-{
     // For more information about compareDocumentPosition, see:
     // http://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html
-    return (parent === child) || !!(parent.compareDocumentPosition(child) & 16);  
+    return (parent === child) || !!(parent.compareDocumentPosition(child) & 16);
   }-*/;
-  
+
   @Override
   public native void setInnerText(Element elem, String text) /*-{
     elem.textContent = text || '';
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java b/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
index b4e375b..6b22e52 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
@@ -24,6 +24,16 @@
  */
  class DOMImplMozillaOld extends DOMImplMozilla {
 
+  public native void buttonClick(ButtonElement button) /*-{
+    var doc = button.ownerDocument;
+    if (doc != null) {
+      var evt = doc.createEvent('MouseEvents');
+      evt.initMouseEvent('click', true, true, null, 0, 0,
+        0, 0, 0, false, false, false, false, 0, null);
+      button.dispatchEvent(evt);
+    }
+  }-*/;
+
   @Override
   public native int getAbsoluteLeft(Element elem) /*-{
     var style = $doc.defaultView.getComputedStyle(elem, null);
diff --git a/user/src/com/google/gwt/dom/client/DOMImplOpera.java b/user/src/com/google/gwt/dom/client/DOMImplOpera.java
index e8c27e4..58f1d69 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplOpera.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplOpera.java
@@ -21,6 +21,11 @@
 class DOMImplOpera extends DOMImplStandard {
 
   @Override
+  public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
+    return evt.detail * 4 || 0;
+  }-*/;
+
+  @Override
   public native int getAbsoluteLeft(Element elem) /*-{
     var left = 0;
 
@@ -63,7 +68,7 @@
     }
     return top;
   }-*/;
-  
+
   @Override
   public native void scrollIntoView(Element elem) /*-{
     elem.scrollIntoView();
diff --git a/user/src/com/google/gwt/dom/client/DOMImplSafari.java b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
index 2265d48..34c50dd 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplSafari.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
@@ -19,6 +19,24 @@
  * Safari implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
  */
 class DOMImplSafari extends DOMImplStandard {
+
+  @Override
+  public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+      boolean metaKey, int keyCode, int charCode) /*-{
+    // The spec calls for KeyEvents/initKeyEvent(), but that doesn't exist on WebKit.
+    var evt = doc.createEvent('HTMLEvents');
+    evt.initEvent(type, canBubble, cancelable);
+    evt.ctrlKey = ctrlKey;
+    evt.altKey = altKey;
+    evt.shiftKey = shiftKey;
+    evt.metaKey = metaKey;
+    evt.keyCode = keyCode;
+    evt.charCode = charCode;
+
+    return evt;
+  }-*/;
+
   /**
    * Safari 2 does not support {@link ScriptElement#setText(String)}.
    */
@@ -30,6 +48,43 @@
   }
 
   @Override
+  public native int eventGetClientX(NativeEvent evt) /*-{
+    // In Safari2: clientX is wrong and pageX is returned instead.
+    // $wnd.devicePixelRatio identifies Safari 3 from Safari 2
+    if ($wnd.devicePixelRatio) {
+      return evt.clientX || 0;
+    } else {
+      // Subtract the margin and border of the HTML element in Safari 2 
+      // TODO: Remove this code when we drop Safari 2 support
+      var style = document.defaultView.getComputedStyle($doc.getElementsByTagName('html')[0], '');
+      return evt.pageX - $doc.body.scrollLeft
+          - parseInt(style.getPropertyValue('margin-left'))
+          - parseInt(style.getPropertyValue('border-left-width')) || 0;
+    }
+  }-*/;
+
+  @Override
+  public native int eventGetClientY(NativeEvent evt) /*-{
+    // In Safari2: clientY is wrong and pageY is returned instead.
+    // $wnd.devicePixelRatio identifies Safari 3 from Safari 2
+    if ($wnd.devicePixelRatio) {
+      return evt.clientY || 0;
+    } else {
+      // Subtract the margin and border of the HTML element in Safari 2 
+      // TODO: Remove this code when we drop Safari 2 support
+      var style = document.defaultView.getComputedStyle($doc.getElementsByTagName('html')[0], '');
+      return evt.pageY - $doc.body.scrollTop
+          - parseInt(style.getPropertyValue('margin-top'))
+          - parseInt(style.getPropertyValue('border-top-width')) || 0;
+    }
+  }-*/;
+
+  @Override
+  public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
+    return Math.round(-evt.wheelDelta / 40) || 0;
+  }-*/;
+
+  @Override
   public native int getAbsoluteLeft(Element elem) /*-{
     // Unattached elements and elements (or their ancestors) with style
     // 'display: none' have no offsetLeft.
@@ -68,7 +123,7 @@
     }
     return left;
   }-*/;
-
+  
   @Override
   public native int getAbsoluteTop(Element elem) /*-{
     // Unattached elements and elements (or their ancestors) with style
diff --git a/user/src/com/google/gwt/dom/client/DOMImplStandard.java b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
index 847b7d3..0536d46 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplStandard.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
@@ -23,6 +23,15 @@
 abstract class DOMImplStandard extends DOMImpl {
 
   @Override
+  public native NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable) /*-{
+    var evt = doc.createEvent('HTMLEvents');
+    evt.initEvent(type, canBubble, cancelable);
+
+    return evt;
+  }-*/;
+
+  @Override
   public native InputElement createInputRadioElement(String name) /*-{
     var elem = $doc.createElement("INPUT");
     elem.type = 'radio';
@@ -31,7 +40,81 @@
   }-*/;
 
   @Override
+  public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+      boolean metaKey, int keyCode, int charCode) /*-{
+    // The spec calls for KeyEvents/initKeyEvent(), but that doesn't exist on WebKit.
+    var evt = doc.createEvent('KeyEvents');
+    evt.initKeyEvent(type, canBubble, cancelable, null, ctrlKey, altKey,
+      shiftKey, metaKey, keyCode, charCode);
+
+    return evt;
+  }-*/;
+
+  @Override
+  public native NativeEvent createMouseEvent(Document doc, String type, boolean canBubble,
+      boolean cancelable, int detail, int screenX, int screenY, int clientX,
+      int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey,
+      boolean metaKey, int button, Element relatedTarget) /*-{
+    // Because Event.getButton() returns bitfield values [1, 4, 2] for [left,
+    // middle, right], we need to translate them to the standard [0, 1, 2]
+    // button constants.
+    if (button == 1) {
+      button = 0;
+    } else if (button == 4) {
+      button = 1;
+    } else {
+      button = 2;
+    }
+
+    var evt = doc.createEvent('MouseEvents');
+    evt.initMouseEvent(type, canBubble, cancelable, null, detail, screenX,
+      screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button,
+      relatedTarget);
+
+    return evt;
+  }-*/;
+ 
+  public native void dispatchEvent(Element target, NativeEvent evt) /*-{
+    target.dispatchEvent(evt);
+  }-*/;
+
+  @Override
+  public native int eventGetButton(NativeEvent evt) /*-{
+    // All modern browsers return 0, 1, and 2 for left, middle, and right,
+    // respectively. Because eventGetButton() is expected to return the IE
+    // bitfield norms of 1, 4, and 2, we translate them here.
+    var button = evt.button;
+    if (button == 1) {
+      return 4;
+    } else if (button == 2) {
+      return 2;
+    }
+    return 1;
+  }-*/;
+
+  @Override
+  public native Element eventGetRelatedTarget(NativeEvent evt) /*-{
+    return evt.relatedTarget;
+  }-*/;
+
+  @Override
+  public native Element eventGetTarget(NativeEvent evt) /*-{
+    return evt.target;
+  }-*/;
+
+  @Override
+  public native void eventPreventDefault(NativeEvent evt) /*-{
+    evt.preventDefault();
+  }-*/;
+
+  @Override
+  public native String eventToString(NativeEvent evt) /*-{
+    return evt.toString();
+  }-*/;
+
+  @Override
   public native boolean isOrHasChild(Element parent, Element child) /*-{
-    return parent.contains(child);  
+    return parent.contains(child);
   }-*/;
 }
diff --git a/user/src/com/google/gwt/dom/client/Document.java b/user/src/com/google/gwt/dom/client/Document.java
index 3d10a25..b19540e 100644
--- a/user/src/com/google/gwt/dom/client/Document.java
+++ b/user/src/com/google/gwt/dom/client/Document.java
@@ -16,10 +16,9 @@
 package com.google.gwt.dom.client;
 
 /**
- * A Document is the root of the HTML hierarchy and holds the entire
- * content. Besides providing access to the hierarchy, it also provides some
- * convenience methods for accessing certain sets of information from the
- * document.
+ * A Document is the root of the HTML hierarchy and holds the entire content.
+ * Besides providing access to the hierarchy, it also provides some convenience
+ * methods for accessing certain sets of information from the document.
  */
 public class Document extends Node {
 
@@ -73,6 +72,13 @@
   }
 
   /**
+   * Creates a 'blur' event.
+   */
+  public final NativeEvent createBlurEvent() {
+    return createHtmlEvent("blur", false, false);
+  }
+
+  /**
    * Creates a &lt;br&gt; element.
    * 
    * @return the newly created element
@@ -100,6 +106,13 @@
   }
 
   /**
+   * Creates a 'change' event.
+   */
+  public final NativeEvent createChangeEvent() {
+    return createHtmlEvent("change", false, true);
+  }
+
+  /**
    * Creates an &lt;input type='checkbox'&gt; element.
    * 
    * @return the newly created element
@@ -109,6 +122,35 @@
   }
 
   /**
+   * Creates a 'click' event.
+   * 
+   * <p>
+   * Note that this method does not allow the event's 'button' field to be
+   * specified, because not all browsers support it reliably for click events.
+   * </p>
+   * 
+   * @param detail the event's detail property
+   * @param screenX the event's screen-relative x-position
+   * @param screenY the event's screen-relative y-position
+   * @param clientX the event's client-relative x-position
+   * @param clientY the event's client-relative y-position
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @return the event object
+   */
+  public final NativeEvent createClickEvent(int detail, int screenX, int screenY,
+      int clientX, int clientY, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey) {
+    // We disallow setting the button here, because IE doesn't provide the
+    // button property for click events.
+    return createMouseEvent("click", true, true, detail, screenX, screenY,
+        clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
+        NativeEvent.BUTTON_LEFT, null);
+  }
+
+  /**
    * Creates a &lt;col&gt; element.
    * 
    * @return the newly created element
@@ -127,6 +169,52 @@
   }
 
   /**
+   * Creates a 'contextmenu' event.
+   * 
+   * Note: Contextmenu events will not dispatch properly on Firefox 2 and
+   * earlier.
+   * 
+   * @return the event object
+   */
+  public final NativeEvent createContextMenuEvent() {
+    return createHtmlEvent("contextmenu", true, true);
+  }
+
+  /**
+   * Creates a 'dblclick' event.
+   * 
+   * <p>
+   * Note that this method does not allow the event's 'button' field to be
+   * specified, because not all browsers support it reliably for click events.
+   * </p>
+   * 
+   * <p>
+   * Note that on some browsers, this may cause 'click' events to be synthesized
+   * as well.
+   * </p>
+   * 
+   * @param detail the event's detail property
+   * @param screenX the event's screen-relative x-position
+   * @param screenY the event's screen-relative y-position
+   * @param clientX the event's client-relative x-position
+   * @param clientY the event's client-relative y-position
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @return the event object
+   */
+  public final NativeEvent createDblClickEvent(int detail, int screenX, int screenY,
+      int clientX, int clientY, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey) {
+    // We disallow setting the button here, because IE doesn't provide the
+    // button property for click events.
+    return createMouseEvent("dblclick", true, true, detail, screenX, screenY,
+        clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
+        NativeEvent.BUTTON_LEFT, null);
+  }
+
+  /**
    * Creates a &lt;del&gt; element.
    * 
    * @return the newly created element
@@ -164,6 +252,15 @@
   }
 
   /**
+   * Creates an 'error' event.
+   * 
+   * @return the event object
+   */
+  public final NativeEvent createErrorEvent() {
+    return createHtmlEvent("error", false, false);
+  }
+
+  /**
    * Creates a &lt;fieldset&gt; element.
    * 
    * @return the newly created element
@@ -182,6 +279,15 @@
   }
 
   /**
+   * Creates a 'focus' event.
+   * 
+   * @return the event object
+   */
+  public final NativeEvent createFocusEvent() {
+    return createHtmlEvent("focus", false, false);
+  }
+
+  /**
    * Creates a &lt;form&gt; element.
    * 
    * @return the newly created element
@@ -247,6 +353,31 @@
   }
 
   /**
+   * Creates an event.
+   * 
+   * <p>
+   * While this method may be used to create events directly, it is generally
+   * preferable to use existing helper methods such as
+   * {@link #createFocusEvent()}.
+   * </p>
+   * 
+   * <p>
+   * Also, note that on Internet Explorer the 'canBubble' and 'cancelable'
+   * arguments will be ignored (the event's behavior is inferred by the browser
+   * based upon its type).
+   * </p>
+   * 
+   * @param type the type of event (e.g., "focus", "load", etc)
+   * @param canBubble <code>true</code> if the event should bubble
+   * @param cancelable <code>true</code> if the event should be cancelable
+   * @return the event object
+   */
+  public final NativeEvent createHtmlEvent(String type, boolean canBubble,
+      boolean cancelable) {
+    return DOMImpl.impl.createHtmlEvent(this, type, canBubble, cancelable);
+  }
+
+  /**
    * Creates an &lt;iframe&gt; element.
    * 
    * @return the newly created element
@@ -283,6 +414,91 @@
   }
 
   /**
+   * Creates a 'keydown' event.
+   * 
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param keyCode the key-code to be set on the event
+   * @param charCode the char-code to be set on the event
+   * @return the event object
+   */
+  public final NativeEvent createKeyDownEvent(boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int keyCode, int charCode) {
+    return createKeyEvent("keydown", true, true, ctrlKey, altKey, shiftKey,
+        metaKey, keyCode, charCode);
+  }
+
+  /**
+   * Creates a key event.
+   * 
+   * <p>
+   * While this method may be used to create events directly, it is generally
+   * preferable to use existing helper methods such as
+   * {@link #createKeyPressEvent(boolean, boolean, boolean, boolean, int, int)}
+   * .
+   * </p>
+   * 
+   * <p>
+   * Also, note that on Internet Explorer the 'canBubble' and 'cancelable'
+   * arguments will be ignored (the event's behavior is inferred by the browser
+   * based upon its type).
+   * </p>
+   * 
+   * @param type the type of event (e.g., "focus", "load", etc)
+   * @param canBubble <code>true</code> if the event should bubble
+   * @param cancelable <code>true</code> if the event should be cancelable
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param keyCode the key-code to be set on the event
+   * @param charCode the char-code to be set on the event
+   * @return the event object
+   */
+  public final NativeEvent createKeyEvent(String type, boolean canBubble,
+      boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+      boolean metaKey, int keyCode, int charCode) {
+    return DOMImpl.impl.createKeyEvent(this, type, canBubble, cancelable,
+        ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode);
+  }
+
+  /**
+   * Creates a 'keypress' event.
+   * 
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param keyCode the key-code to be set on the event
+   * @param charCode the char-code to be set on the event
+   * @return the event object
+   */
+  public final NativeEvent createKeyPressEvent(boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int keyCode, int charCode) {
+    return createKeyEvent("keypress", true, true, ctrlKey, altKey, shiftKey,
+        metaKey, keyCode, charCode);
+  }
+
+  /**
+   * Creates a 'keyup' event.
+   * 
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param keyCode the key-code to be set on the event
+   * @param charCode the char-code to be set on the event
+   * @return the event object
+   */
+  public final NativeEvent createKeyUpEvent(boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int keyCode, int charCode) {
+    return createKeyEvent("keyup", true, true, ctrlKey, altKey, shiftKey,
+        metaKey, keyCode, charCode);
+  }
+
+  /**
    * Creates a &lt;label&gt; element.
    * 
    * @return the newly created element
@@ -319,6 +535,15 @@
   }
 
   /**
+   * Creates a 'load' event.
+   * 
+   * @return the event object
+   */
+  public final NativeEvent createLoadEvent() {
+    return createHtmlEvent("load", false, false);
+  }
+
+  /**
    * Creates a &lt;map&gt; element.
    * 
    * @return the newly created element
@@ -337,6 +562,174 @@
   }
 
   /**
+   * Creates a 'mousedown' event.
+   * 
+   * @param detail the event's detail property
+   * @param screenX the event's screen-relative x-position
+   * @param screenY the event's screen-relative y-position
+   * @param clientX the event's client-relative x-position
+   * @param clientY the event's client-relative y-position
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param button the event's button property (values from
+   *          {@link Event#BUTTON_LEFT} et al)
+   * @return the event object
+   */
+  public final NativeEvent createMouseDownEvent(int detail, int screenX, int screenY,
+      int clientX, int clientY, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int button) {
+    return createMouseEvent("mousedown", true, true, detail, screenX, screenY,
+        clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null);
+  }
+
+  /**
+   * Creates an mouse event.
+   * 
+   * <p>
+   * While this method may be used to create events directly, it is generally
+   * preferable to use existing helper methods such as
+   * {@link #createClickEvent(int, int, int, int, int, boolean, boolean, boolean, boolean)}
+   * .
+   * </p>
+   * 
+   * <p>
+   * Also, note that on Internet Explorer the 'canBubble' and 'cancelable'
+   * arguments will be ignored (the event's behavior is inferred by the browser
+   * based upon its type).
+   * </p>
+   * 
+   * @param type the type of event (e.g., "focus", "load", etc)
+   * @param canBubble <code>true</code> if the event should bubble
+   * @param cancelable <code>true</code> if the event should be cancelable
+   * @param detail the event's detail property
+   * @param screenX the event's screen-relative x-position
+   * @param screenY the event's screen-relative y-position
+   * @param clientX the event's client-relative x-position
+   * @param clientY the event's client-relative y-position
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param button the event's button property (values from
+   *          {@link Event#BUTTON_LEFT} et al)
+   * @param relatedTarget the event's related target (only relevant for
+   *          mouseover and mouseout events)
+   * @return the event object
+   */
+  public final NativeEvent createMouseEvent(String type, boolean canBubble,
+      boolean cancelable, int detail, int screenX, int screenY, int clientX,
+      int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey,
+      boolean metaKey, int button, Element relatedTarget) {
+    return DOMImpl.impl.createMouseEvent(this, type, canBubble, cancelable,
+        detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey,
+        metaKey, button, relatedTarget);
+  }
+
+  /**
+   * Creates a 'mousemove' event.
+   * 
+   * @param detail the event's detail property
+   * @param screenX the event's screen-relative x-position
+   * @param screenY the event's screen-relative y-position
+   * @param clientX the event's client-relative x-position
+   * @param clientY the event's client-relative y-position
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param button the event's button property (values from
+   *          {@link Event#BUTTON_LEFT} et al)
+   * @return the event object
+   */
+  public final NativeEvent createMouseMoveEvent(int detail, int screenX, int screenY,
+      int clientX, int clientY, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int button) {
+    return createMouseEvent("mousemove", true, true, detail, screenX, screenY,
+        clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null);
+  }
+
+  /**
+   * Creates a 'mouseout' event.
+   * 
+   * Note: The 'relatedTarget' parameter will be ignored on Firefox 2 and
+   * earlier.
+   * 
+   * @param detail the event's detail property
+   * @param screenX the event's screen-relative x-position
+   * @param screenY the event's screen-relative y-position
+   * @param clientX the event's client-relative x-position
+   * @param clientY the event's client-relative y-position
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param button the event's button property (values from
+   *          {@link Event#BUTTON_LEFT} et al)
+   * @param relatedTarget the event's related target
+   * @return the event object
+   */
+  public final NativeEvent createMouseOutEvent(int detail, int screenX, int screenY,
+      int clientX, int clientY, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int button, Element relatedTarget) {
+    return createMouseEvent("mouseout", true, true, detail, screenX, screenY,
+        clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button,
+        relatedTarget);
+  }
+
+  /**
+   * Creates a 'mouseover' event.
+   * 
+   * Note: The 'relatedTarget' parameter will be ignored on Firefox 2 and
+   * earlier.
+   * 
+   * @param detail the event's detail property
+   * @param screenX the event's screen-relative x-position
+   * @param screenY the event's screen-relative y-position
+   * @param clientX the event's client-relative x-position
+   * @param clientY the event's client-relative y-position
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param button the event's button property (values from
+   *          {@link Event#BUTTON_LEFT} et al)
+   * @param relatedTarget the event's related target
+   * @return the event object
+   */
+  public final NativeEvent createMouseOverEvent(int detail, int screenX, int screenY,
+      int clientX, int clientY, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int button, Element relatedTarget) {
+    return createMouseEvent("mouseover", true, true, detail, screenX, screenY,
+        clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button,
+        relatedTarget);
+  }
+
+  /**
+   * Creates a 'mouseup' event.
+   * 
+   * @param detail the event's detail property
+   * @param screenX the event's screen-relative x-position
+   * @param screenY the event's screen-relative y-position
+   * @param clientX the event's client-relative x-position
+   * @param clientY the event's client-relative y-position
+   * @param ctrlKey <code>true</code> if the ctrl key is depressed
+   * @param altKey <code>true</code> if the alt key is depressed
+   * @param shiftKey <code>true</code> if the shift key is depressed
+   * @param metaKey <code>true</code> if the meta key is depressed
+   * @param button the event's button property (values from
+   *          {@link Event#BUTTON_LEFT} et al)
+   * @return the event object
+   */
+  public final NativeEvent createMouseUpEvent(int detail, int screenX, int screenY,
+      int clientX, int clientY, boolean ctrlKey, boolean altKey,
+      boolean shiftKey, boolean metaKey, int button) {
+    return createMouseEvent("mouseup", true, true, detail, screenX, screenY,
+        clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null);
+  }
+
+  /**
    * Creates a &lt;object&gt; element.
    * 
    * @return the newly created element
@@ -447,6 +840,18 @@
   }
 
   /**
+   * Creates a 'scroll' event.
+   * 
+   * Note: Contextmenu events will not dispatch properly on Firefox 2 and
+   * earlier.
+   * 
+   * @return the event object
+   */
+  public final NativeEvent createScrollEvent() {
+    return createHtmlEvent("scroll", false, false);
+  }
+
+  /**
    * Creates a &lt;select&gt; element.
    * 
    * @return the newly created element
@@ -628,6 +1033,7 @@
    * For example, to position an element directly under the mouse cursor
    * (assuming you are handling a mouse event), do the following:
    * </p>
+   * 
    * <pre>
    * Event event;
    * Document doc;
@@ -743,8 +1149,8 @@
    * that the two documents may have different DTDs in the XML case.
    * 
    * @param node the node to import
-   * @param deep If <code>true</code>, recursively import the subtree under
-   *          the specified node; if <code>false</code>, import only the node
+   * @param deep If <code>true</code>, recursively import the subtree under the
+   *          specified node; if <code>false</code>, import only the node
    *          itself, as explained above
    */
   public final native void importNode(Node node, boolean deep) /*-{
diff --git a/user/src/com/google/gwt/dom/client/Element.java b/user/src/com/google/gwt/dom/client/Element.java
index 54abf0b..0559099 100644
--- a/user/src/com/google/gwt/dom/client/Element.java
+++ b/user/src/com/google/gwt/dom/client/Element.java
@@ -33,6 +33,22 @@
   }
 
   /**
+   * Dispatched the given event with this element as its target. The event will
+   * go through all phases of the browser's normal event dispatch mechanism.
+   * 
+   * Note: Because the browser's normal dispatch mechanism is used, exceptions
+   * thrown from within handlers triggered by this method cannot be caught by
+   * wrapping this method in a try/catch block. Such exceptions will be caught
+   * by the {@link GWT#setUncaughtExceptionHandler() uncaught exception handler}
+   * as usual.
+   * 
+   * @param evt the event to be dispatched
+   */
+  public final void dispatchEvent(NativeEvent evt) {
+    DOMImpl.impl.dispatchEvent(this, evt);
+  }
+
+  /**
    * Gets an element's absolute left coordinate in the document's coordinate
    * system.
    */
diff --git a/user/src/com/google/gwt/dom/client/NativeEvent.java b/user/src/com/google/gwt/dom/client/NativeEvent.java
new file mode 100644
index 0000000..8109652
--- /dev/null
+++ b/user/src/com/google/gwt/dom/client/NativeEvent.java
@@ -0,0 +1,215 @@
+/*

+ * Copyright 2009 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;

+

+/**

+ * The native dom event.

+ */

+public class NativeEvent extends JavaScriptObject {

+

+  /**

+   * The left mouse button.

+   */

+  public static final int BUTTON_LEFT = 1;

+

+  /**

+   * The middle mouse button.

+   */

+  public static final int BUTTON_MIDDLE = 4;

+

+  /**

+   * The right mouse button.

+   */

+  public static final int BUTTON_RIGHT = 2;

+

+  /**

+   * Required constructor for GWT compiler to function.

+   */

+  protected NativeEvent() {

+  }

+

+  /**

+   * Gets whether the ALT key was depressed when the given event occurred.

+   * 

+   * @return <code>true</code> if ALT was depressed when the event occurred

+   */

+  public final boolean getAltKey() {

+    return DOMImpl.impl.eventGetAltKey(this);

+  }

+

+  /**

+   * Gets the mouse buttons that were depressed when the given event occurred.

+   * 

+   * @return a bit-field, defined by {@link NativeEvent#BUTTON_LEFT},

+   *         {@link NativeEvent#BUTTON_MIDDLE}, and

+   *         {@link NativeEvent#BUTTON_RIGHT}

+   */

+  public final int getButton() {

+    return DOMImpl.impl.eventGetButton(this);

+  }

+

+  /**

+   * Gets the mouse x-position within the browser window's client area.

+   * 

+   * @return the mouse x-position

+   */

+  public final int getClientX() {

+    return DOMImpl.impl.eventGetClientX(this);

+  }

+

+  /**

+   * Gets the mouse y-position within the browser window's client area.

+   * 

+   * @return the mouse y-position

+   */

+  public final int getClientY() {

+    return DOMImpl.impl.eventGetClientY(this);

+  }

+

+  /**

+   * Gets whether the CTRL key was depressed when the given event occurred.

+   * 

+   * @return <code>true</code> if CTRL was depressed when the event occurred

+   */

+  public final boolean getCtrlKey() {

+    return DOMImpl.impl.eventGetCtrlKey(this);

+  }

+

+  /**

+   * Gets the key code associated with this event.

+   * 

+   * <p>

+   * For key press events, this method returns the Unicode value of the

+   * character generated. For key down and key up events, it returns the code

+   * associated with the physical key.

+   * </p>

+   * 

+   * @return the Unicode character or key code.

+   * @see com.google.gwt.event.dom.client.KeyCodes

+   */

+  public final int getKeyCode() {

+    return DOMImpl.impl.eventGetKeyCode(this);

+  }

+

+  /**

+   * Gets whether the META key was depressed when the given event occurred.

+   * 

+   * @return <code>true</code> if META was depressed when the event occurred

+   */

+  public final boolean getMetaKey() {

+    return DOMImpl.impl.eventGetMetaKey(this);

+  }

+

+  /**

+   * 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>

+   * 

+   * @return The velocity of the mouse wheel.

+   */

+  public final int getMouseWheelVelocityY() {

+    return DOMImpl.impl.eventGetMouseWheelVelocityY(this);

+  }

+

+  /**

+   * Gets the related target for this event.

+   * 

+   * @return the related target

+   */

+  public final Element getRelatedTarget() {

+    return DOMImpl.impl.eventGetRelatedTarget(this);

+  }

+

+  /**

+   * Gets the mouse x-position on the user's display.

+   * 

+   * @return the mouse x-position

+   */

+  public final int getScreenX() {

+    return DOMImpl.impl.eventGetScreenX(this);

+  }

+

+  /**

+   * Gets the mouse y-position on the user's display.

+   * 

+   * @return the mouse y-position

+   */

+  public final int getScreenY() {

+    return DOMImpl.impl.eventGetScreenY(this);

+  }

+

+  /**

+   * Gets whether the shift key was depressed when the given event occurred.

+   * 

+   * @return <code>true</code> if shift was depressed when the event occurred

+   */

+  public final boolean getShiftKey() {

+    return DOMImpl.impl.eventGetShiftKey(this);

+  }

+

+  /**

+   * Gets a string representation of this event.

+   * 

+   * We do not override {@link #toString()} because it is final in

+   * {@link com.google.gwt.core.client.JavaScriptObject }.

+   * 

+   * @return the string representation of this event

+   */

+  public final String getString() {

+    return DOMImpl.impl.eventToString(this);

+  }

+

+  /**

+   * Returns the element that was the actual target of the given event.

+   * 

+   * @return the target element

+   */

+  public final Element getTarget() {

+    return DOMImpl.impl.eventGetTarget(this);

+  }

+

+  /**

+   * Gets the enumerated type of this event.

+   * 

+   * @return the event's enumerated type

+   */

+  public final String getType() {

+    return DOMImpl.impl.eventGetType(this);

+  }

+

+  /**

+   * Prevents the browser from taking its default action for the given event.

+   */

+  public final void preventDefault() {

+    DOMImpl.impl.eventPreventDefault(this);

+  }

+

+  /**

+   * Stops the event from being propagated to parent elements.

+   */

+  public final void stopPropagation() {

+    DOMImpl.impl.eventStopPropagation(this);

+  }

+}

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 c5434ae..1e761c5 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,5 @@
 <module>
 	<inherits name="com.google.gwt.event.EventBase" />
-	<inherits name="com.google.gwt.user.DOM" />
-
+	<inherits name="com.google.gwt.dom.DOM" />
   <source path="client"/>
 </module>
diff --git a/user/src/com/google/gwt/event/dom/client/BlurEvent.java b/user/src/com/google/gwt/event/dom/client/BlurEvent.java
index acbd82c..db0d326 100644
--- a/user/src/com/google/gwt/event/dom/client/BlurEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/BlurEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native blur event.

  */

@@ -26,8 +24,8 @@
    * Event type for blur events. Represents the meta-data associated with this

    * event.

    */

-  private static final Type<BlurHandler> TYPE = new Type<BlurHandler>(

-      Event.ONBLUR, "blur", new BlurEvent());

+  private static final Type<BlurHandler> TYPE = new Type<BlurHandler>("blur",

+      new BlurEvent());

 

   /**

    * Gets the event type associated with blur events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire blur events.

    */

   protected BlurEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/ChangeEvent.java b/user/src/com/google/gwt/event/dom/client/ChangeEvent.java
index f66f3cd..7a2ec49 100644
--- a/user/src/com/google/gwt/event/dom/client/ChangeEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ChangeEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native change event.

  */

@@ -27,7 +25,7 @@
    * event.

    */

   private static final Type<ChangeHandler> TYPE = new Type<ChangeHandler>(

-      Event.ONCHANGE, "change", new ChangeEvent());

+      "change", new ChangeEvent());

 

   /**

    * Gets the event type associated with change events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire change events.

    */

   protected ChangeEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/ClickEvent.java b/user/src/com/google/gwt/event/dom/client/ClickEvent.java
index 805c956..74fc74e 100644
--- a/user/src/com/google/gwt/event/dom/client/ClickEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ClickEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native click event.

  */

@@ -27,7 +25,7 @@
    * event.

    */

   private static final Type<ClickHandler> TYPE = new Type<ClickHandler>(

-      Event.ONCLICK, "click", new ClickEvent());

+      "click", new ClickEvent());

 

   /**

    * Gets the event type associated with click events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire click events.

    */

   protected ClickEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/ContextMenuEvent.java b/user/src/com/google/gwt/event/dom/client/ContextMenuEvent.java
index 513fd2b..ff801d3 100644
--- a/user/src/com/google/gwt/event/dom/client/ContextMenuEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ContextMenuEvent.java
@@ -15,8 +15,6 @@
  */
 package com.google.gwt.event.dom.client;
 
-import com.google.gwt.user.client.Event;
-
 /**
  * Represents a native context menu event.
  */
@@ -27,7 +25,7 @@
    * with this event.
    */
   private static final Type<ContextMenuHandler> TYPE = new Type<ContextMenuHandler>(
-      Event.ONCONTEXTMENU, "contextmenu", new ContextMenuEvent());
+      "contextmenu", new ContextMenuEvent());
 
   /**
    * Gets the event type associated with context menu events.
@@ -40,7 +38,7 @@
 
   /**
    * Protected constructor, use
-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
    * to fire context menu events.
    */
   protected ContextMenuEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/DomEvent.java b/user/src/com/google/gwt/event/dom/client/DomEvent.java
index c4ff6f4..bf279db 100644
--- a/user/src/com/google/gwt/event/dom/client/DomEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DomEvent.java
@@ -15,14 +15,13 @@
  */
 package com.google.gwt.event.dom.client;
 
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.GwtEvent;
 import com.google.gwt.event.shared.HasHandlers;
-import com.google.gwt.user.client.Event;
 
 /**
  * {@link DomEvent} is a subclass of {@link GwtEvent} that provides events that
- * map to DOM Level 2 Events. It provides an additional method to access the
  * underlying native browser event object as well as a subclass of {@link Type}
  * that understands GWT event bits used by sinkEvents().
  * 
@@ -39,38 +38,25 @@
    * @param <H> handler type
    */
   public static class Type<H extends EventHandler> extends GwtEvent.Type<H> {
-    private final int eventToSink;
     private DomEvent<H> flyweight;
-
-    /**
-     * Constructor.
-     * 
-     * @param eventToSink the native event type to sink
-     * 
-     */
-    public Type(int eventToSink) {
-      this.eventToSink = eventToSink;
-    }
+    private String name;
 
     /**
      * This constructor allows dom event types to be triggered by the
-     * {@link DomEvent#fireNativeEvent(Event, HasHandlers)} method. It should
-     * only be used by implementors supporting new dom events.
+     * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, HasHandlers)}
+     * method. It should only be used by implementors supporting new dom events.
+     * 
      * <p>
      * Any such dom event type must act as a flyweight around a native event
      * object.
      * </p>
      * 
-     * 
-     * @param eventToSink the integer value used by sink events to set up event
-     *          handling for this dom type
      * @param eventName the raw native event name
      * @param flyweight the instance that will be used as a flyweight to wrap a
      *          native event
      */
-    protected Type(int eventToSink, String eventName, DomEvent<H> flyweight) {
+    public Type(String eventName, DomEvent<H> flyweight) {
       this.flyweight = flyweight;
-      this.eventToSink = eventToSink;
 
       // Until we have eager clinits implemented, we are manually initializing
       // DomEvent here.
@@ -78,26 +64,16 @@
         init();
       }
       registered.unsafePut(eventName, this);
-    }
-
-    Type(int nativeEventTypeInt, String eventName, DomEvent<H> cached,
-        String... auxNames) {
-      this(nativeEventTypeInt, eventName, cached);
-      for (int i = 0; i < auxNames.length; i++) {
-        registered.unsafePut(auxNames[i], this);
-      }
+      name = eventName;
     }
 
     /**
-     * Gets the integer defined by the native {@link Event} type needed to hook
-     * up event handling when the user calls
-     * {@link com.google.gwt.user.client.DOM#sinkEvents(com.google.gwt.user.client.Element, int)}
-     * .
+     * Gets the name associated with this event type.
      * 
-     * @return the native event type
+     * @return the name of this event typ
      */
-    public int getEventToSink() {
-      return eventToSink;
+    public String getName() {
+      return name;
     }
   }
 
@@ -107,19 +83,19 @@
    * Fires the given native event on the specified handlers.
    * 
    * @param nativeEvent the native event
-   * @param handlers the event manager containing the handlers to fire (may be
-   *          null)
+   * @param handlerSource the source of the handlers to fire
    */
-  public static void fireNativeEvent(Event nativeEvent, HasHandlers handlers) {
+  public static void fireNativeEvent(NativeEvent nativeEvent,
+      HasHandlers handlerSource) {
     assert nativeEvent != null : "nativeEvent must not be null";
-    if (registered != null && handlers != null) {
+    if (registered != null) {
       final DomEvent.Type<?> typeKey = registered.unsafeGet(nativeEvent.getType());
       if (typeKey != null) {
         // Store and restore native event just in case we are in recursive
         // loop.
-        Event currentNative = typeKey.flyweight.nativeEvent;
+        NativeEvent currentNative = typeKey.flyweight.nativeEvent;
         typeKey.flyweight.setNativeEvent(nativeEvent);
-        handlers.fireEvent(typeKey.flyweight);
+        handlerSource.fireEvent(typeKey.flyweight);
         typeKey.flyweight.setNativeEvent(currentNative);
       }
     }
@@ -130,12 +106,12 @@
     registered = new PrivateMap<Type<?>>();
   }
 
-  private Event nativeEvent;
+  private NativeEvent nativeEvent;
 
   @Override
   public abstract DomEvent.Type<H> getAssociatedType();
 
-  public final Event getNativeEvent() {
+  public final NativeEvent getNativeEvent() {
     assertLive();
     return nativeEvent;
   }
@@ -154,7 +130,7 @@
    * 
    * @param nativeEvent the native event
    */
-  public final void setNativeEvent(Event nativeEvent) {
+  public final void setNativeEvent(NativeEvent nativeEvent) {
     this.nativeEvent = nativeEvent;
   }
 
@@ -163,6 +139,6 @@
    */
   public void stopPropagation() {
     assertLive();
-    nativeEvent.cancelBubble(true);
+    nativeEvent.stopPropagation();
   }
 }
diff --git a/user/src/com/google/gwt/event/dom/client/DoubleClickEvent.java b/user/src/com/google/gwt/event/dom/client/DoubleClickEvent.java
index 972b645..20cdf8e 100644
--- a/user/src/com/google/gwt/event/dom/client/DoubleClickEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DoubleClickEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native double click event.

  */

@@ -27,7 +25,7 @@
    * with this event.

    */

   private static final Type<DoubleClickHandler> TYPE = new Type<DoubleClickHandler>(

-      Event.ONDBLCLICK, "dblclick", new DoubleClickEvent());

+      "dblclick", new DoubleClickEvent());

 

   /**

    * Gets the event type associated with double click events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire double click events.

    */

   protected DoubleClickEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/ErrorEvent.java b/user/src/com/google/gwt/event/dom/client/ErrorEvent.java
index 0c9a007..40a3771 100644
--- a/user/src/com/google/gwt/event/dom/client/ErrorEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ErrorEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native error event.

  */

@@ -27,7 +25,7 @@
    * event.

    */

   private static final Type<ErrorHandler> TYPE = new Type<ErrorHandler>(

-      Event.ONERROR, "error", new ErrorEvent());

+      "error", new ErrorEvent());

 

   /**

    * Gets the event type associated with error events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire error events.

    */

   protected ErrorEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/FocusEvent.java b/user/src/com/google/gwt/event/dom/client/FocusEvent.java
index c2ca7bd..16df375 100644
--- a/user/src/com/google/gwt/event/dom/client/FocusEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/FocusEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native focus event.

  */

@@ -27,7 +25,7 @@
    * event.

    */

   private static final Type<FocusHandler> TYPE = new Type<FocusHandler>(

-      Event.ONFOCUS, "focus", new FocusEvent());

+      "focus", new FocusEvent());

 

   /**

    * Gets the event type associated with focus events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire focus events.

    */

   protected FocusEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java b/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java
index 510c273..88aaf36 100644
--- a/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java
@@ -16,7 +16,7 @@
 
 package com.google.gwt.event.dom.client;
 
-import com.google.gwt.user.client.Event;
+import com.google.gwt.dom.client.NativeEvent;
 
 /**
  * An object that implements this interface has a native event associated with
@@ -28,5 +28,5 @@
    * 
    * @return the native event
    */
-  Event getNativeEvent();
+  NativeEvent getNativeEvent();
 }
diff --git a/user/src/com/google/gwt/event/dom/client/KeyDownEvent.java b/user/src/com/google/gwt/event/dom/client/KeyDownEvent.java
index 1b58b03..d1175a2 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyDownEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyDownEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native key down event.

  */

@@ -27,7 +25,7 @@
    * this event.

    */

   private static final Type<KeyDownHandler> TYPE = new Type<KeyDownHandler>(

-      Event.ONKEYDOWN, "keydown", new KeyDownEvent());

+      "keydown", new KeyDownEvent());

 

   /**

    * Gets the event type associated with key down events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire key down events.

    */

   protected KeyDownEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/KeyEvent.java b/user/src/com/google/gwt/event/dom/client/KeyEvent.java
index c6367e2..535995f 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyEvent.java
@@ -47,15 +47,6 @@
   }
 
   /**
-   * Gets the key-repeat state of this event.
-   * 
-   * @return <code>true</code> if this key event was an auto-repeat
-   */
-  public boolean isAutoRepeat() {
-    return getNativeEvent().getRepeat();
-  }
-
-  /**
    * Is the <code>control</code> key down?
    * 
    * @return whether the control key is down
diff --git a/user/src/com/google/gwt/event/dom/client/KeyPressEvent.java b/user/src/com/google/gwt/event/dom/client/KeyPressEvent.java
index f955e3c..496aa6c 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyPressEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyPressEvent.java
@@ -15,7 +15,7 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

+import com.google.gwt.dom.client.NativeEvent; 

 

 /**

  * Represents a native key press event.

@@ -27,7 +27,7 @@
    * this event.

    */

   private static final Type<KeyPressHandler> TYPE = new Type<KeyPressHandler>(

-      Event.ONKEYPRESS, "keypress", new KeyPressEvent());

+      "keypress", new KeyPressEvent());

 

   /**

    * Gets the event type associated with key press events.

@@ -40,7 +40,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire key press events.

    */

   protected KeyPressEvent() {

@@ -70,8 +70,8 @@
     handler.onKeyPress(this);

   }

 

-  private native char getCharCode(Event e)/*-{

-        return e.charCode || e.keyCode;

-      }-*/;

+  private native char getCharCode(NativeEvent e)/*-{

+    return e.charCode || e.keyCode;

+  }-*/;

 

 }

diff --git a/user/src/com/google/gwt/event/dom/client/KeyUpEvent.java b/user/src/com/google/gwt/event/dom/client/KeyUpEvent.java
index 5a07977..f728468 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyUpEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyUpEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native key up event.

  */

@@ -27,7 +25,7 @@
    * event.

    */

   private static final Type<KeyUpHandler> TYPE = new Type<KeyUpHandler>(

-      Event.ONKEYUP, "keyup", new KeyUpEvent());

+      "keyup", new KeyUpEvent());

 

   /**

    * Gets the event type associated with key up events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire key up events.

    */

   protected KeyUpEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/LoadEvent.java b/user/src/com/google/gwt/event/dom/client/LoadEvent.java
index 3255c4b..00397fb 100644
--- a/user/src/com/google/gwt/event/dom/client/LoadEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/LoadEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native load event.

  */

@@ -26,8 +24,8 @@
    * Event type for load events. Represents the meta-data associated with this

    * event.

    */

-  private static final Type<LoadHandler> TYPE = new Type<LoadHandler>(

-      Event.ONLOAD, "load", new LoadEvent());

+  private static final Type<LoadHandler> TYPE = new Type<LoadHandler>("load",

+      new LoadEvent());

 

   /**

    * Gets the event type associated with load events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire load events.

    */

   protected LoadEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/LoseCaptureEvent.java b/user/src/com/google/gwt/event/dom/client/LoseCaptureEvent.java
index 857e8d0..eef6843 100644
--- a/user/src/com/google/gwt/event/dom/client/LoseCaptureEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/LoseCaptureEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native lose capture event.

  */

@@ -27,7 +25,7 @@
    * with this event.

    */

   private static final Type<LoseCaptureHandler> TYPE = new Type<LoseCaptureHandler>(

-      Event.ONLOSECAPTURE, "losecapture", new LoseCaptureEvent());

+      "losecapture", new LoseCaptureEvent());

 

   /**

    * Gets the event type associated with lose capture events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire lose capture events.

    */

   protected LoseCaptureEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/MouseDownEvent.java b/user/src/com/google/gwt/event/dom/client/MouseDownEvent.java
index dd36ec2..5dcfff6 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseDownEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseDownEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native mouse down event.

  */

@@ -27,7 +25,7 @@
    * this event.

    */

   private static final Type<MouseDownHandler> TYPE = new Type<MouseDownHandler>(

-      Event.ONMOUSEDOWN, "mousedown", new MouseDownEvent());

+      "mousedown", new MouseDownEvent());

 

   /**

    * Gets the event type associated with mouse down events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire mouse down events.

    */

   protected MouseDownEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/MouseEvent.java b/user/src/com/google/gwt/event/dom/client/MouseEvent.java
index 424b138..1357261 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseEvent.java
@@ -15,10 +15,7 @@
  */
 package com.google.gwt.event.dom.client;
 
-import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.Window;
 
 /**
  * Abstract class representing mouse events.
@@ -28,30 +25,6 @@
  */
 public abstract class MouseEvent<H extends EventHandler> extends DomEvent<H> {
   /**
-   * Gets the x coordinate relative to the given element.
-   * 
-   * @param nativeEvent the native event
-   * @param relativeTo the relative element
-   * @return the relative x
-   */
-  public static int getRelativeX(Event nativeEvent, Element relativeTo) {
-    return nativeEvent.getClientX() - relativeTo.getAbsoluteLeft()
-        + relativeTo.getScrollLeft() + Window.getScrollLeft();
-  }
-
-  /**
-   * Gets the y coordinate relative to the given element.
-   * 
-   * @param nativeEvent the native event
-   * @param relativeTo the relative element
-   * @return the relative y
-   */
-  public static int getRelativeY(Event nativeEvent, Element relativeTo) {
-    return nativeEvent.getClientY() - relativeTo.getAbsoluteTop()
-        + relativeTo.getScrollTop() + Window.getScrollTop();
-  }
-
-  /**
    * Gets the mouse x-position within the browser window's client area.
    * 
    * @return the mouse x-position
@@ -70,8 +43,10 @@
   }
 
   /**
-   * Gets the button value. Compare it to {@link Event#BUTTON_LEFT},
-   * {@link Event#BUTTON_RIGHT}, {@link Event#BUTTON_MIDDLE}
+   * Gets the button value. Compare it to
+   * {@link com.google.gwt.dom.client.NativeEvent#BUTTON_LEFT},
+   * {@link com.google.gwt.dom.client.NativeEvent#BUTTON_RIGHT},
+   * {@link com.google.gwt.dom.client.NativeEvent#BUTTON_MIDDLE}
    * 
    * @return the button value
    */
@@ -80,27 +55,6 @@
   }
 
   /**
-   * Gets the x coordinate relative to the given element.
-   * 
-   * @param relativeTo the relative element
-   * @return the relative x
-   */
-  public int getRelativeX(Element relativeTo) {
-    return getRelativeX(getNativeEvent(), relativeTo);
-  }
-
-  /**
-   * Gets the y coordinate relative to the given element.
-   * 
-   * 
-   * @param relativeTo the relative element
-   * @return the relative y
-   */
-  public int getRelativeY(Element relativeTo) {
-    return getRelativeY(getNativeEvent(), relativeTo);
-  }
-
-  /**
    * Gets the mouse x-position on the user's display.
    * 
    * @return the mouse x-position
diff --git a/user/src/com/google/gwt/event/dom/client/MouseMoveEvent.java b/user/src/com/google/gwt/event/dom/client/MouseMoveEvent.java
index cafa24c..cefd26c 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseMoveEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseMoveEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native mouse move event.

  */

@@ -27,7 +25,7 @@
    * this event.

    */

   private static final Type<MouseMoveHandler> TYPE = new Type<MouseMoveHandler>(

-      Event.ONMOUSEMOVE, "mousemove", new MouseMoveEvent());

+      "mousemove", new MouseMoveEvent());

 

   /**

    * Gets the event type associated with mouse move events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire mouse move events.

    */

   protected MouseMoveEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/MouseOutEvent.java b/user/src/com/google/gwt/event/dom/client/MouseOutEvent.java
index 7b1d47e..9b89c91 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseOutEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseOutEvent.java
@@ -16,7 +16,6 @@
 package com.google.gwt.event.dom.client;

 

 import com.google.gwt.dom.client.Element;

-import com.google.gwt.user.client.Event;

 

 /**

  * Represents a native mouse out event.

@@ -28,7 +27,7 @@
    * this event.

    */

   private static final Type<MouseOutHandler> TYPE = new Type<MouseOutHandler>(

-      Event.ONMOUSEOUT, "mouseout", new MouseOutEvent());

+      "mouseout", new MouseOutEvent());

 

   /**

    * Gets the event type associated with mouse out events.

@@ -41,7 +40,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire mouse out events.

    */

   protected MouseOutEvent() {

@@ -58,8 +57,7 @@
    * @return the element from which the mouse pointer was moved

    */

   public Element getFromElement() {

-    // Use a deferred binding instead of DOMImpl's inefficient switch statement

-    return getNativeEvent().getFromElement();

+    return getNativeEvent().getTarget();

   }

 

   /**

@@ -69,7 +67,7 @@
    */

   public Element getToElement() {

     // Use a deferred binding instead of DOMImpl's inefficient switch statement

-    return getNativeEvent().getToElement();

+    return getNativeEvent().getRelatedTarget();

   }

 

   @Override

diff --git a/user/src/com/google/gwt/event/dom/client/MouseOverEvent.java b/user/src/com/google/gwt/event/dom/client/MouseOverEvent.java
index 90a664c..3306151 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseOverEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseOverEvent.java
@@ -16,7 +16,6 @@
 package com.google.gwt.event.dom.client;

 

 import com.google.gwt.dom.client.Element;

-import com.google.gwt.user.client.Event;

 

 /**

  * Represents a native mouse over event.

@@ -28,7 +27,7 @@
    * this event.

    */

   private static final Type<MouseOverHandler> TYPE = new Type<MouseOverHandler>(

-      Event.ONMOUSEOVER, "mouseover", new MouseOverEvent());

+      "mouseover", new MouseOverEvent());

 

   /**

    * Gets the event type associated with mouse over events.

@@ -41,7 +40,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire mouse over events.

    */

   protected MouseOverEvent() {

@@ -58,8 +57,7 @@
    * @return the element from which the mouse pointer was moved

    */

   public Element getFromElement() {

-    // Use a deferred binding instead of DOMImpl's inefficient switch statement

-    return getNativeEvent().getFromElement();

+    return getNativeEvent().getRelatedTarget();

   }

 

   /**

@@ -68,8 +66,7 @@
    * @return the element to which the mouse pointer was moved

    */

   public Element getToElement() {

-    // Use a deferred binding instead of DOMImpl's inefficient switch statement

-    return getNativeEvent().getToElement();

+    return getNativeEvent().getTarget();

   }

 

   @Override

diff --git a/user/src/com/google/gwt/event/dom/client/MouseUpEvent.java b/user/src/com/google/gwt/event/dom/client/MouseUpEvent.java
index 9817f07..a098ff0 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseUpEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseUpEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native mouse up event.

  */

@@ -27,7 +25,7 @@
    * this event.

    */

   private static final Type<MouseUpHandler> TYPE = new Type<MouseUpHandler>(

-      Event.ONMOUSEUP, "mouseup", new MouseUpEvent());

+      "mouseup", new MouseUpEvent());

 

   /**

    * Gets the event type associated with mouse up events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire mouse up events.

    */

   protected MouseUpEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/MouseWheelEvent.java b/user/src/com/google/gwt/event/dom/client/MouseWheelEvent.java
index d8fed04..8120a1b 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseWheelEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseWheelEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native mouse wheel event.

  */

@@ -27,7 +25,7 @@
    * this event.

    */

   private static final Type<MouseWheelHandler> TYPE = new Type<MouseWheelHandler>(

-      Event.ONMOUSEWHEEL, "mousewheel", new MouseWheelEvent(), "DOMMouseScroll");

+      "mousewheel", new MouseWheelEvent());

 

   /**

    * Gets the event type associated with mouse wheel events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire mouse wheel events.

    */

   protected MouseWheelEvent() {

diff --git a/user/src/com/google/gwt/event/dom/client/PrivateMap.java b/user/src/com/google/gwt/event/dom/client/PrivateMap.java
index 2b136b3..9f264bf 100644
--- a/user/src/com/google/gwt/event/dom/client/PrivateMap.java
+++ b/user/src/com/google/gwt/event/dom/client/PrivateMap.java
@@ -89,12 +89,12 @@
   public final V safeGet(String key) {
     return unsafeGet(":" + key);
   }
- 
+
   // ONLY use this for values that will be accessed with safeGet.
   public final void safePut(String key, V value) {
     unsafePut(":" + key, value);
   }
-  
+
   // ONLY use this for values put with unsafePut.
   public final V unsafeGet(String key) {
     if (GWT.isScript()) {
@@ -103,7 +103,7 @@
       return javaMap.get(key);
     }
   }
-  
+
   // ONLY use this for values that will be accessed with unsafeGet.
   public final void unsafePut(String key, V value) {
     if (GWT.isScript()) {
diff --git a/user/src/com/google/gwt/event/dom/client/ScrollEvent.java b/user/src/com/google/gwt/event/dom/client/ScrollEvent.java
index 21910e9..8451ce9 100644
--- a/user/src/com/google/gwt/event/dom/client/ScrollEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ScrollEvent.java
@@ -15,8 +15,6 @@
  */

 package com.google.gwt.event.dom.client;

 

-import com.google.gwt.user.client.Event;

-

 /**

  * Represents a native scroll event.

  */

@@ -27,7 +25,7 @@
    * event.

    */

   private static final Type<ScrollHandler> TYPE = new Type<ScrollHandler>(

-      Event.ONSCROLL, "scroll", new ScrollEvent());

+      "scroll", new ScrollEvent());

 

   /**

    * Gets the event type associated with scroll events.

@@ -40,7 +38,7 @@
 

   /**

    * Protected constructor, use

-   * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}

+   * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}

    * to fire scroll events.

    */

   protected ScrollEvent() {

diff --git a/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java b/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
index a482ae6..3514c6a 100644
--- a/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
@@ -34,7 +34,6 @@
    * manager.If no such handlers exist, this method will do nothing.

    * 

    * @param <I> the selected item type

-   * @param <S> The event source

    * @param source the source of the handlers

    * @param selectedItem the selected item

    */

diff --git a/user/src/com/google/gwt/event/shared/HandlerManager.java b/user/src/com/google/gwt/event/shared/HandlerManager.java
index 4123dab..f180f96 100644
--- a/user/src/com/google/gwt/event/shared/HandlerManager.java
+++ b/user/src/com/google/gwt/event/shared/HandlerManager.java
@@ -16,7 +16,6 @@
 package com.google.gwt.event.shared;
 
 import com.google.gwt.event.shared.GwtEvent.Type;
-import com.google.gwt.user.client.Command;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -28,6 +27,14 @@
  * handlers on passed in events.
  */
 public class HandlerManager {
+
+  /**
+   * Interface for queued add/remove operations.
+   */
+  private interface AddOrRemoveCommand {
+    public void execute();
+  }
+
   /**
    * Inner class used to actually contain the handlers.
    */
@@ -77,9 +84,16 @@
       return l == null ? 0 : l.size();
     }
 
+    private boolean isEventHandled(GwtEvent.Type<?> eventKey) {
+      return map.containsKey(eventKey);
+    }
+
     private <H> void removeHandler(GwtEvent.Type<H> eventKey, H handler) {
       ArrayList<H> l = get(eventKey);
       boolean result = l.remove(handler);
+      if (l.size() == 0) {
+        map.remove(eventKey);
+      }
       assert result : "Tried to remove unknown handler: " + handler + " from "
           + eventKey;
     }
@@ -95,7 +109,7 @@
   private final Object source;
 
   // Add and remove operations received during dispatch.
-  private List<Command> deferredDeltas;
+  private List<AddOrRemoveCommand> deferredDeltas;
 
   /**
    * Creates a handler manager with the given source. Handlers will be fired in
@@ -204,6 +218,16 @@
   }
 
   /**
+   * Does this handler manager handle the given event type?
+   * 
+   * @param e the event type
+   * @return whether the given event type is handled
+   */
+  public boolean isEventHandled(Type<?> e) {
+    return registry.isEventHandled(e);
+  }
+
+  /**
    * Removes the given handler from the specified event type. Normally,
    * applications should call {@link HandlerRegistration#removeHandler()}
    * instead.
@@ -236,9 +260,9 @@
     return registry.map;
   }
 
-  private void defer(Command command) {
+  private void defer(AddOrRemoveCommand command) {
     if (deferredDeltas == null) {
-      deferredDeltas = new ArrayList<Command>();
+      deferredDeltas = new ArrayList<AddOrRemoveCommand>();
     }
     deferredDeltas.add(command);
   }
@@ -255,7 +279,7 @@
 
   private <H extends EventHandler> void enqueueAdd(final GwtEvent.Type<H> type,
       final H handler) {
-    defer(new Command() {
+    defer(new AddOrRemoveCommand() {
       public void execute() {
         doAdd(type, handler);
       }
@@ -264,7 +288,7 @@
 
   private <H extends EventHandler> void enqueueRemove(
       final GwtEvent.Type<H> type, final H handler) {
-    defer(new Command() {
+    defer(new AddOrRemoveCommand() {
       public void execute() {
         doRemove(type, handler);
       }
@@ -274,7 +298,7 @@
   private void handleQueuedAddsAndRemoves() {
     if (deferredDeltas != null) {
       try {
-        for (Command c : deferredDeltas) {
+        for (AddOrRemoveCommand c : deferredDeltas) {
           c.execute();
         }
       } finally {
diff --git a/user/src/com/google/gwt/i18n/I18N.gwt.xml b/user/src/com/google/gwt/i18n/I18N.gwt.xml
index 061a67f..e84868c 100644
--- a/user/src/com/google/gwt/i18n/I18N.gwt.xml
+++ b/user/src/com/google/gwt/i18n/I18N.gwt.xml
@@ -27,7 +27,7 @@
       // Look for the locale as a url argument
       if (locale == null) {
         var args = location.search;
-        var startLang = args.indexOf("locale");
+        var startLang = args.indexOf("locale=");
         if (startLang >= 0) {
           var language = args.substring(startLang);
           var begin = language.indexOf("=") + 1;
@@ -45,6 +45,11 @@
       }
 
       if (locale == null) {
+        // Look for an override computed by other means in the selection script
+        locale = $wnd['__gwt_Locale'];
+      }
+      
+      if (locale == null) {
         return "default";
       }
 
diff --git a/user/src/com/google/gwt/i18n/client/Constants.java b/user/src/com/google/gwt/i18n/client/Constants.java
index c5be987..8417853 100644
--- a/user/src/com/google/gwt/i18n/client/Constants.java
+++ b/user/src/com/google/gwt/i18n/client/Constants.java
@@ -64,7 +64,7 @@
  * 
  * {@example com.google.gwt.examples.i18n.NumberFormatConstantsAnnot}
  * </p>
- *
+ * 
  * <p>
  * It is also possible to change the property name bound to a constant accessor
  * using the {@code @Key} annotation. For example,
@@ -152,7 +152,8 @@
  * the constant accessor <code>someMap()</code> would return a
  * <code>Map</code> that maps <code>"a"</code> onto <code>"X"</code>,
  * <code>"b"</code> onto <code>"Y"</code>, and <code>"c"</code> onto
- * <code>"Z"</code>.
+ * <code>"Z"</code>. Iterating through this <code>Map</code> will return
+ * the keys or entries in declaration order.
  * </p>
  * 
  * <p>The benefit of using annotations, aside from not having to switch to
diff --git a/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java b/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
index 0ecec17..f683e97 100644
--- a/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
+++ b/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
@@ -20,10 +20,9 @@
 import java.util.AbstractMap;
 import java.util.AbstractSet;
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
@@ -33,10 +32,62 @@
  */
 public class ConstantMap extends AbstractMap<String, String> {
 
-  /**
-   * A cache of a synthesized entry set.
-   */
-  private Set<Map.Entry<String, String>> entries;
+  private static final class EntryImpl implements Entry<String, String> {
+    private final String key;
+    private final String value;
+
+    private EntryImpl(String key, String value) {
+      assert (key != null);
+      assert (value != null);
+      this.key = key;
+      this.value = value;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (o instanceof Map.Entry) {
+        Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
+        // Key and value known to be non-null.
+        if (key.equals(other.getKey()) && value.equals(other.getValue())) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    public String getKey() {
+      return key;
+    }
+
+    public String getValue() {
+      return value;
+    }
+
+    /**
+     * Calculate the hash code using Sun's specified algorithm.
+     */
+    @Override
+    public int hashCode() {
+      int keyHash = 0;
+      int valueHash = 0;
+      if (getKey() != null) {
+        keyHash = getKey().hashCode();
+      }
+      if (getValue() != null) {
+        valueHash = getValue().hashCode();
+      }
+      return keyHash ^ valueHash;
+    }
+
+    public String setValue(String value) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString() {
+      return key + "=" + value;
+    }
+  }
 
   /**
    * The original set of keys.
@@ -56,6 +107,8 @@
     init();
 
     for (int i = 0; i < keys.length; ++i) {
+      assert keys[i] != null;
+      assert values[i] != null;
       putImpl(keys[i], values[i]);
     }
   }
@@ -67,14 +120,48 @@
 
   @Override
   public Set<Map.Entry<String, String>> entrySet() {
-    if (entries == null) {
-      Map<String, String> copy = new HashMap<String, String>();
-      for (String key : keys) {
-        copy.put(key, get(key));
+    return new AbstractSet<Entry<String, String>>() {
+      @Override
+      public boolean contains(Object o) {
+        if (!(o instanceof Entry)) {
+          return false;
+        }
+        Entry<?, ?> other = (Entry<?, ?>) o;
+        String value = get(other.getKey());
+        if (value != null && value.equals(other.getValue())) {
+          return true;
+        }
+        return false;
       }
-      entries = Collections.unmodifiableMap(copy).entrySet();
-    }
-    return entries;
+
+      @Override
+      public Iterator<Map.Entry<String, String>> iterator() {
+        return new Iterator<Entry<String, String>>() {
+          private int next = 0;
+
+          public boolean hasNext() {
+            return next < ConstantMap.this.size();
+          }
+
+          public Entry<String, String> next() {
+            if (!hasNext()) {
+              throw new NoSuchElementException();
+            }
+            String key = keys[next++];
+            return new EntryImpl(key, get(key));
+          }
+
+          public void remove() {
+            throw new UnsupportedOperationException();
+          }
+        };
+      }
+
+      @Override
+      public int size() {
+        return ConstantMap.this.size();
+      }
+    };
   }
 
   @Override
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
index a192966..ee6fa28 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
@@ -22,8 +22,8 @@
 import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
 import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
 
-import java.util.SortedMap;
-import java.util.TreeMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 /**
  * Creator for methods of the form Map getX() .
@@ -81,7 +81,8 @@
 
     String[] keys = ConstantsStringArrayMethodCreator.split(keyString);
     ResourceList resources = getResources();
-    SortedMap<String, String> map = new TreeMap<String, String>();
+    // Use a LinkedHashMap to preserve declaration order (but remove dups).
+    Map<String, String> map = new LinkedHashMap<String, String>();
     for (String key : keys) {
       if (key.length() == 0) {
         continue;
diff --git a/user/src/com/google/gwt/json/client/JSONObject.java b/user/src/com/google/gwt/json/client/JSONObject.java
index 6fd985d..bb6867a 100644
--- a/user/src/com/google/gwt/json/client/JSONObject.java
+++ b/user/src/com/google/gwt/json/client/JSONObject.java
@@ -15,11 +15,14 @@
  */
 package com.google.gwt.json.client;
 
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JavaScriptObject;
 
+import java.util.AbstractSet;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -39,7 +42,7 @@
   private final JavaScriptObject jsObject;
 
   public JSONObject() {
-    jsObject = JavaScriptObject.createObject();
+    this(JavaScriptObject.createObject());
   }
 
   /**
@@ -107,12 +110,27 @@
   }
 
   /**
-   * Returns the set of properties defined on this JSONObject.
+   * Returns the set of properties defined on this JSONObject. The returned set
+   * is immutable.
    */
   public Set<String> keySet() {
-    HashSet<String> keySet = new HashSet<String>();
-    addAllKeys(keySet);
-    return keySet;
+    final String[] keys = computeKeys();
+    return new AbstractSet<String>() {
+      @Override
+      public boolean contains(Object o) {
+        return (o instanceof String) && containsKey((String) o);
+      }
+
+      @Override
+      public Iterator<String> iterator() {
+        return Arrays.asList(keys).iterator();
+      }
+
+      @Override
+      public int size() {
+        return keys.length;
+      }
+    };
   }
 
   /**
@@ -138,7 +156,8 @@
    * Determines the number of properties on this object.
    */
   public int size() {
-    return keySet().size();
+    // Must always recheck due to foreign changes. :(
+    return computeSize();
   }
 
   /**
@@ -152,8 +171,7 @@
     StringBuffer sb = new StringBuffer();
     sb.append("{");
     boolean first = true;
-    List<String> keys = new ArrayList<String>();
-    addAllKeys(keys);
+    String[] keys = computeKeys();
     for (String key : keys) {
       if (first) {
         first = false;
@@ -180,6 +198,34 @@
     }
   }-*/;
 
+  private String[] computeKeys() {
+    if (GWT.isScript()) {
+      return computeKeys0(new String[0]);
+    } else {
+      List<String> result = new ArrayList<String>();
+      addAllKeys(result);
+      return result.toArray(new String[result.size()]);
+    }
+  }
+
+  private native String[] computeKeys0(String[] result) /*-{
+    var jsObject = this.@com.google.gwt.json.client.JSONObject::jsObject;
+    var i = 0;
+    for (var key in jsObject) {
+      result[i++] = key;
+    }
+    return result;
+  }-*/;
+
+  private native int computeSize() /*-{
+    var jsObject = this.@com.google.gwt.json.client.JSONObject::jsObject;
+    var size = 0;
+    for (var key in jsObject) {
+      ++size;
+    }
+    return size;
+  }-*/;
+
   private native JSONValue get0(String key) /*-{
     var v = this.@com.google.gwt.json.client.JSONObject::jsObject[key];
     var func = @com.google.gwt.json.client.JSONParser::typeMap[typeof v];
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index 41508b7..700acd4 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -28,6 +28,7 @@
 import com.google.gwt.dev.cfg.Properties;
 import com.google.gwt.dev.cfg.Property;
 import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.shell.CheckForUpdates;
 import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
 import com.google.gwt.junit.client.TimeoutException;
@@ -514,11 +515,11 @@
   }
 
   /**
-   * Never check for updates in JUnit mode.
+   * Check for updates once a minute.
    */
   @Override
-  protected boolean doShouldCheckForUpdates() {
-    return false;
+  protected long checkForUpdatesInterval() {
+    return CheckForUpdates.ONE_MINUTE;
   }
 
   @Override
diff --git a/user/src/com/google/gwt/user/client/BaseListenerWrapper.java b/user/src/com/google/gwt/user/client/BaseListenerWrapper.java
index 686cf20..a196bb2 100644
--- a/user/src/com/google/gwt/user/client/BaseListenerWrapper.java
+++ b/user/src/com/google/gwt/user/client/BaseListenerWrapper.java
@@ -63,7 +63,7 @@
       // The legacy EventHandler should only fire if it is on the top of the

       // stack (ie. the last one added).

       if (event.isFirstHandler()) {

-        if (!listener.onEventPreview(event.getNativeEvent())) {

+        if (!listener.onEventPreview(Event.as(event.getNativeEvent()))) {

           event.cancel();

         }

       }

diff --git a/user/src/com/google/gwt/user/client/DOM.java b/user/src/com/google/gwt/user/client/DOM.java
index 7840ff3..c781bd1 100644
--- a/user/src/com/google/gwt/user/client/DOM.java
+++ b/user/src/com/google/gwt/user/client/DOM.java
@@ -32,7 +32,7 @@
 public class DOM {
   // The current event being fired
   private static Event currentEvent = null;
-  private static final DOMImpl impl = GWT.create(DOMImpl.class);
+  static final DOMImpl impl = GWT.create(DOMImpl.class);
   private static Element sCaptureElem;
 
   /**
@@ -393,7 +393,7 @@
    * @return <code>true</code> if ALT was depressed when the event occurred
    */
   public static boolean eventGetAltKey(Event evt) {
-    return impl.eventGetAltKey(evt);
+    return evt.getAltKey();
   }
 
   /**
@@ -404,7 +404,7 @@
    *         {@link Event#BUTTON_MIDDLE}, and {@link Event#BUTTON_RIGHT}
    */
   public static int eventGetButton(Event evt) {
-    return impl.eventGetButton(evt);
+    return evt.getButton();
   }
 
   /**
@@ -414,7 +414,7 @@
    * @return the mouse x-position
    */
   public static int eventGetClientX(Event evt) {
-    return impl.eventGetClientX(evt);
+    return evt.getClientX();
   }
 
   /**
@@ -424,7 +424,7 @@
    * @return the mouse y-position
    */
   public static int eventGetClientY(Event evt) {
-    return impl.eventGetClientY(evt);
+    return evt.getClientY();
   }
 
   /**
@@ -434,7 +434,7 @@
    * @return <code>true</code> if CTRL was depressed when the event occurred
    */
   public static boolean eventGetCtrlKey(Event evt) {
-    return impl.eventGetCtrlKey(evt);
+    return evt.getCtrlKey();
   }
 
   /**
@@ -467,6 +467,7 @@
    * @param evt the event to be tested
    * @return the element from which the mouse pointer was moved
    */
+
   public static Element eventGetFromElement(Event evt) {
     return impl.eventGetFromElement(evt);
   }
@@ -485,7 +486,7 @@
    * @see com.google.gwt.user.client.ui.KeyboardListener
    */
   public static int eventGetKeyCode(Event evt) {
-    return impl.eventGetKeyCode(evt);
+    return evt.getKeyCode();
   }
 
   /**
@@ -495,7 +496,7 @@
    * @return <code>true</code> if META was depressed when the event occurred
    */
   public static boolean eventGetMetaKey(Event evt) {
-    return impl.eventGetMetaKey(evt);
+    return evt.getMetaKey();
   }
 
   /**
@@ -514,7 +515,7 @@
    * @return The velocity of the mouse wheel.
    */
   public static int eventGetMouseWheelVelocityY(Event evt) {
-    return impl.eventGetMouseWheelVelocityY(evt);
+    return evt.getMouseWheelVelocityY();
   }
 
   /**
@@ -522,7 +523,9 @@
    * 
    * @param evt the event to be tested
    * @return <code>true</code> if this key event was an auto-repeat
+   * @deprecated not supported in any browser but IE
    */
+  @Deprecated
   public static boolean eventGetRepeat(Event evt) {
     return impl.eventGetRepeat(evt);
   }
@@ -534,7 +537,7 @@
    * @return the mouse x-position
    */
   public static int eventGetScreenX(Event evt) {
-    return impl.eventGetScreenX(evt);
+    return evt.getScreenX();
   }
 
   /**
@@ -544,7 +547,7 @@
    * @return the mouse y-position
    */
   public static int eventGetScreenY(Event evt) {
-    return impl.eventGetScreenY(evt);
+    return evt.getScreenY();
   }
 
   /**
@@ -554,7 +557,7 @@
    * @return <code>true</code> if shift was depressed when the event occurred
    */
   public static boolean eventGetShiftKey(Event evt) {
-    return impl.eventGetShiftKey(evt);
+    return evt.getShiftKey();
   }
 
   /**
@@ -564,7 +567,7 @@
    * @return the target element
    */
   public static Element eventGetTarget(Event evt) {
-    return impl.eventGetTarget(evt);
+    return (Element) evt.getTarget();
   }
 
   /**
@@ -574,6 +577,7 @@
    * @param evt the event to be tested
    * @return the element to which the mouse pointer was moved
    */
+
   public static Element eventGetToElement(Event evt) {
     return impl.eventGetToElement(evt);
   }
@@ -595,7 +599,7 @@
    * @return the event's type name
    */
   public static String eventGetTypeString(Event evt) {
-    return impl.eventGetType(evt);
+    return evt.getType();
   }
 
   /**
@@ -604,7 +608,7 @@
    * @param evt the event whose default action is to be prevented
    */
   public static void eventPreventDefault(Event evt) {
-    impl.eventPreventDefault(evt);
+    evt.preventDefault();
   }
 
   /**
@@ -628,7 +632,7 @@
    * @return a string form of the event
    */
   public static String eventToString(Event evt) {
-    return impl.eventToString(evt);
+    return evt.getString();
   }
 
   /**
@@ -1264,7 +1268,6 @@
    * @param evt a handle to the event being previewed
    * @return <code>false</code> to cancel the event
    */
-  @SuppressWarnings("deprecation")
   static boolean previewEvent(Event evt) {
     // Fire a NativePreviewEvent to NativePreviewHandlers
     boolean ret = Event.fireNativePreviewEvent(evt);
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java
index 2a72281..0d633fd 100644
--- a/user/src/com/google/gwt/user/client/Event.java
+++ b/user/src/com/google/gwt/user/client/Event.java
@@ -15,8 +15,8 @@
  */
 package com.google.gwt.user.client;
 
-import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.dom.client.HasNativeEvent;
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.GwtEvent;
@@ -33,7 +33,8 @@
  * calling methods in the {@link com.google.gwt.user.client.DOM} class.
  * </p>
  */
-public class Event extends JavaScriptObject {
+public class Event extends NativeEvent {
+
   /**
    * Represents a preview of a native {@link Event}.
    */
@@ -69,8 +70,8 @@
      * @param nativeEvent the native event
      * @return true to fire the event normally, false to cancel the event
      */
-    private static boolean fire(HandlerManager handlers, Event nativeEvent) {
-      if (TYPE != null && handlers != null) {
+    private static boolean fire(HandlerManager handlers, NativeEvent nativeEvent) {
+      if (TYPE != null && handlers != null && handlers.isEventHandled(TYPE)) {
         // Revive the event
         singleton.revive();
         singleton.setNativeEvent(nativeEvent);
@@ -102,7 +103,7 @@
     /**
      * The event being previewed.
      */
-    private Event nativeEvent;
+    private NativeEvent nativeEvent;
 
     /**
      * Cancel the native event and prevent it from firing. Note that the event
@@ -130,11 +131,21 @@
       return TYPE;
     }
 
-    public Event getNativeEvent() {
+    public NativeEvent getNativeEvent() {
       return nativeEvent;
     }
 
     /**
+     * Gets the type int corresponding to the native event that triggered this
+     * preview.
+     * 
+     * @return the type int associated with this native event
+     */
+    public final int getTypeInt() {
+      return Event.as(getNativeEvent()).getTypeInt();
+    }
+
+    /**
      * Has the event already been canceled? Note that {@link #isConsumed()} will
      * still return true if the native event has also been consumed.
      * 
@@ -185,7 +196,7 @@
      * 
      * @param nativeEvent the native {@link Event} being previewed.
      */
-    private void setNativeEvent(Event nativeEvent) {
+    private void setNativeEvent(NativeEvent nativeEvent) {
       this.nativeEvent = nativeEvent;
     }
   }
@@ -203,21 +214,6 @@
   }
 
   /**
-   * The left mouse button (used in {@link DOM#eventGetButton(Event)}).
-   */
-  public static final int BUTTON_LEFT = 1;
-
-  /**
-   * The middle mouse button (used in {@link DOM#eventGetButton(Event)}).
-   */
-  public static final int BUTTON_MIDDLE = 4;
-
-  /**
-   * The right mouse button (used in {@link DOM#eventGetButton(Event)}).
-   */
-  public static final int BUTTON_RIGHT = 2;
-
-  /**
    * Fired when an element loses keyboard focus.
    */
   public static final int ONBLUR = 0x01000;
@@ -398,6 +394,25 @@
   }
 
   /**
+   * Converts the {@link NativeEvent} to Event. This is always safe.
+   * 
+   * @param event the event to downcast
+   */
+  public static Event as(NativeEvent event) {
+    return (Event) event;
+  }
+
+  /**
+   * Fire a {@link NativePreviewEvent} for the native event.
+   * 
+   * @param nativeEvent the native event
+   * @return true to fire the event normally, false to cancel the event
+   */
+  public static boolean fireNativePreviewEvent(NativeEvent nativeEvent) {
+    return NativePreviewEvent.fire(handlers, nativeEvent);
+  }
+
+  /**
    * Gets the current event that is being fired. The current event is only
    * available within the lifetime of the onBrowserEvent function. Once the
    * onBrowserEvent method returns, the current event is reset to null.
@@ -420,6 +435,40 @@
   }
 
   /**
+   * Gets the x coordinate relative to the given element.
+   * 
+   * @param nativeEvent the native event
+   * @param relativeTo the relative element
+   * @return the relative x
+   */
+  public static int getRelativeX(NativeEvent nativeEvent, Element relativeTo) {
+    return nativeEvent.getClientX() - relativeTo.getAbsoluteLeft()
+        + relativeTo.getScrollLeft() + Window.getScrollLeft();
+  }
+
+  /**
+   * Gets the y coordinate relative to the given element.
+   * 
+   * @param nativeEvent the native event
+   * @param relativeTo the relative element
+   * @return the relative y
+   */
+  public static int getRelativeY(NativeEvent nativeEvent, Element relativeTo) {
+    return nativeEvent.getClientY() - relativeTo.getAbsoluteTop()
+        + relativeTo.getScrollTop() + Window.getScrollTop();
+  }
+
+  /**
+   * Gets the enumerated type of this event given a valid event type name.
+   * 
+   * @param typeName the typeName to be tested
+   * @return the event's enumerated type
+   */
+  public static int getTypeInt(String typeName) {
+    return DOM.impl.eventGetTypeInt(typeName);
+  }
+
+  /**
    * Releases mouse capture on the given element. Calling this method has no
    * effect if the element does not currently have mouse capture.
    * 
@@ -454,6 +503,17 @@
   }
 
   /**
+   * 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}
+   */
+  public static void setEventListener(Element elem, EventListener listener) {
+    DOM.setEventListener((com.google.gwt.user.client.Element) elem, listener);
+  }
+
+  /**
    * 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.
@@ -467,16 +527,6 @@
   }
 
   /**
-   * Fire a {@link NativePreviewEvent} for the native event.
-   * 
-   * @param nativeEvent the native event
-   * @return true to fire the event normally, false to cancel the event
-   */
-  static boolean fireNativePreviewEvent(Event nativeEvent) {
-    return NativePreviewEvent.fire(handlers, nativeEvent);
-  }
-
-  /**
    * Not directly instantiable. Subclasses should also define a protected no-arg
    * constructor to prevent client code from directly instantiating the class.
    */
@@ -494,52 +544,6 @@
   }
 
   /**
-   * Gets whether the ALT key was depressed when the given event occurred.
-   * 
-   * @return <code>true</code> if ALT was depressed when the event occurred
-   */
-  public final boolean getAltKey() {
-    return DOM.eventGetAltKey(this);
-  }
-
-  /**
-   * Gets the mouse buttons that were depressed when the given event occurred.
-   * 
-   * @return a bit-field, defined by {@link Event#BUTTON_LEFT},
-   *         {@link Event#BUTTON_MIDDLE}, and {@link Event#BUTTON_RIGHT}
-   */
-  public final int getButton() {
-    return DOM.eventGetButton(this);
-  }
-
-  /**
-   * Gets the mouse x-position within the browser window's client area.
-   * 
-   * @return the mouse x-position
-   */
-  public final int getClientX() {
-    return DOM.eventGetClientX(this);
-  }
-
-  /**
-   * Gets the mouse y-position within the browser window's client area.
-   * 
-   * @return the mouse y-position
-   */
-  public final int getClientY() {
-    return DOM.eventGetClientY(this);
-  }
-
-  /**
-   * Gets whether the CTRL key was depressed when the given event occurred.
-   * 
-   * @return <code>true</code> if CTRL was depressed when the event occurred
-   */
-  public final boolean getCtrlKey() {
-    return DOM.eventGetCtrlKey(this);
-  }
-
-  /**
    * Gets the current target element of this event. This is the element whose
    * listener fired last, not the element which fired the event initially.
    * 
@@ -553,132 +557,38 @@
    * Gets the element from which the mouse pointer was moved (only valid for
    * {@link Event#ONMOUSEOVER}).
    * 
+   * @deprecated use {@link NativeEvent#getRelatedTarget()} instead
    * @return the element from which the mouse pointer was moved
    */
+  @Deprecated
   public final Element getFromElement() {
     return DOM.eventGetFromElement(this);
   }
 
   /**
-   * 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>
-   * 
-   * @return the Unicode character or key code.
-   * @see com.google.gwt.event.dom.client.KeyCodes
-   */
-  public final int getKeyCode() {
-    return DOM.eventGetKeyCode(this);
-  }
-
-  /**
-   * Gets whether the META key was depressed when the given event occurred.
-   * 
-   * @return <code>true</code> if META was depressed when the event occurred
-   */
-  public final boolean getMetaKey() {
-    return DOM.eventGetMetaKey(this);
-  }
-
-  /**
-   * 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>
-   * 
-   * @return The velocity of the mouse wheel.
-   */
-  public final int getMouseWheelVelocityY() {
-    return DOM.eventGetMouseWheelVelocityY(this);
-  }
-
-  /**
    * Gets the key-repeat state of this event.
    * 
    * @return <code>true</code> if this key event was an auto-repeat
+   * @deprecated not supported on all browsers
    */
+  @Deprecated
   public final boolean getRepeat() {
     return DOM.eventGetRepeat(this);
   }
 
   /**
-   * Gets the mouse x-position on the user's display.
-   * 
-   * @return the mouse x-position
-   */
-  public final int getScreenX() {
-    return DOM.eventGetScreenX(this);
-  }
-
-  /**
-   * Gets the mouse y-position on the user's display.
-   * 
-   * @return the mouse y-position
-   */
-  public final int getScreenY() {
-    return DOM.eventGetScreenY(this);
-  }
-
-  /**
-   * Gets whether the shift key was depressed when the given event occurred.
-   * 
-   * @return <code>true</code> if shift was depressed when the event occurred
-   */
-  public final boolean getShiftKey() {
-    return DOM.eventGetShiftKey(this);
-  }
-
-  /**
-   * Gets a string representation of this event.
-   * 
-   * We do not override {@link #toString()} because it is final in
-   * {@link JavaScriptObject}.
-   * 
-   * @return the string representation of this event
-   */
-  public final String getString() {
-    return DOM.eventToString(this);
-  }
-
-  /**
-   * Returns the element that was the actual target of the given event.
-   * 
-   * @return the target element
-   */
-  public final Element getTarget() {
-    return DOM.eventGetTarget(this);
-  }
-
-  /**
    * Gets the element to which the mouse pointer was moved (only valid for
    * {@link Event#ONMOUSEOUT}).
    * 
+   * @deprecated use {@link NativeEvent#getRelatedTarget()} instead
    * @return the element to which the mouse pointer was moved
    */
+  @Deprecated
   public final Element getToElement() {
     return DOM.eventGetToElement(this);
   }
 
   /**
-   * Gets the enumerated type of this event (as defined in {@link Event}).
-   * 
-   * @return the event's enumerated type
-   */
-  public final String getType() {
-    return DOM.eventGetTypeString(this);
-  }
-
-  /**
    * Gets the enumerated type of this event, as defined by {@link #ONCLICK},
    * {@link #ONMOUSEDOWN}, and so forth.
    * 
@@ -687,11 +597,4 @@
   public final int getTypeInt() {
     return DOM.eventGetType(this);
   }
-
-  /**
-   * Prevents the browser from taking its default action for the given event.
-   */
-  public final void preventDefault() {
-    DOM.eventPreventDefault(this);
-  }
 }
diff --git a/user/src/com/google/gwt/user/client/Timer.java b/user/src/com/google/gwt/user/client/Timer.java
index 4cbceed..dadf6c8 100644
--- a/user/src/com/google/gwt/user/client/Timer.java
+++ b/user/src/com/google/gwt/user/client/Timer.java
@@ -17,7 +17,8 @@
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
-import com.google.gwt.user.client.Window.ClosingEvent;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
 
 import java.util.ArrayList;
 
@@ -64,9 +65,9 @@
 
   private static void hookWindowClosing() {
     // Catch the window closing event.
-    Window.addWindowClosingHandler(new Window.ClosingHandler() {
+    Window.addCloseHandler(new CloseHandler<Window>() {
 
-      public void onWindowClosing(ClosingEvent event) {
+      public void onClose(CloseEvent<Window> event) {
         while (timers.size() > 0) {
           timers.get(0).cancel();
         }
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 09ffb25..a42eaa5 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
@@ -28,8 +28,8 @@
   protected static boolean eventSystemIsInitialized;
 
   /**
-   * Returns <code>true</code>if the object is an instance of EventListener
-   * and the object belongs to this module.
+   * Returns <code>true</code>if the object is an instance of EventListener and
+   * the object belongs to this module.
    */
   protected static boolean isMyListener(Object object) {
     /*
@@ -47,104 +47,53 @@
 
   public native void eventCancelBubble(Event evt, boolean cancel) /*-{
     evt.cancelBubble = cancel;
-   }-*/;
-
-  public native boolean eventGetAltKey(Event evt) /*-{
-    return !!evt.altKey;
-   }-*/;
-
-  public native int eventGetButton(Event evt) /*-{
-    return evt.button || 0;
-   }-*/;
-
-  public native int eventGetClientX(Event evt) /*-{
-    return evt.clientX || 0;
-   }-*/;
-
-  public native int eventGetClientY(Event evt) /*-{
-    return evt.clientY || 0;
-   }-*/;
-
-  public native boolean eventGetCtrlKey(Event evt) /*-{
-    return !!evt.ctrlKey;
-   }-*/;
-
+  }-*/;
+  
   public native Element eventGetCurrentTarget(Event evt) /*-{
     return evt.currentTarget;
-   }-*/;
+  }-*/;
 
   public abstract Element eventGetFromElement(Event evt);
-
-  public native int eventGetKeyCode(Event evt) /*-{
-    // 'which' gives the right key value, except when it doesn't -- in which
-    // case, keyCode gives the right value on all browsers.
-    // If all else fails, return an error code
-    return evt.which || evt.keyCode || 0;
-   }-*/;
-
-  public native boolean eventGetMetaKey(Event evt) /*-{
-    return !!evt.metaKey;
-   }-*/;
-
-  public abstract int eventGetMouseWheelVelocityY(Event evt);
-
+  
   public native boolean eventGetRepeat(Event evt) /*-{
     return !!evt.repeat;
-   }-*/;
-
-  public native int eventGetScreenX(Event evt) /*-{
-    return evt.screenX || 0;
-   }-*/;
-
-  public native int eventGetScreenY(Event evt) /*-{
-    return evt.screenY || 0;
-   }-*/;
-
-  public native boolean eventGetShiftKey(Event evt) /*-{
-    return !!evt.shiftKey;
-   }-*/;
-
-  public abstract Element eventGetTarget(Event evt);
-
+  }-*/; 
+ 
   public abstract Element eventGetToElement(Event evt);
 
-  public native String eventGetType(Event evt) /*-{
-    return evt.type;
-   }-*/;
-
-  public native int eventGetTypeInt(Event evt) /*-{
-      switch (evt.type) {
-        case "blur": return 0x01000;
-        case "change": return 0x00400;
-        case "click": return 0x00001;
-        case "dblclick": return 0x00002;
-        case "focus": return 0x00800;
-        case "keydown": return 0x00080;
-        case "keypress": return 0x00100;
-        case "keyup": return 0x00200;
-        case "load": return 0x08000;
-        case "losecapture": return 0x02000;
-        case "mousedown": return 0x00004;
-        case "mousemove": return 0x00040;
-        case "mouseout": return 0x00020;
-        case "mouseover": return 0x00010;
-        case "mouseup": return 0x00008;
-        case "scroll": return 0x04000;
-        case "error": return 0x10000;
-        case "mousewheel": return 0x20000;
-        case "DOMMouseScroll": return 0x20000;
-        case "contextmenu": return 0x40000;
-      }
-    }-*/;
-
-  public abstract void eventPreventDefault(Event evt);
-
+  public final int eventGetTypeInt(Event evt) {
+    return eventGetTypeInt(evt.getType());
+  }
+  
+  public native int eventGetTypeInt(String eventType) /*-{
+    switch (eventType) {
+    case "blur": return 0x01000;
+    case "change": return 0x00400;
+    case "click": return 0x00001;
+    case "dblclick": return 0x00002;
+    case "focus": return 0x00800;
+    case "keydown": return 0x00080;
+    case "keypress": return 0x00100;
+    case "keyup": return 0x00200;
+    case "load": return 0x08000;
+    case "losecapture": return 0x02000;
+    case "mousedown": return 0x00004;
+    case "mousemove": return 0x00040;
+    case "mouseout": return 0x00020;
+    case "mouseover": return 0x00010;
+    case "mouseup": return 0x00008;
+    case "scroll": return 0x04000;
+    case "error": return 0x10000;
+    case "mousewheel": return 0x20000;
+    case "DOMMouseScroll": return 0x20000;
+    case "contextmenu": return 0x40000;
+    }
+  }-*/; 
+  
   public native void eventSetKeyCode(Event evt, char key) /*-{
-      evt.keyCode = key;
-    }-*/;
-
-  public abstract String eventToString(Event evt);
-
+    evt.keyCode = key;
+  }-*/;
+ 
   public abstract Element getChild(Element elem, int index);
 
   public abstract int getChildCount(Element elem);
@@ -152,8 +101,8 @@
   public abstract int getChildIndex(Element parent, Element child);
 
   public native int getEventsSunk(Element elem) /*-{
-      return elem.__eventBits || 0;
-    }-*/;
+    return elem.__eventBits || 0;
+  }-*/;
 
   public abstract void insertChild(Element parent, Element child, int index);
 
@@ -169,8 +118,8 @@
   public abstract void setCapture(Element elem);
 
   public native void setEventListener(Element elem, EventListener listener) /*-{
-      elem.__listener = listener;
-    }-*/;
+    elem.__listener = listener;
+  }-*/;
 
   public abstract void sinkEvents(Element elem, int eventBits);
 
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 8cd05bf..d071853 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
@@ -41,33 +41,16 @@
 
   @Override
   public native Element eventGetFromElement(Event evt) /*-{
-    return evt.fromElement;
-  }-*/;
-
-  @Override
-  public native int eventGetMouseWheelVelocityY(Event evt) /*-{
-    return Math.round(-evt.wheelDelta / 40) || 0;
-  }-*/;
-
-  @Override
-  public native Element eventGetTarget(Event evt) /*-{
-    return evt.srcElement;
+    // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which
+    // explicitly sets relatedTarget when synthesizing mouse events).
+    return evt.relatedTarget || evt.fromElement;
   }-*/;
 
   @Override
   public native Element eventGetToElement(Event evt) /*-{
-    return evt.toElement;
-  }-*/;
-
-  @Override
-  public native void eventPreventDefault(Event evt) /*-{
-    evt.returnValue = false;
-  }-*/;
-
-  @Override
-  public native String eventToString(Event evt) /*-{
-    if (evt.toString) return evt.toString();
-      return "[object Event]";
+    // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which
+    // explicitly sets relatedTarget when synthesizing mouse events).
+    return evt.relatedTarget || evt.toElement;
   }-*/;
 
   @Override
@@ -125,7 +108,7 @@
 
     @com.google.gwt.user.client.impl.DOMImplIE6::dispatchDblClickEvent = function() {
       var newEvent = $doc.createEventObject();
-      this.fireEvent('onclick', newEvent);
+      $wnd.event.srcElement.fireEvent('onclick', newEvent);
       if (this.__eventBits & 2) {
         @com.google.gwt.user.client.impl.DOMImplIE6::dispatchEvent.call(this);
       }
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 20892b7..a647aa1 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
@@ -16,7 +16,6 @@
 package com.google.gwt.user.client.impl;
 
 import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
 
 /**
  * Mozilla implementation of StandardBrowser.
@@ -24,11 +23,6 @@
 class DOMImplMozilla extends DOMImplStandard {
 
   @Override
-  public native int eventGetMouseWheelVelocityY(Event evt) /*-{
-    return evt.detail || 0;
-  }-*/;
-
-  @Override
   public void sinkEvents(Element elem, int bits) {
     super.sinkEvents(elem, bits);
     sinkEventsMozilla(elem, bits);
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 d94dbc8..8261d77 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
@@ -16,18 +16,11 @@
 package com.google.gwt.user.client.impl;
 
 import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
 
 /**
  * Opera implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
  */
 public class DOMImplOpera extends DOMImplStandard {
-
-  @Override
-  public native int eventGetMouseWheelVelocityY(Event evt) /*-{
-    return evt.detail * 4 || 0;
-  }-*/;
-
   /**
    * As Opera sinks events very quickly, adding guards to prevent the sinking of
    * events actually slows Opera down.
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 1b7e3b55..16ab0ed 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 2008 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
@@ -15,47 +15,8 @@
  */
 package com.google.gwt.user.client.impl;
 
-import com.google.gwt.user.client.Event;
-
 /**
  * Safari implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
  */
 class DOMImplSafari extends DOMImplStandard {
-
-  @Override
-  public native int eventGetClientX(Event evt) /*-{
-    // In Safari2: clientX is wrong and pageX is returned instead.
-    // $wnd.devicePixelRatio identifies Safari 3 from Safari 2
-    if ($wnd.devicePixelRatio) {
-      return evt.clientX || 0;
-    } else {
-      // Subtract the margin and border of the HTML element in Safari 2 
-      // TODO: Remove this code when we drop Safari 2 support
-      var style = document.defaultView.getComputedStyle($doc.getElementsByTagName('html')[0], '');
-      return evt.pageX - $doc.body.scrollLeft
-          - parseInt(style.getPropertyValue('margin-left'))
-          - parseInt(style.getPropertyValue('border-left-width')) || 0;
-    }
-  }-*/;
-
-  @Override
-  public native int eventGetClientY(Event evt) /*-{
-    // In Safari2: clientY is wrong and pageY is returned instead.
-    // $wnd.devicePixelRatio identifies Safari 3 from Safari 2
-    if ($wnd.devicePixelRatio) {
-      return evt.clientY || 0;
-    } else {
-      // Subtract the margin and border of the HTML element in Safari 2 
-      // TODO: Remove this code when we drop Safari 2 support
-      var style = document.defaultView.getComputedStyle($doc.getElementsByTagName('html')[0], '');
-      return evt.pageY - $doc.body.scrollTop
-          - parseInt(style.getPropertyValue('margin-top'))
-          - parseInt(style.getPropertyValue('border-top-width')) || 0;
-    }
-  }-*/;
-
-  @Override
-  public native int eventGetMouseWheelVelocityY(Event evt) /*-{
-    return Math.round(-evt.wheelDelta / 40) || 0;
-  }-*/;
 }
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 5d2be3c..3fa1553 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
@@ -39,19 +39,6 @@
   private static JavaScriptObject dispatchEvent;
 
   @Override
-  public native int eventGetButton(Event evt) /*-{
-    // Standard browsers and IE disagree on what the button codes for buttons
-    // should be.  Translating to match IE standard.
-    var button = evt.which;
-    if(button == 2) {
-      return 4;
-    } else if (button == 3) {
-      return 2;
-    }
-    return button || 0;
-  }-*/;
-
-  @Override
   public native Element eventGetFromElement(Event evt) /*-{
     if (evt.type == "mouseover")
       return evt.relatedTarget;
@@ -59,12 +46,7 @@
       return evt.target;
     return null;  
   }-*/;
-
-  @Override
-  public native Element eventGetTarget(Event evt) /*-{
-    return evt.target;
-  }-*/;
-
+ 
   @Override
   public native Element eventGetToElement(Event evt) /*-{
     if (evt.type == "mouseover")
@@ -73,17 +55,7 @@
       return evt.relatedTarget;
     return null;
   }-*/;
-
-  @Override
-  public native void eventPreventDefault(Event evt) /*-{
-    evt.preventDefault();
-  }-*/;
-
-  @Override
-  public native String eventToString(Event evt) /*-{
-    return evt.toString();
-  }-*/;
-
+  
   @Override
   public native Element getChild(Element elem, int index) /*-{
     var count = 0, child = elem.firstChild;
diff --git a/user/src/com/google/gwt/user/client/ui/Button.java b/user/src/com/google/gwt/user/client/ui/Button.java
index e571bbd..33d17f4 100644
--- a/user/src/com/google/gwt/user/client/ui/Button.java
+++ b/user/src/com/google/gwt/user/client/ui/Button.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dom.client.ButtonElement;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.ButtonElement;
 import com.google.gwt.event.dom.client.ClickHandler;
 
 /**
@@ -71,10 +72,6 @@
     }
   }-*/;
 
-  static native void click(Element button) /*-{
-    button.click();
-  }-*/;
-
   /**
    * Creates a button with no caption.
    */
@@ -133,6 +130,11 @@
    * Programmatic equivalent of the user clicking the button.
    */
   public void click() {
-    click(getElement());
+    getButtonElement().click();
+  }
+
+  private ButtonElement getButtonElement() {
+    return getElement().cast();
   }
 }
+
diff --git a/user/src/com/google/gwt/user/client/ui/CheckBox.java b/user/src/com/google/gwt/user/client/ui/CheckBox.java
index 7aad9ba..40386ff 100644
--- a/user/src/com/google/gwt/user/client/ui/CheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/CheckBox.java
@@ -303,11 +303,12 @@
       throw new IllegalArgumentException("value must not be null");
     }
 
-    if (value.equals(getValue())) {
-      return;
-    }
+    Boolean oldValue = getValue();
     inputElem.setChecked(value);
     inputElem.setDefaultChecked(value);
+    if (value.equals(oldValue)) {
+      return;
+    }
     if (fireEvents) {
       ValueChangeEvent.fire(this, value);
     }
diff --git a/user/src/com/google/gwt/user/client/ui/CustomButton.java b/user/src/com/google/gwt/user/client/ui/CustomButton.java
index 89efb9b..a59978a 100644
--- a/user/src/com/google/gwt/user/client/ui/CustomButton.java
+++ b/user/src/com/google/gwt/user/client/ui/CustomButton.java
@@ -16,6 +16,8 @@
 
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.dom.client.Document;
+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.user.client.DOM;
@@ -316,6 +318,12 @@
   private boolean isFocusing;
 
   /**
+   * Used to decide whether to allow clicks to propagate up to the superclass
+   * or container elements.
+   */
+  private boolean allowClick;
+
+  /**
    * Constructor for <code>CustomButton</code>.
    * 
    * @param upImage image for the default (up) face of the button
@@ -575,6 +583,14 @@
 
     int type = DOM.eventGetType(event);
     switch (type) {
+      case Event.ONCLICK:
+        // If clicks are currently disallowed, keep it from bubbling or being
+        // passed to the superclass.
+        if (!allowClick) {
+          event.stopPropagation();
+          return;
+        }
+        break;
       case Event.ONMOUSEDOWN:
         if (event.getButton() == Event.BUTTON_LEFT) {
           setFocus(true);
@@ -618,9 +634,6 @@
           }
         }
         break;
-      case Event.ONCLICK:
-        // we handle clicks ourselves
-        return;
       case Event.ONBLUR:
         if (isFocusing) {
           isFocusing = false;
@@ -748,7 +761,18 @@
    * widget display.
    */
   protected void onClick() {
-    fireClickListeners(null);
+    // Allow the click we're about to synthesize to pass through to the
+    // superclass and containing elements. Element.dispatchEvent() is
+    // synchronous, so we simply set and clear the flag within this method.
+    allowClick = true;
+
+    // Mouse coordinates are not always available (e.g., when the click is
+    // caused by a keyboard event).
+    NativeEvent evt = Document.get().createClickEvent(1, 0, 0, 0, 0, false,
+        false, false, false);
+    getElement().dispatchEvent(evt);
+
+    allowClick = false;
   }
 
   /**
diff --git a/user/src/com/google/gwt/user/client/ui/DialogBox.java b/user/src/com/google/gwt/user/client/ui/DialogBox.java
index e1d3e34..a5bde38 100644
--- a/user/src/com/google/gwt/user/client/ui/DialogBox.java
+++ b/user/src/com/google/gwt/user/client/ui/DialogBox.java
@@ -16,6 +16,7 @@
 package com.google.gwt.user.client.ui;
 
 import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.dom.client.HasAllMouseHandlers;
 import com.google.gwt.event.dom.client.MouseDownEvent;
 import com.google.gwt.event.dom.client.MouseDownHandler;
@@ -45,10 +46,11 @@
  * <img class='gallery' src='DialogBox.png'/>
  * </p>
  * <h3>CSS Style Rules</h3>
- * <ul class='css'>
+ * 
+ * <ul>
  * <li>.gwt-DialogBox { the outside of the dialog }</li>
  * <li>.gwt-DialogBox .Caption { the caption }</li>
- * <li>.gwt-DialogBox .dialogContent { the wrapepr around the content }</li>
+ * <li>.gwt-DialogBox .dialogContent { the wrapper around the content }</li>
  * <li>.gwt-DialogBox .dialogTopLeft { the top left cell }</li>
  * <li>.gwt-DialogBox .dialogTopLeftInner { the inner element of the cell }</li>
  * <li>.gwt-DialogBox .dialogTopCenter { the top center cell, where the caption
@@ -60,15 +62,18 @@
  * <li>.gwt-DialogBox .dialogMiddleLeftInner { the inner element of the cell }</li>
  * <li>.gwt-DialogBox .dialogMiddleCenter { the middle center cell, where the
  * content is located }</li>
- * <li>.gwt-DialogBox .dialogMiddleCenterInner { the inner element of the cell }</li>
+ * <li>.gwt-DialogBox .dialogMiddleCenterInner { the inner element of the cell }
+ * </li>
  * <li>.gwt-DialogBox .dialogMiddleRight { the middle right cell }</li>
  * <li>.gwt-DialogBox .dialogMiddleRightInner { the inner element of the cell }</li>
  * <li>.gwt-DialogBox .dialogBottomLeft { the bottom left cell }</li>
  * <li>.gwt-DialogBox .dialogBottomLeftInner { the inner element of the cell }</li>
  * <li>.gwt-DialogBox .dialogBottomCenter { the bottom center cell }</li>
- * <li>.gwt-DialogBox .dialogBottomCenterInner { the inner element of the cell }</li>
+ * <li>.gwt-DialogBox .dialogBottomCenterInner { the inner element of the cell }
+ * </li>
  * <li>.gwt-DialogBox .dialogBottomRight { the bottom right cell }</li>
  * <li>.gwt-DialogBox .dialogBottomRightInner { the inner element of the cell }</li>
+ * </ul>
  * <p>
  * <h3>Example</h3>
  * {@example com.google.gwt.examples.DialogBoxExample}
@@ -79,7 +84,7 @@
     MouseListener {
   /**
    * Set of characteristic interfaces supported by the {@link DialogBox} caption
-   *
+   * 
    * Note that this set might expand over time, so implement this interface at
    * your own risk.
    */
@@ -141,7 +146,7 @@
    * {@link #add(Widget)}.
    * 
    * @param autoHide <code>true</code> if the dialog should be automatically
-   * hidden when the user clicks outside of it
+   *          hidden when the user clicks outside of it
    */
   public DialogBox(boolean autoHide) {
     this(autoHide, true);
@@ -153,9 +158,9 @@
    * {@link #add(Widget)}.
    * 
    * @param autoHide <code>true</code> if the dialog should be automatically
-   * hidden when the user clicks outside of it
+   *          hidden when the user clicks outside of it
    * @param modal <code>true</code> if keyboard and mouse events for widgets not
-   * contained by the dialog should be ignored
+   *          contained by the dialog should be ignored
    */
   public DialogBox(boolean autoHide, boolean modal) {
     super(autoHide, modal, "dialog");
@@ -184,10 +189,10 @@
 
   /**
    * Provides access to the dialog's caption.
-   *
+   * 
    * This method is final because the Caption interface will expand. Therefore
-   * it is highly likely that subclasses which implemented this method would end up
-   * breaking.
+   * it is highly likely that subclasses which implemented this method would end
+   * up breaking.
    * 
    * @return the logical caption for this dialog box
    */
@@ -232,7 +237,7 @@
 
   /**
    * @deprecated Use {@link #beginDragging} instead and {@link #getCaption}
-   * instead
+   *             instead
    */
   @Deprecated
   public void onMouseDown(Widget sender, int x, int y) {
@@ -324,8 +329,8 @@
    * @param event the mouse down event that triggered dragging
    */
   protected void beginDragging(MouseDownEvent event) {
-    onMouseDown(caption, event.getRelativeX(getElement()),
-        event.getRelativeY(getElement()));
+    onMouseDown(caption, Event.getRelativeX(event.getNativeEvent(),
+        getElement()), Event.getRelativeY(event.getNativeEvent(), getElement()));
   }
 
   /**
@@ -337,8 +342,8 @@
    * @param event the mouse move event that continues dragging
    */
   protected void continueDragging(MouseMoveEvent event) {
-    onMouseMove(caption, event.getRelativeX(getElement()),
-        event.getRelativeY(getElement()));
+    onMouseMove(caption, Event.getRelativeX(event.getNativeEvent(),
+        getElement()), Event.getRelativeY(event.getNativeEvent(), getElement()));
   }
 
   @Override
@@ -363,15 +368,17 @@
   /**
    * Called on mouse up in the caption area, ends dragging by ending event
    * capture.
-   * @param event  the mouse up event that ended dragging
+   * 
+   * @param event the mouse up event that ended dragging
    * 
    * @see DOM#releaseCapture
    * @see #beginDragging
    * @see #endDragging
    */
   protected void endDragging(MouseUpEvent event) {
-    onMouseUp(caption, event.getRelativeX(getElement()),
-        event.getRelativeY(getElement()));
+    onMouseUp(caption,
+        Event.getRelativeX(event.getNativeEvent(), getElement()),
+        Event.getRelativeY(event.getNativeEvent(), getElement()));
   }
 
   /**
@@ -395,8 +402,10 @@
     // We need to preventDefault() on mouseDown events (outside of the
     // DialogBox content) to keep text from being selected when it
     // is dragged.
-    Event nativeEvent = event.getNativeEvent();
-    if (!event.isCanceled() && nativeEvent.getTypeInt() == Event.ONMOUSEDOWN
+    NativeEvent nativeEvent = event.getNativeEvent();
+
+    if (!event.isCanceled()
+        && (event.getTypeInt() == Event.ONMOUSEDOWN)
         && isCaptionEvent(nativeEvent)) {
       nativeEvent.preventDefault();
     }
@@ -404,7 +413,7 @@
     super.onPreviewNativeEvent(event);
   }
 
-  private boolean isCaptionEvent(Event event) {
+  private boolean isCaptionEvent(NativeEvent event) {
     return getCellElement(0, 1).getParentElement().isOrHasChild(
         event.getTarget());
   }
diff --git a/user/src/com/google/gwt/user/client/ui/FlexTable.java b/user/src/com/google/gwt/user/client/ui/FlexTable.java
index b2ecb0a..402bf81 100644
--- a/user/src/com/google/gwt/user/client/ui/FlexTable.java
+++ b/user/src/com/google/gwt/user/client/ui/FlexTable.java
@@ -98,7 +98,7 @@
       var cell = $doc.createElement("td");
       rowElem.appendChild(cell);  
     }
- }-*/;
+  }-*/;
 
   public FlexTable() {
     super();
@@ -172,9 +172,6 @@
     return super.insertRow(beforeRow);
   }
 
-  /**
-   * @see com.google.gwt.user.client.ui.HTMLTable#removeCell(int, int)
-   */
   @Override
   public void removeCell(int row, int col) {
     super.removeCell(row, col);
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 51eb0a3..41066ff 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLTable.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
@@ -700,7 +700,7 @@
    * @param listener listener to add
    * @deprecated add a click handler instead and use
    *             {@link HTMLTable#getCellForEvent(ClickEvent)} to get the cell
-   *             information
+   *             information (remember to check for a null return value)
    */
   @Deprecated
   public void addTableListener(TableListener listener) {
@@ -748,13 +748,14 @@
 
   /**
    * Given a click event, return the Cell that was clicked, or null if the event
-   * did not hit this table.
+   * did not hit this table.  The cell can also be null if the click event does
+   * not occur on a specific cell.
    * 
    * @param event A click event of indeterminate origin
    * @return The appropriate cell, or null
    */
   public Cell getCellForEvent(ClickEvent event) {
-    Element td = getEventTargetCell(event.getNativeEvent());
+    Element td = getEventTargetCell(Event.as(event.getNativeEvent()));
     if (td == null) {
       return null;
     }
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 ee62223..e3bc47e 100644
--- a/user/src/com/google/gwt/user/client/ui/Image.java
+++ b/user/src/com/google/gwt/user/client/ui/Image.java
@@ -42,8 +42,6 @@
 import com.google.gwt.event.dom.client.MouseWheelEvent;
 import com.google.gwt.event.dom.client.MouseWheelHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.impl.ClippedImageImpl;
 
@@ -66,10 +64,7 @@
  * will be lost.
  * </p>
  * 
- * <h3>CSS Style Rules</h3>
- * <ul class="css">
- * <li>.gwt-Image { }</li>
- * </ul>
+ * <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
@@ -113,8 +108,8 @@
       image.replaceElement(impl.createStructure(url, left, top, width, height));
       // Todo(ecc) This is wrong, we should not be sinking these here on such a
       // common widget.After the branch is stable, this should be fixed.
-      image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL);
-      fireSyntheticLoadEvent(image);
+      image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL
+          | Event.ONLOAD);
     }
 
     @Override
@@ -160,7 +155,7 @@
         this.height = height;
 
         impl.adjust(image.getElement(), url, left, top, width, height);
-        fireSyntheticLoadEvent(image);
+        impl.fireSyntheticLoadEvent(image);
       }
     }
 
@@ -181,7 +176,7 @@
         this.height = height;
 
         impl.adjust(image.getElement(), url, left, top, width, height);
-        fireSyntheticLoadEvent(image);
+        impl.fireSyntheticLoadEvent(image);
       }
     }
 
@@ -190,30 +185,6 @@
     protected String getStateName() {
       return "clipped";
     }
-
-    private void fireSyntheticLoadEvent(final Image image) {
-      /*
-       * We need to synthesize a load event, because the native events that are
-       * fired would correspond to the loading of clear.cache.gif, which is
-       * incorrect. A native event would not even fire in Internet Explorer,
-       * 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
-       * event handler.
-       */
-      DeferredCommand.addCommand(new Command() {
-        public void execute() {
-          // TODO(ecc) once event triggering is committed, this call should
-          // fire a native load event instead.
-          image.fireEvent(new LoadEvent() {
-          });
-        }
-      });
-    }
   }
 
   /**
@@ -251,16 +222,20 @@
   private static class UnclippedState extends State {
 
     UnclippedState(Element element) {
-      // Todo(ecc) This is wrong, we should not be sinking these here on such a
-      // common widget.After the branch is stable, this should be fixed.
+      // This case is relatively unusual, in that we swapped a clipped image
+      // out, so does not need to be efficient.
       Event.sinkEvents(element, Event.ONCLICK | Event.MOUSEEVENTS
           | Event.ONLOAD | Event.ONERROR | Event.ONMOUSEWHEEL);
     }
 
     UnclippedState(Image image) {
       image.replaceElement(Document.get().createImageElement());
-      // Todo(ecc) This is wrong, we should not be sinking these here on such a
-      // common widget.After the branch is stable, this should be fixed.
+      // We are working around an IE race condition that can make the image
+      // incorrectly cache itself if the load event is assigned at the same time
+      // as the image is added to the dom.
+      Event.sinkEvents(image.getElement(), Event.ONLOAD);
+
+      // Todo(ecc) this could be more efficient overall.
       image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONLOAD
           | Event.ONERROR | Event.ONMOUSEWHEEL);
     }
diff --git a/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
index ed2aff7..a3a5435 100644
--- a/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
+++ b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
@@ -80,6 +80,7 @@
 import com.google.gwt.event.shared.HandlerManager;

 import com.google.gwt.event.shared.GwtEvent.Type;

 import com.google.gwt.user.client.BaseListenerWrapper;

+import com.google.gwt.user.client.Event;

 

 import java.util.EventListener;

 

@@ -98,8 +99,8 @@
   /**

    * Wrapper for a {@link LoadListener}.

    */

-  public static class WrappedLoadListener extends ListenerWrapper<LoadListener> implements

-      LoadHandler, ErrorHandler {

+  public static class WrappedLoadListener extends ListenerWrapper<LoadListener>

+      implements LoadHandler, ErrorHandler {

 

     /**

      * Adds the wrapped listener.

@@ -341,14 +342,14 @@
       getListener().onKeyDown(

           getSource(event),

           (char) event.getNativeKeyCode(),

-          KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));

+          KeyboardListenerCollection.getKeyboardModifiers(Event.as(event.getNativeEvent())));

     }

 

     public void onKeyPress(KeyPressEvent event) {

       getListener().onKeyPress(

           getSource(event),

           (char) event.getNativeEvent().getKeyCode(),

-          KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));

+          KeyboardListenerCollection.getKeyboardModifiers(Event.as(event.getNativeEvent())));

     }

 

     public void onKeyUp(KeyUpEvent event) {

@@ -356,7 +357,7 @@
       getListener().onKeyUp(

           getSource(event),

           (char) event.getNativeKeyCode(),

-          KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));

+          KeyboardListenerCollection.getKeyboardModifiers(Event.as(event.getNativeEvent())));

     }

   }

 

@@ -463,15 +464,17 @@
     public void onMouseDown(MouseDownEvent event) {

       Widget source = getSource(event);

       Element elem = source.getElement();

-      getListener().onMouseDown(source, event.getRelativeX(elem),

-          event.getRelativeY(elem));

+      getListener().onMouseDown(source,

+          Event.getRelativeX(event.getNativeEvent(), elem),

+          Event.getRelativeY(event.getNativeEvent(), elem));

     }

 

     public void onMouseMove(MouseMoveEvent event) {

       Widget source = getSource(event);

       Element elem = source.getElement();

-      getListener().onMouseMove(source, event.getRelativeX(elem),

-          event.getRelativeY(elem));

+      getListener().onMouseMove(source,

+          Event.getRelativeX(event.getNativeEvent(), elem),

+          Event.getRelativeY(event.getNativeEvent(), elem));

     }

 

     public void onMouseOut(MouseOutEvent event) {

@@ -485,8 +488,9 @@
     public void onMouseUp(MouseUpEvent event) {

       Widget source = getSource(event);

       Element elem = source.getElement();

-      getListener().onMouseUp(source, event.getRelativeX(elem),

-          event.getRelativeY(elem));

+      getListener().onMouseUp(source,

+          Event.getRelativeX(event.getNativeEvent(), elem),

+          Event.getRelativeY(event.getNativeEvent(), elem));

     }

   }

   /**

@@ -530,7 +534,7 @@
 

     public void onMouseWheel(MouseWheelEvent event) {

       getListener().onMouseWheel(getSource(event),

-          new MouseWheelVelocity(event.getNativeEvent()));

+          new MouseWheelVelocity(Event.as(event.getNativeEvent())));

     }

   }

   /**

@@ -708,8 +712,10 @@
     public void onClick(ClickEvent event) {

       HTMLTable table = (HTMLTable) event.getSource();

       HTMLTable.Cell cell = table.getCellForEvent(event);

-      getListener().onCellClicked(table, cell.getRowIndex(),

-          cell.getCellIndex());

+      if (cell != null) {

+        getListener().onCellClicked(table, cell.getRowIndex(),

+            cell.getCellIndex());

+      }

     }

   }

 

diff --git a/user/src/com/google/gwt/user/client/ui/MenuBar.java b/user/src/com/google/gwt/user/client/ui/MenuBar.java
index 0bf2173..a9fa5b3 100644
--- a/user/src/com/google/gwt/user/client/ui/MenuBar.java
+++ b/user/src/com/google/gwt/user/client/ui/MenuBar.java
@@ -979,8 +979,7 @@
     // clear the selection; a keyboard user can cursor down to the first item
     selectItem(null);
   }
-
-  @SuppressWarnings("deprecation")
+ 
   private void openPopup(final MenuItem item) {
     // Only the last popup to be opened should preview all event
     if (parentMenu != null && parentMenu.popup != null) {
@@ -1002,12 +1001,12 @@
         // Hook the popup panel's event preview. We use this to keep it from
         // auto-hiding when the parent menu is clicked.
         if (!event.isCanceled()) {
-          Event nativeEvent = event.getNativeEvent();
-          switch (nativeEvent.getTypeInt()) {
+
+          switch (event.getTypeInt()) {
             case Event.ONMOUSEDOWN:
               // If the event target is part of the parent menu, suppress the
               // event altogether.
-              com.google.gwt.dom.client.Element target = nativeEvent.getTarget();
+              com.google.gwt.dom.client.Element target = event.getNativeEvent().getTarget();
               Element parentMenuElement = item.getParentMenu().getElement();
               if (parentMenuElement.isOrHasChild(target)) {
                 event.cancel();
diff --git a/user/src/com/google/gwt/user/client/ui/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
index 986f45a..8155ae4 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -19,6 +19,7 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.logical.shared.CloseEvent;
 import com.google.gwt.event.logical.shared.CloseHandler;
 import com.google.gwt.event.logical.shared.HasCloseHandlers;
@@ -462,14 +463,10 @@
    *          {@link CloseHandler#onClose(CloseEvent)} when the popup is closed
    */
   public void hide(boolean autoClosed) {
-    if (!showing) {
+    if (!isShowing()) {
       return;
     }
-    showing = false;
-    if (nativePreviewHandlerRegistration != null) {
-      nativePreviewHandlerRegistration.removeHandler();
-      nativePreviewHandlerRegistration = null;
-    }
+    cleanup();
 
     // Hide the popup
     resizeAnimation.setState(false);
@@ -588,6 +585,14 @@
     return true;
   }
 
+  @Override
+  protected void onUnload() {
+    // Just to be sure, we perform cleanup when the popup is unloaded (i.e.
+    // removed from the DOM). This is normally taken care of in hide(), but it
+    // can be missed if someone removes the popup directly from the RootPanel.
+    cleanup();
+  }
+
   /**
    * Remove an autoHide partner.
    * 
@@ -822,14 +827,11 @@
   protected com.google.gwt.user.client.Element getStyleElement() {
     return impl.getStyleElement(getPopupImplElement());
   }
-
-  /**
-   * @see NativePreviewHandler#onPreviewNativeEvent(NativePreviewEvent)
-   */
-  @SuppressWarnings("deprecation")
+ 
   protected void onPreviewNativeEvent(NativePreviewEvent event) {
     // Cancel the event based on the deprecated onEventPreview() method
-    if (event.isFirstHandler() && !onEventPreview(event.getNativeEvent())) {
+    if (event.isFirstHandler()
+        && !onEventPreview(Event.as(event.getNativeEvent()))) {
       event.cancel();
     }
   }
@@ -892,13 +894,23 @@
     }
   }-*/;
 
+  private void cleanup() {
+    // Clear the 'showing' flag and make sure that the event preview is cleaned
+    // up.
+    showing = false;
+    if (nativePreviewHandlerRegistration != null) {
+      nativePreviewHandlerRegistration.removeHandler();
+      nativePreviewHandlerRegistration = null;
+    }
+  }
+
   /**
    * Does the event target one of the partner elements?
    * 
    * @param event the native event
    * @return true if the event targets a partner
    */
-  private boolean eventTargetsPartner(Event event) {
+  private boolean eventTargetsPartner(NativeEvent event) {
     if (autoHidePartners == null) {
       return false;
     }
@@ -918,7 +930,7 @@
    * @param event the native event
    * @return true if the event targets the popup
    */
-  private boolean eventTargetsPopup(Event event) {
+  private boolean eventTargetsPopup(NativeEvent event) {
     return getElement().isOrHasChild(event.getTarget());
   }
 
@@ -1087,7 +1099,7 @@
     }
 
     // If the event targets the popup or the partner, consume it
-    Event nativeEvent = event.getNativeEvent();
+    Event nativeEvent = Event.as(event.getNativeEvent());
     boolean eventTargetsPopupOrPartner = eventTargetsPopup(nativeEvent)
         || eventTargetsPartner(nativeEvent);
     if (eventTargetsPopupOrPartner) {
diff --git a/user/src/com/google/gwt/user/client/ui/PushButton.java b/user/src/com/google/gwt/user/client/ui/PushButton.java
index 3872d11..daad75d 100644
--- a/user/src/com/google/gwt/user/client/ui/PushButton.java
+++ b/user/src/com/google/gwt/user/client/ui/PushButton.java
@@ -96,6 +96,17 @@
    * 
    * @param upImage image for the default(up) face of the button
    * @param downImage image for the down face of the button
+   * @param handler the click handler
+   */
+  public PushButton(Image upImage, Image downImage, ClickHandler handler) {
+    super(upImage, downImage, handler);
+  }
+
+  /**
+   * Constructor for <code>PushButton</code>.
+   * 
+   * @param upImage image for the default(up) face of the button
+   * @param downImage image for the down face of the button
    * @param listener clickListener
    */
   @Deprecated
diff --git a/user/src/com/google/gwt/user/client/ui/SourcesKeyboardEvents.java b/user/src/com/google/gwt/user/client/ui/SourcesKeyboardEvents.java
index 37f0ff2..78e1052 100644
--- a/user/src/com/google/gwt/user/client/ui/SourcesKeyboardEvents.java
+++ b/user/src/com/google/gwt/user/client/ui/SourcesKeyboardEvents.java
@@ -20,7 +20,7 @@
  * {@link com.google.gwt.user.client.ui.KeyboardListener} interface.
  * 
  * @deprecated use
- *             {@link com.google.gwt.com.google.gwt.event.dom.client.HasAllKeyHandlers}
+ *             {@link com.google.gwt.event.dom.client.HasAllKeyHandlers}
  *             instead
  */
 @Deprecated
diff --git a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
index 9fbad0c..d143c8b 100644
--- a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
+++ b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
@@ -19,6 +19,7 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.dom.client.HasChangeHandlers;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
@@ -31,7 +32,7 @@
  */
 @SuppressWarnings("deprecation")
 public class TextBoxBase extends FocusWidget implements SourcesChangeEvents,
-    HasText, HasName, HasValue<String> {
+    HasChangeHandlers, HasText, HasName, HasValue<String> {
 
   /**
    * Text alignment constant, used in
@@ -88,9 +89,13 @@
     super(elem);
   }
 
+  public HandlerRegistration addChangeHandler(ChangeHandler handler) {
+    return addDomHandler(handler, ChangeEvent.getType());
+  }
+
   @Deprecated
   public void addChangeListener(ChangeListener listener) {
-    addDomHandler(new ListenerWrapper.WrappedChangeListener(listener), ChangeEvent.getType());
+    addChangeHandler(new ListenerWrapper.WrappedChangeListener(listener));
   }
 
   public HandlerRegistration addValueChangeHandler(
@@ -98,11 +103,11 @@
     // Initialization code
     if (!valueChangeHandlerInitialized) {
       valueChangeHandlerInitialized = true;
-      addDomHandler(new ChangeHandler() {
+      addChangeHandler(new ChangeHandler() {
         public void onChange(ChangeEvent event) {
           ValueChangeEvent.fire(TextBoxBase.this, getText());
         }
-      }, ChangeEvent.getType());
+      });
     }
     return addHandler(handler, ValueChangeEvent.getType());
   }
diff --git a/user/src/com/google/gwt/user/client/ui/Tree.java b/user/src/com/google/gwt/user/client/ui/Tree.java
index 9dff280..0f96566 100644
--- a/user/src/com/google/gwt/user/client/ui/Tree.java
+++ b/user/src/com/google/gwt/user/client/ui/Tree.java
@@ -516,8 +516,7 @@
           // The click event should have given focus to this element already.
           // Avoid moving focus back up to the tree (so that focusable widgets
           // attached to TreeItems can receive keyboard events).
-        } else if (curSelection != null
-            && curSelection.getContentElem().isOrHasChild(e)) {
+        } else if (curSelection != null) {
           setFocus(true);
         }
         break;
@@ -929,7 +928,7 @@
     DOM.setIntStyleAttribute(focusable, "zIndex", -1);
     DOM.appendChild(getElement(), focusable);
 
-    sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK | Event.KEYEVENTS);
+    sinkEvents(Event.ONMOUSEDOWN | Event.ONCLICK | Event.KEYEVENTS);
     DOM.sinkEvents(focusable, Event.FOCUSEVENTS);
 
     // The 'root' item is invisible and serves only as a container
@@ -1154,9 +1153,10 @@
     }
     curSelection = item;
 
-    if (moveFocus && curSelection != null) {
-      moveFocus();
-
+    if (curSelection != null) {
+      if (moveFocus) {
+        moveFocus();
+      }
       // Select the item and fire the selection event.
       curSelection.setSelected(true);
       if (fireEvents) {
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 2bcf44a..5933672 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -77,22 +77,18 @@
       case Event.ONMOUSEOVER:
         // Only fire the mouse over event if it's coming from outside this
         // widget.
-        Element from = event.getFromElement();
-        if (from != null && getElement().isOrHasChild(from)) {
+      case Event.ONMOUSEOUT:
+        // Only fire the mouse out event if it's leaving this
+        // widget.
+        Element related = event.getRelatedTarget();
+        if (related != null && getElement().isOrHasChild(related)) {
           return;
         }
         break;
-      case Event.ONMOUSEOUT:
-        // Only fire the mouse out event if it's actually leaving this
-        // widget.
-        Element to = event.getToElement();
-        if (to != null && getElement().isOrHasChild(to)) {
-          return;
-        }
     }
     DomEvent.fireNativeEvent(event, this);
   }
-
+ 
   /**
    * Removes this widget from its parent widget. If it has no parent, this
    * method does nothing.
@@ -113,7 +109,8 @@
    * Overridden to defer the call to super.sinkEvents until the first time this
    * widget is attached to the dom, as a performance enhancement. Subclasses
    * wishing to customize sinkEvents can preserve this deferred sink behavior by
-   * putting their implementation behind a check of <code>isOrWasAttached()</code>:
+   * putting their implementation behind a check of
+   * <code>isOrWasAttached()</code>:
    * 
    * <pre>
    * {@literal @}Override
@@ -148,7 +145,7 @@
       final H handler, DomEvent.Type<H> type) {
     assert handler != null : "handler must not be null";
     assert type != null : "type must not be null";
-    sinkEvents(type.getEventToSink());
+    sinkEvents(Event.getTypeInt(type.getName()));
     return ensureHandlers().addHandler(type, handler);
   }
 
diff --git a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
index 5a835f3..4e78056 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
@@ -18,6 +18,10 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.Image;
 
 /**
  * Uses a combination of a clear image and a background image to clip all except
@@ -54,4 +58,26 @@
 
     return clippedImgHtml;
   }
+
+  public void fireSyntheticLoadEvent(final Image image) {
+    /*
+     * We need to synthesize a load event, because the native events that are
+     * fired would correspond to the loading of clear.cache.gif, which is
+     * incorrect. A native event would not even fire in Internet Explorer,
+     * 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
+     * event handler.
+     */
+    DeferredCommand.addCommand(new Command() {
+      public void execute() {
+        NativeEvent evt = Document.get().createLoadEvent();
+        image.getElement().dispatchEvent(evt);
+      }
+    });
+  }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
index 6c83175..3666ce8 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
@@ -16,7 +16,13 @@
 package com.google.gwt.user.client.ui.impl;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Image;
 
 /**
  * Implements the clipped image as a IMG inside a custom tag because we can't
@@ -65,6 +71,31 @@
   }
 
   @Override
+  public Element createStructure(String url, int left, int top, int width,
+      int height) {
+    // We need to explicitly sink ONLOAD on the child image element, because it
+    // can't be fired on the clipper.
+    Element clipper = super.createStructure(url, left, top, width, height);
+    Element img = clipper.getFirstChildElement();
+    Event.sinkEvents(img, Event.ONLOAD);
+    return clipper;
+  }
+
+  public void fireSyntheticLoadEvent(final Image image) {
+    // This is the same as the superclass' implementation, except that it
+    // explicitly checks for the 'clipper' element, and dispatches the event
+    // on the img (you can't dispatch events on the clipper).
+    DeferredCommand.addCommand(new Command() {
+      public void execute() {
+        NativeEvent evt = Document.get().createLoadEvent();
+        Element clipper = image.getElement();
+        Element img = clipper.getFirstChildElement();
+        img.dispatchEvent(evt);
+      }
+    });
+  }
+
+  @Override
   public String getHTML(String url, int left, int top, int width, int height) {
     String clipperStyle = "overflow: hidden; width: " + width + "px; height: "
         + height + "px; padding: 0px; zoom: 1";
diff --git a/user/src/com/google/gwt/user/tools/.classpathsrc b/user/src/com/google/gwt/user/tools/.classpathsrc
index d2b73b6..570ab72 100644
--- a/user/src/com/google/gwt/user/tools/.classpathsrc
+++ b/user/src/com/google/gwt/user/tools/.classpathsrc
@@ -2,6 +2,7 @@
 <classpath>
    <classpathentry kind="src" path="src"/>
    <classpathentry kind="lib" path="@gwtUserPath"/>
+   <classpathentry kind="lib" path="@gwtDevPath"/>
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
    <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
    <classpathentry kind="output" path="war/WEB-INF/classes"/>
diff --git a/user/src/com/google/gwt/user/tools/App.launchsrc b/user/src/com/google/gwt/user/tools/App.launchsrc
index 92200c3..b5ea711 100644
--- a/user/src/com/google/gwt/user/tools/App.launchsrc
+++ b/user/src/com/google/gwt/user/tools/App.launchsrc
@@ -6,7 +6,6 @@
 <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot; javaProject=&quot;@moduleShortName&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
 <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/@moduleShortName/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
 <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento project=&quot;@moduleShortName&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
-<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;runtimeClasspathEntry externalArchive=&quot;@gwtDevPath&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
 </listAttribute>
 <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256M@vmargs"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl @startupUrl&#10;@moduleName"/>
diff --git a/user/src/com/google/gwt/user/tools/WebAppCreator.java b/user/src/com/google/gwt/user/tools/WebAppCreator.java
index d324a83..552d454 100644
--- a/user/src/com/google/gwt/user/tools/WebAppCreator.java
+++ b/user/src/com/google/gwt/user/tools/WebAppCreator.java
@@ -24,6 +24,7 @@
 import com.google.gwt.user.tools.util.ArgHandlerOverwrite;
 import com.google.gwt.user.tools.util.CreatorUtilities;
 import com.google.gwt.util.tools.ArgHandlerExtra;
+import com.google.gwt.util.tools.ArgHandlerFlag;
 import com.google.gwt.util.tools.ArgHandlerOutDir;
 import com.google.gwt.util.tools.Utility;
 
@@ -55,6 +56,8 @@
       registerHandler(new ArgHandlerIgnoreExtension());
       registerHandler(new ArgHandlerModuleName());
       registerHandler(new ArgHandlerOutDirExtension());
+      registerHandler(new ArgHandlerNoEclipse());
+      registerHandler(new ArgHandlerOnlyEclipse());
     }
 
     @Override
@@ -75,10 +78,6 @@
     }
   }
 
-  /*
-   * Arguments for the application creator.
-   */
-
   private final class ArgHandlerModuleName extends ArgHandlerExtra {
     @Override
     public boolean addExtraArg(String arg) {
@@ -114,6 +113,52 @@
     }
   }
 
+  private final class ArgHandlerNoEclipse extends ArgHandlerFlag {
+    @Override
+    public String getPurpose() {
+      return "Do not generate eclipse files";
+    }
+
+    @Override
+    public String getTag() {
+      return "-XnoEclipse";
+    }
+
+    @Override
+    public boolean isUndocumented() {
+      return true;
+    }
+
+    @Override
+    public boolean setFlag() {
+      noEclipse = true;
+      return true;
+    }
+  }
+
+  private final class ArgHandlerOnlyEclipse extends ArgHandlerFlag {
+    @Override
+    public String getPurpose() {
+      return "Generate only eclipse files";
+    }
+
+    @Override
+    public String getTag() {
+      return "-XonlyEclipse";
+    }
+
+    @Override
+    public boolean isUndocumented() {
+      return true;
+    }
+
+    @Override
+    public boolean setFlag() {
+      onlyEclipse = true;
+      return true;
+    }
+  }
+
   private final class ArgHandlerOverwriteExtension extends ArgHandlerOverwrite {
     @Override
     public boolean setFlag() {
@@ -127,8 +172,8 @@
   }
 
   private static final class FileCreator {
-    private final String destName;
     private final File destDir;
+    private final String destName;
     private final String sourceName;
 
     public FileCreator(File destDir, String destName, String sourceName) {
@@ -149,16 +194,19 @@
     System.exit(1);
   }
 
+  private boolean ignore = false;
+  private String moduleName;
+  private boolean noEclipse;
+  private boolean onlyEclipse;
+  private File outDir;
+  private boolean overwrite = false;
+
   /**
-   * @param moduleName name of the fully-qualified GWT module to create as an
-   *          Application.
-   * @param outDir Where to put the output files
-   * @param overwrite Overwrite an existing files if they exist.
-   * @param ignore Ignore existing files if they exist.
-   * @throws IOException
+   * Create the sample app.
+   * 
+   * @throws IOException if any disk write fails
    */
-  static void createApplication(String moduleName, File outDir,
-      boolean overwrite, boolean ignore) throws IOException {
+  protected void doRun() throws IOException {
 
     // Figure out the installation directory
     String installPath = Utility.getInstallPath();
@@ -213,24 +261,51 @@
     replacements.put("@vmargs", isMacOsX ? "&#10;-XstartOnFirstThread" : "");
     replacements.put("@renameTo", moduleShortName.toLowerCase());
 
+    String antEclipseRule = "";
+    if (noEclipse) {
+      /*
+       * Generate a rule into the build file that allows for the generation of
+       * an eclipse project later on. This is primarily for distro samples. This
+       * is a quick and dirty way to inject a build rule, but it works.
+       */
+      antEclipseRule = "\n\n"
+          + "  <target name=\"eclipse.generate\" depends=\"libs\" description=\"Generate eclipse project\">\n"
+          + "    <java failonerror=\"true\" fork=\"true\" classname=\""
+          + this.getClass().getName() + "\">\n" + "      <classpath>\n"
+          + "        <path refid=\"project.class.path\"/>\n"
+          + "      </classpath>\n" + "      <arg value=\"-XonlyEclipse\"/>\n"
+          + "      <arg value=\"-ignore\"/>\n" + "      <arg value=\""
+          + moduleName + "\"/>\n" + "    </java>\n" + "  </target>";
+    } else {
+      antEclipseRule = "";
+    }
+    replacements.put("@antEclipseRule", antEclipseRule);
+
     List<FileCreator> files = new ArrayList<FileCreator>();
-    files.add(new FileCreator(moduleDir, moduleShortName + ".gwt.xml",
-        "Module.gwt.xml"));
-    files.add(new FileCreator(warDir, moduleShortName + ".html", "AppHtml.html"));
-    files.add(new FileCreator(warDir, moduleShortName + ".css", "AppCss.css"));
-    files.add(new FileCreator(webInfDir, "web.xml", "web.xml"));
-    files.add(new FileCreator(clientDir, moduleShortName + ".java",
-        "AppClassTemplate.java"));
-    files.add(new FileCreator(clientDir, "EchoService" + ".java",
-        "RpcClientTemplate.java"));
-    files.add(new FileCreator(clientDir, "EchoServiceAsync" + ".java",
-        "RpcAsyncClientTemplate.java"));
-    files.add(new FileCreator(serverDir, "EchoServiceImpl" + ".java",
-        "RpcServerTemplate.java"));
-    files.add(new FileCreator(outDir, "build.xml", "project.ant.xml"));
-    files.add(new FileCreator(outDir, ".project", ".project"));
-    files.add(new FileCreator(outDir, ".classpath", ".classpath"));
-    files.add(new FileCreator(outDir, moduleShortName + ".launch", "App.launch"));
+    if (!onlyEclipse) {
+      files.add(new FileCreator(moduleDir, moduleShortName + ".gwt.xml",
+          "Module.gwt.xml"));
+      files.add(new FileCreator(warDir, moduleShortName + ".html",
+          "AppHtml.html"));
+      files.add(new FileCreator(warDir, moduleShortName + ".css", "AppCss.css"));
+      files.add(new FileCreator(webInfDir, "web.xml", "web.xml"));
+      files.add(new FileCreator(clientDir, moduleShortName + ".java",
+          "AppClassTemplate.java"));
+      files.add(new FileCreator(clientDir, "EchoService" + ".java",
+          "RpcClientTemplate.java"));
+      files.add(new FileCreator(clientDir, "EchoServiceAsync" + ".java",
+          "RpcAsyncClientTemplate.java"));
+      files.add(new FileCreator(serverDir, "EchoServiceImpl" + ".java",
+          "RpcServerTemplate.java"));
+      files.add(new FileCreator(outDir, "build.xml", "project.ant.xml"));
+    }
+    if (!noEclipse) {
+      assert new File(gwtDevPath).isAbsolute();
+      files.add(new FileCreator(outDir, ".project", ".project"));
+      files.add(new FileCreator(outDir, ".classpath", ".classpath"));
+      files.add(new FileCreator(outDir, moduleShortName + ".launch",
+          "App.launch"));
+    }
 
     for (FileCreator fileCreator : files) {
       File file = Utility.createNormalFile(fileCreator.destDir,
@@ -247,14 +322,9 @@
     }
   }
 
-  private boolean ignore = false;
-  private String moduleName;
-  private File outDir;
-  private boolean overwrite = false;
-
   protected boolean run() {
     try {
-      createApplication(moduleName, outDir, overwrite, ignore);
+      doRun();
       return true;
     } catch (IOException e) {
       System.err.println(e.getClass().getName() + ": " + e.getMessage());
diff --git a/user/src/com/google/gwt/user/tools/project.ant.xmlsrc b/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
index 9b6e4a9..b050e83 100644
--- a/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
+++ b/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
@@ -4,6 +4,7 @@
   <path id="project.class.path">
     <pathelement location="war/WEB-INF/classes"/>
     <pathelement location="@gwtUserPath"/>
+    <pathelement location="@gwtDevPath"/>
     <!-- Add any additional non-server libs (such as JUnit) -->
     <fileset dir="war/WEB-INF/lib">
       <include name="**/*.jar"/>
@@ -32,7 +33,6 @@
       <classpath>
         <pathelement location="src"/>
         <path refid="project.class.path"/>
-        <pathelement location="@gwtDevPath"/>
       </classpath>
       <!-- add jvmarg -Xss16M or similar if you see a StackOverflowError -->
       <jvmarg value="-Xmx256M"/>@antVmargs
@@ -45,7 +45,6 @@
       <classpath>
         <pathelement location="src"/>
         <path refid="project.class.path"/>
-        <pathelement location="@gwtDevPath"/>
       </classpath>
       <jvmarg value="-Xmx256M"/>@antVmargs
       <arg value="-startupUrl"/>
@@ -53,7 +52,7 @@
       <arg value="@moduleName"/>
       <!-- Additional arguments like -style PRETTY or -logLevel DEBUG -->
     </java>
-  </target>
+  </target>@antEclipseRule
 
   <target name="build" depends="gwtc" description="Build this project" />
 
diff --git a/user/super/com/google/gwt/emul/java/util/Arrays.java b/user/super/com/google/gwt/emul/java/util/Arrays.java
index ed22899..56d1778 100644
--- a/user/super/com/google/gwt/emul/java/util/Arrays.java
+++ b/user/super/com/google/gwt/emul/java/util/Arrays.java
@@ -493,8 +493,10 @@
         hash = hashCode((float[]) obj);
       } else if (obj instanceof double[]) {
         hash = hashCode((double[]) obj);
-      } else {
+      } else if (obj != null) {
         hash = obj.hashCode();
+      } else {
+        hash = 0;
       }
 
       // nasty trick related to JS and lack of integer rollover
diff --git a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
index a975fc4..9d161ce 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
@@ -95,6 +95,12 @@
 
       new InnerSub().new InnerSubSub().fda();
       new SecondMain().new FunkyInner();
+      /*
+       * The statement below causes a javac bug in openJdk and sun's java 6. It
+       * produces incorrect bytecode that fails with a java.lang.VerifyError --
+       * see Google's internal issue 1628473. This is likely to be an hindrance
+       * if and when GWT attempts to read bytecode directly.
+       */
       new NamedLocal().new NamedLocalSub().foo();
     }
 
diff --git a/user/test/com/google/gwt/dev/shell/rewrite/client/EmmaClassLoadingTest.java b/user/test/com/google/gwt/dev/shell/rewrite/client/EmmaClassLoadingTest.java
index 35250a3..8d6eb5b 100644
--- a/user/test/com/google/gwt/dev/shell/rewrite/client/EmmaClassLoadingTest.java
+++ b/user/test/com/google/gwt/dev/shell/rewrite/client/EmmaClassLoadingTest.java
@@ -16,6 +16,9 @@
 package com.google.gwt.dev.shell.rewrite.client;
 
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Timer;
+
+import junit.framework.TestCase;
 
 /**
  * Test-case to check if the jsni blocks are mapped correctly between the
@@ -31,7 +34,7 @@
  */
 public class EmmaClassLoadingTest extends GWTTestCase {
 
-  enum EnumTest {
+  enum EnumClass {
     A, B, C,
   }
 
@@ -40,7 +43,7 @@
   }
 
   private static String messages[] = {
-      "a foo", "b foo", "enum A", "d foo", "e foo"};
+      "1a foo", "1b foo", "1enum A", "1d foo", "1e foo"};
 
   private static int logCount = 0;
 
@@ -56,14 +59,14 @@
   public void test1() {
     TestInterface a = new TestInterface() {
       public void foo() {
-        log("a foo");
+        log("1a foo");
       }
     };
     a.foo();
 
     TestInterface b = new TestInterface() {
       public native void foo() /*-{
-        @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("b foo");
+        @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("1b foo");
       }-*/;
     };
     b.foo();
@@ -75,10 +78,10 @@
         }-*/;
       };
     }
-    EnumTest et = EnumTest.A;
+    EnumClass et = EnumClass.A;
     switch (et) {
       case A:
-        log("enum A");
+        log("1enum A");
         break;
       case B:
         log("ANY_FOO_2");
@@ -90,7 +93,7 @@
 
     TestInterface d = new TestInterface() {
       public native void foo() /*-{
-        @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("d foo");
+        @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("1d foo");
       }-*/;
     };
     d.foo();
@@ -103,8 +106,193 @@
      */
     TestInterface e = new TestInterface() {
       public native void foo() /*-{
-        @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("e foo");
+        @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("1e foo");
       }-*/;
     };
-  } 
+  }
+
+  public void test2() {
+    SecondTopLevelClass second = new SecondTopLevelClass();
+    SecondTopLevelClass.InnerClass.test();
+  }
+
+  public void test3() {
+    ThirdTopLevelClass third = new ThirdTopLevelClass();
+    third.test();
+  }
+
+  public void test4() {
+    FourthTopLevelClass fourth = new FourthTopLevelClass();
+    fourth.test();
+  }
+
+}
+
+/**
+ * Check that the algorithm correctly maps named inner classes. In this example,
+ * jdt generates $1Foo and $2Foo whereas javac generates $2Foo and $3Foo.
+ * 
+ */
+class FourthTopLevelClass extends TestCase {
+  private static String messages[] = {"4a foo"};
+
+  private static int logCount = 0;
+
+  private static void log(String msg) {
+    assertEquals(messages[logCount++], msg);
+  }
+
+  void test() {
+    test1();
+    test2();
+  };
+
+  private void test1() {
+    if (false) {
+      class Foo {
+        public native void foo() /*-{
+          @com.google.gwt.dev.shell.rewrite.client.FourthTopLevelClass::log(Ljava/lang/String;)("ANY_FOO");
+        }-*/;
+      }
+      new Foo().foo();
+    }
+  }
+
+  private void test2() {
+    class Foo {
+      public native void foo() /*-{
+        @com.google.gwt.dev.shell.rewrite.client.FourthTopLevelClass::log(Ljava/lang/String;)("4a foo");
+      }-*/;
+    }
+    new Foo().foo();
+  }
+
+  /*
+   * Added a test3() method so that when the test fails, it fails quickly.
+   * Instead of timing out, the AssertEquals fails
+   */
+  private void test3() {
+    class Foo {
+      public native void foo() /*-{
+        @com.google.gwt.dev.shell.rewrite.client.FourthTopLevelClass::log(Ljava/lang/String;)("4b foo");
+      }-*/;
+    }
+    new Foo().foo();
+  }
+}
+
+/**
+ * Check if GWT is able to correctly compile cases when there are multiple
+ * top-level classes and when there is a need to traverse inner classes. This
+ * class's test method simply mirrors the test methods of EmmaClassLoadingTest.
+ * 
+ */
+class SecondTopLevelClass extends TestCase {
+
+  static class InnerClass {
+    /**
+     * Test that mapping is constructed for something which is not in the main
+     * unit as well.
+     */
+    static void test() {
+      EmmaClassLoadingTest.TestInterface a = new EmmaClassLoadingTest.TestInterface() {
+        public void foo() {
+          log("2a foo");
+        }
+      };
+      a.foo();
+
+      EmmaClassLoadingTest.TestInterface b = new EmmaClassLoadingTest.TestInterface() {
+        public native void foo() /*-{
+          @com.google.gwt.dev.shell.rewrite.client.SecondTopLevelClass::log(Ljava/lang/String;)("2b foo");
+        }-*/;
+      };
+      b.foo();
+
+      if (false) {
+        EmmaClassLoadingTest.TestInterface c = new EmmaClassLoadingTest.TestInterface() {
+          public native void foo() /*-{
+            @com.google.gwt.dev.shell.rewrite.client.SecondTopLevelClass::log(Ljava/lang/String;)("ANY_FOO_1");
+          }-*/;
+        };
+      }
+      EmmaClassLoadingTest.EnumClass et = EmmaClassLoadingTest.EnumClass.A;
+      switch (et) {
+        case A:
+          log("2enum A");
+          break;
+        case B:
+          log("ANY_FOO_2");
+          break;
+        case C:
+          log("ANY_FOO_3");
+          break;
+      }
+
+      EmmaClassLoadingTest.TestInterface d = new EmmaClassLoadingTest.TestInterface() {
+        public native void foo() /*-{
+          @com.google.gwt.dev.shell.rewrite.client.SecondTopLevelClass::log(Ljava/lang/String;)("2d foo");
+        }-*/;
+      };
+      d.foo();
+
+      /*
+       * jdt generates $1 (a), $2 (b), $3 (d), $4 (e). javac generates $1 (a),
+       * $2 (b), $3 (c), $4 (d), $5 (e), $6 (synthetic). Added e so that the
+       * test fails quickly. Otherwise, it had to wait for a time-out (in
+       * looking through jdt generated code for non-existent jsni methods of $4)
+       * to fail.
+       */
+      EmmaClassLoadingTest.TestInterface e = new EmmaClassLoadingTest.TestInterface() {
+        public native void foo() /*-{
+          @com.google.gwt.dev.shell.rewrite.client.SecondTopLevelClass::log(Ljava/lang/String;)("2e foo");
+        }-*/;
+      };
+    }
+  }
+
+  private static String messages[] = {
+      "2a foo", "2b foo", "2enum A", "2d foo", "2e foo"};
+
+  private static int logCount = 0;
+
+  private static void log(String msg) {
+    assertEquals(messages[logCount++], msg);
+  }
+}
+
+/**
+ * Check that the mapping algorithm is not confused by the presence of other
+ * inner classes.
+ */
+class ThirdTopLevelClass extends TestCase {
+
+  private static String messages[] = {"3a foo"};
+
+  private static int logCount = 0;
+
+  private static void log(String msg) {
+    assertEquals(messages[logCount++], msg);
+  }
+
+  void test() {
+    Timer t1 = new Timer() {
+      @Override
+      public void run() {
+      }
+    };
+
+    EmmaClassLoadingTest.TestInterface a = new EmmaClassLoadingTest.TestInterface() {
+      public native void foo() /*-{
+        @com.google.gwt.dev.shell.rewrite.client.ThirdTopLevelClass::log(Ljava/lang/String;)("3a foo");
+      }-*/;
+    };
+    a.foo();
+
+    Timer t2 = new Timer() {
+      @Override
+      public void run() {
+      }
+    };
+  }
 }
diff --git a/user/test/com/google/gwt/event/shared/HandlerTestBase.java b/user/test/com/google/gwt/event/shared/HandlerTestBase.java
index 303ff12..80e551b 100644
--- a/user/test/com/google/gwt/event/shared/HandlerTestBase.java
+++ b/user/test/com/google/gwt/event/shared/HandlerTestBase.java
@@ -29,6 +29,7 @@
  */

 public abstract class HandlerTestBase extends GWTTestCase {

 

+  @Override

   public String getModuleName() {

     return "com.google.gwt.event.Event";

   }

diff --git a/user/test/com/google/gwt/json/client/JSONTest.java b/user/test/com/google/gwt/json/client/JSONTest.java
index de9f9f0..c10751f 100644
--- a/user/test/com/google/gwt/json/client/JSONTest.java
+++ b/user/test/com/google/gwt/json/client/JSONTest.java
@@ -55,14 +55,14 @@
   private static void assertJSONObjectEquals(JSONObject expected,
       JSONObject actual) {
     Set<String> actKeys = actual.keySet();
-    for (String key : expected.keySet()) {
-      actKeys.remove(key);
+    Set<String> expKeys = expected.keySet();
+    assertEquals(expKeys.size(), actKeys.size());
+    for (String key : expKeys) {
       assertTrue(actual.containsKey(key));
       JSONValue expValue = expected.get(key);
       JSONValue actValue = actual.get(key);
       assertJSONValueEquals(expValue, actValue);
     }
-    assertEquals(0, actKeys.size());
   }
 
   private static void assertJSONValueEquals(JSONValue expected, JSONValue actual) {
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index c7483be..716c5ee 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -23,9 +23,11 @@
 import com.google.gwt.user.client.WindowTest;
 import com.google.gwt.user.client.ui.AbsolutePanelTest;
 import com.google.gwt.user.client.ui.AnchorTest;
+import com.google.gwt.user.client.ui.ButtonTest;
 import com.google.gwt.user.client.ui.CaptionPanelTest;
 import com.google.gwt.user.client.ui.CheckBoxTest;
 import com.google.gwt.user.client.ui.CompositeTest;
+import com.google.gwt.user.client.ui.CreateEventTest;
 import com.google.gwt.user.client.ui.CustomButtonTest;
 import com.google.gwt.user.client.ui.DOMTest;
 import com.google.gwt.user.client.ui.DateBoxTest;
@@ -95,6 +97,7 @@
     suite.addTestSuite(AbsolutePanelTest.class);
     suite.addTestSuite(AnchorTest.class);
     suite.addTestSuite(AsyncProxyTest.class);
+    suite.addTestSuite(ButtonTest.class);
     suite.addTestSuite(CaptionPanelTest.class);
     suite.addTestSuite(CheckBoxTest.class);
     suite.addTestSuite(ClippedImagePrototypeTest.class);
@@ -160,6 +163,7 @@
     suite.addTestSuite(XMLTest.class);
     suite.addTestSuite(ClassInitTest.class);
     suite.addTestSuite(DateChangeEventTest.class);
+    suite.addTestSuite(CreateEventTest.class);
     return suite;
   }
 }
diff --git a/user/test/com/google/gwt/user/client/ui/ButtonTest.java b/user/test/com/google/gwt/user/client/ui/ButtonTest.java
new file mode 100644
index 0000000..83777e7
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/ButtonTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2008 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.dom.client.Element;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests for {@link Button}.
+ */
+public class ButtonTest extends GWTTestCase {
+
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+
+  private class H implements ClickHandler {
+    boolean clicked;
+    Element target;
+
+    public void onClick(ClickEvent event) {
+      target = event.getNativeEvent().getTarget();
+      clicked = true;
+    }
+  }
+
+  public void testClick() {
+    Button b = new Button();
+    RootPanel.get().add(b);
+
+    H h = new H();
+    b.addClickHandler(h);
+
+    b.click();
+    assertTrue(h.clicked);
+
+    // Old Mozilla browsers don't set up the event target properly for
+    // synthesized clicks. This tests the workaround in DOMImplMozillaOld.
+    assertEquals(b.getElement(), h.target);
+  }
+}
+
diff --git a/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java b/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
index 95fb16c..2a4ed97 100644
--- a/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
@@ -96,6 +96,14 @@
     assertEquals("valuable", cb.getFormValue());
   }
 
+  public void testConstructorInputElement() {
+    InputElement elm = DOM.createInputCheck().cast();
+    CheckBox box = new CheckBox(elm.<Element> cast());
+    assertFalse(box.getValue());
+    elm.setDefaultChecked(true);
+    assertTrue(box.getValue());
+  }
+
   public void testDebugId() {
     CheckBox check = new CheckBox("myLabel");
 
@@ -111,42 +119,18 @@
     UIObjectTest.assertDebugIdContents("myCheck-label", "myLabel");
   }
 
-  public void testConstructorInputElement() {
+  /**
+   * Tests that detaching and attaching a CheckBox widget retains the checked
+   * state of the element. This is known to be tricky on IE.
+   */
+  public void testDetachment() {
     InputElement elm = DOM.createInputCheck().cast();
     CheckBox box = new CheckBox(elm.<Element> cast());
-    assertFalse(box.getValue());
-    elm.setDefaultChecked(true);
-    assertTrue(box.getValue());
-  }
-
-  public void testReplaceInputElement() {
-    cb.setValue(true);
-    cb.setTabIndex(1234);
-    cb.setEnabled(false);
-    cb.setAccessKey('k');
-    cb.setFormValue("valuable");
-
-    InputElement elm = Document.get().createCheckInputElement();
-    assertFalse(elm.isChecked());
-
-    Element asOldElement = elm.cast();
-    cb.replaceInputElement(asOldElement);
-
-    // The values should be preserved
-    assertTrue(cb.getValue());
-    assertEquals(1234, cb.getTabIndex());
-    assertFalse(cb.isEnabled());
-    assertEquals("k", elm.getAccessKey());
-    assertEquals("valuable", cb.getFormValue());
-
-    assertTrue(elm.isChecked());
-    cb.setValue(false);
-    assertFalse(elm.isChecked());
-
+    RootPanel.get().add(box);
     elm.setChecked(true);
-    assertTrue(cb.getValue());
-
-    // TODO: When event creation is in, test that click on the new element works
+    RootPanel.get().remove(box);
+    RootPanel.get().add(box);
+    assertTrue(elm.isChecked());
   }
 
   public void testFormValue() {
@@ -182,6 +166,36 @@
     assertEquals(ListenerTester.fired, 0);
   }
 
+  public void testReplaceInputElement() {
+    cb.setValue(true);
+    cb.setTabIndex(1234);
+    cb.setEnabled(false);
+    cb.setAccessKey('k');
+    cb.setFormValue("valuable");
+
+    InputElement elm = Document.get().createCheckInputElement();
+    assertFalse(elm.isChecked());
+
+    Element asOldElement = elm.cast();
+    cb.replaceInputElement(asOldElement);
+
+    // The values should be preserved
+    assertTrue(cb.getValue());
+    assertEquals(1234, cb.getTabIndex());
+    assertFalse(cb.isEnabled());
+    assertEquals("k", elm.getAccessKey());
+    assertEquals("valuable", cb.getFormValue());
+
+    assertTrue(elm.isChecked());
+    cb.setValue(false);
+    assertFalse(elm.isChecked());
+
+    elm.setChecked(true);
+    assertTrue(cb.getValue());
+
+    // TODO: When event creation is in, test that click on the new element works
+  }
+
   @SuppressWarnings("deprecation")
   public void testValueChangeEvent() {
     Handler h = new Handler();
diff --git a/user/test/com/google/gwt/user/client/ui/CreateEventTest.java b/user/test/com/google/gwt/user/client/ui/CreateEventTest.java
new file mode 100644
index 0000000..9029f94
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/CreateEventTest.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright 2008 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.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.ImageElement;
+import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.EventListener;
+
+/**
+ * Tests for the native event triggering methods in {@link Event}.
+ */
+public class CreateEventTest extends GWTTestCase {
+
+  /**
+   * Listener for use with key[down up press].
+   */
+  private class KeyEventListener extends BubbleAssertingEventListener {
+    public KeyEventListener(String eventType) {
+      super(eventType);
+    }
+
+    public void onBrowserEvent(Event event) {
+      super.onBrowserEvent(event);
+      assertAllShiftKeysOn(event);
+      assertEquals(KEY_CODE, event.getKeyCode());
+    }
+  }
+
+  /**
+   * Listener for use with mouse[down up move over out].
+   */
+  private class MouseEventListener extends BubbleAssertingEventListener {
+    public MouseEventListener(String eventType) {
+      super(eventType);
+    }
+
+    public void onBrowserEvent(Event event) {
+      super.onBrowserEvent(event);
+      assertMouseCoordinates(event);
+      assertAllShiftKeysOn(event);
+      assertEquals(Event.BUTTON_LEFT, event.getButton());
+    }
+  }
+
+  /**
+   * An event listener that asserts that the event is passed to child, then
+   * parent.
+   */
+  private class BubbleAssertingEventListener implements EventListener {
+    public boolean parentReceived, childReceived;
+    private final String eventType;
+
+    public BubbleAssertingEventListener(String eventType) {
+      this.eventType = eventType;
+    }
+
+    public void onBrowserEvent(Event event) {
+      assertEquals(eventType, event.getType());
+
+      Element target = event.getCurrentTarget();
+      if (target == child) {
+        assertFalse("Expecting child to receive the event only once",
+            childReceived);
+        assertFalse("Expecting child to receive the event before parent",
+            parentReceived);
+
+        childReceived = true;
+      } else if (target == parent) {
+        assertFalse("Expecting parent to receive the event only once",
+            parentReceived);
+        assertTrue("Expecting parent to receive the event after the child",
+            childReceived);
+
+        parentReceived = true;
+      }
+    }
+  }
+
+  /**
+   * Used with {@link CreateEventTest#testGetCurrentEvent()}.
+   */
+  private static class CurrentEventListener implements EventListener {
+    public boolean gotClick, gotKeyPress, gotFocus;
+
+    public void onBrowserEvent(Event event) {
+      switch (Event.getCurrentEvent().getTypeInt()) {
+        case Event.ONCLICK:
+          gotClick = true;
+          break;
+        case Event.ONKEYPRESS:
+          gotKeyPress = true;
+          break;
+        case Event.ONFOCUS:
+          gotFocus = true;
+          break;
+      }
+    }
+  }
+
+  /**
+   * An event listener that asserts that the event is passed only to child.
+   */
+  private class NonBubbleAssertingEventListener implements EventListener {
+    private boolean childReceived;
+    private String eventType;
+
+    public NonBubbleAssertingEventListener(String eventType) {
+      this.eventType = eventType;
+    }
+
+    public void onBrowserEvent(Event event) {
+      assertEquals(eventType, event.getType());
+
+      if (event.getTarget() == child) {
+        assertFalse("Expecting child to receive the event only once",
+            childReceived);
+        childReceived = true;
+      } else if (event.getTarget() == parent) {
+        fail("Not expecting parent to receive the event");
+      }
+    }
+
+    protected String getEventType() {
+      return eventType;
+    }
+  }
+
+  /**
+   * An event listener that asserts that events are received properly for the
+   * img element.
+   */
+  private class ImgEventListener implements EventListener {
+    private boolean imgReceived;
+    private final String eventType;
+
+    public ImgEventListener(String eventType) {
+      this.eventType = eventType;
+    }
+
+    public void onBrowserEvent(Event event) {
+      if (event.getType().equals(eventType)) {
+        if (event.getTarget() == img) {
+          assertFalse("Expecting img to receive the event only once",
+              imgReceived);
+
+          imgReceived = true;
+        } else if (event.getTarget() == parent) {
+          fail("Not expecting parent to receive the event");
+        }
+      }
+    }
+  }
+
+  private static final int MOUSE_DETAIL = 1;
+  private static final int CLIENT_X = 2;
+  private static final int CLIENT_Y = 3;
+  private static final int SCREEN_X = 4;
+  private static final int SCREEN_Y = 5;
+  private static final int KEY_CODE = 'A';
+
+  private static final int ALL_EVENTS = Event.MOUSEEVENTS | Event.KEYEVENTS
+      | Event.FOCUSEVENTS | Event.ONCHANGE | Event.ONCLICK | Event.ONDBLCLICK
+      | Event.ONCONTEXTMENU | Event.ONLOAD | Event.ONERROR | Event.ONSCROLL;
+  private static DivElement parent;
+  private static InputElement child;
+  private static ImageElement img;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.UserTest";
+  }
+
+  /**
+   * Tests that {@link Event#getCurrentEvent()} returns the right value for
+   * synthesized events.
+   */
+  public void testGetCurrentEvent() {
+    CurrentEventListener listener = new CurrentEventListener();
+    Event.setEventListener(child, listener);
+
+    // Test all three major event types.
+    child.dispatchEvent(Document.get().createClickEvent(0, 0, 0, 0, 0, false,
+        false, false, false));
+    child.dispatchEvent(Document.get().createKeyPressEvent(false, false, false,
+        false, 65, 65));
+    child.dispatchEvent(Document.get().createFocusEvent());
+
+    assertTrue("Expecting click as current event", listener.gotClick);
+    assertTrue("Expecting keypress as current event", listener.gotKeyPress);
+    assertTrue("Expecting focus as current event", listener.gotFocus);
+  }
+
+  /**
+   * Tests NativeEvent.stopPropagation()
+   */
+  public void testStopPropagation() {
+    NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
+        "click") {
+      @Override
+      public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        if (event.getCurrentTarget() == child) {
+          event.stopPropagation();
+        }
+      }
+    };
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createClickEvent(MOUSE_DETAIL, SCREEN_X,
+        SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+  }
+
+  /**
+   * Tests createBlurEvent().
+   */
+  public void testTriggerBlurEvent() {
+    NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
+        "blur") {
+      public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        assertEquals("blur", event.getType());
+      }
+    };
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createBlurEvent());
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+  }
+
+  /**
+   * Tests createChangeEvent().
+   */
+  public void testTriggerChangeEvent() {
+    BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
+        "change");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createChangeEvent());
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+  }
+
+  /**
+   * Tests createClickEvent().
+   */
+  public void testTriggerClickEvent() {
+    BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
+        "click") {
+      public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        assertMouseCoordinates(event);
+        assertAllShiftKeysOn(event);
+      }
+    };
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createClickEvent(MOUSE_DETAIL, SCREEN_X,
+        SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createContextMenuEvent().
+   * TODO: Re-enable this test when we no longer support Firefox2 and earlier
+   * (which doesn't appear to dispatch contextmenu events properly).
+   */
+//  public void testTriggerContextMenuEvent() {
+//    BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
+//        "contextmenu");
+//    Event.setEventListener(parent, listener);
+//    Event.setEventListener(child, listener);
+//
+//    child.dispatchEvent(Document.get().createContextMenuEvent());
+//
+//    assertTrue("Expected child to receive event", listener.childReceived);
+//    assertTrue("Expected parent to receive event", listener.parentReceived);
+//  }
+
+  /**
+   * Tests createDblClickEvent().
+   */
+  public void testTriggerDblClickEvent() {
+    BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
+        "dblclick") {
+      public void onBrowserEvent(Event event) {
+        if (event.getTypeInt() == Event.ONCLICK) {
+          // Some browsers (IE, I'm looking at you) synthesize an extra click
+          // event when a double-click is triggered. This synthesized click
+          // will *not* have the same properties as the dblclick, so we will
+          // not try to assert them here.
+          return;
+        }
+
+        super.onBrowserEvent(event);
+        assertMouseCoordinates(event);
+        assertAllShiftKeysOn(event);
+      }
+    };
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createDblClickEvent(MOUSE_DETAIL,
+        SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createErrorEvent().
+   */
+  public void testTriggerErrorEvent() {
+    ImgEventListener listener = new ImgEventListener("error");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(img, listener);
+
+    img.dispatchEvent(Document.get().createErrorEvent());
+
+    assertTrue("Expected child to receive event", listener.imgReceived);
+  }
+
+  /**
+   * Tests createFocusEvent().
+   */
+  public void testTriggerFocusEvent() {
+    NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
+        "focus") {
+      public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        assertEquals("focus", event.getType());
+      }
+    };
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createFocusEvent());
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+  }
+
+  /**
+   * Tests createKeyDownEvent().
+   */
+  public void testTriggerKeyDownEvent() {
+    KeyEventListener listener = new KeyEventListener("keydown");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createKeyDownEvent(true, true, true,
+        true, KEY_CODE, KEY_CODE));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createKeyPressEvent().
+   */
+  public void testTriggerKeyPressEvent() {
+    KeyEventListener listener = new KeyEventListener("keypress");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createKeyPressEvent(true, true, true,
+        true, KEY_CODE, KEY_CODE));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createKeyUpEvent().
+   */
+  public void testTriggerKeyUpEvent() {
+    KeyEventListener listener = new KeyEventListener("keyup");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createKeyUpEvent(true, true, true, true,
+        KEY_CODE, KEY_CODE));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createLoadEvent().
+   */
+  public void testTriggerLoadEvent() {
+    ImgEventListener listener = new ImgEventListener("load");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(img, listener);
+
+    img.dispatchEvent(Document.get().createLoadEvent());
+
+    assertTrue("Expected img to receive event", listener.imgReceived);
+  }
+
+  /**
+   * Tests createMouseDownEvent().
+   */
+  public void testTriggerMouseDownEvent() {
+    MouseEventListener listener = new MouseEventListener("mousedown");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createMouseDownEvent(MOUSE_DETAIL,
+        SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true,
+        Event.BUTTON_LEFT));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createMouseMoveEvent().
+   */
+  public void testTriggerMouseMoveEvent() {
+    MouseEventListener listener = new MouseEventListener("mousemove");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createMouseMoveEvent(MOUSE_DETAIL,
+        SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true,
+        Event.BUTTON_LEFT));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createMouseOutEvent().
+   */
+  public void testTriggerMouseOutEvent() {
+    MouseEventListener listener = new MouseEventListener("mouseout") {
+      public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+
+// TODO: Re-enable this assertion when we no longer support Firefox2 and earlier.
+// Old Firefoxen throw away the relatedTarget parameter of initMouseEvent().
+//        Element relatedTarget = event.getRelatedTarget();
+//        assertEquals("Expected relatedElement to be img", img, relatedTarget);
+      }
+    };
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createMouseOutEvent(MOUSE_DETAIL,
+        SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true,
+        Event.BUTTON_LEFT, img));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createMouseOverEvent().
+   */
+  public void testTriggerMouseOverEvent() {
+    MouseEventListener listener = new MouseEventListener("mouseover") {
+      public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+
+// TODO: Re-enable this assertion when we no longer support Firefox2 and earlier.
+// Old Firefoxen throw away the relatedTarget parameter of initMouseEvent().
+//        Element relatedTarget = event.getRelatedTarget();
+//        assertEquals("Expected relatedElement to be img", img, relatedTarget);
+      }
+    };
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createMouseOverEvent(MOUSE_DETAIL, SCREEN_X, SCREEN_Y,
+        CLIENT_X, CLIENT_Y, true, true, true, true, Event.BUTTON_LEFT, img));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createMouseUpEvent().
+   */
+  public void testTriggerMouseUpEvent() {
+    MouseEventListener listener = new MouseEventListener("mouseup");
+    Event.setEventListener(parent, listener);
+    Event.setEventListener(child, listener);
+
+    child.dispatchEvent(Document.get().createMouseUpEvent(MOUSE_DETAIL,
+        SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true,
+        Event.BUTTON_LEFT));
+
+    assertTrue("Expected child to receive event", listener.childReceived);
+    assertTrue("Expected parent to receive event", listener.parentReceived);
+  }
+
+  /**
+   * Tests createScrollEvent().
+   * TODO: Re-enable this test when we no longer support Firefox2 and earlier
+   * (which doesn't appear to dispatch contextmenu events properly).
+   */
+//  public void testTriggerScrollEvent() {
+//    NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
+//        "scroll") {
+//      public void onBrowserEvent(Event event) {
+//        super.onBrowserEvent(event);
+//        assertEquals("scroll", event.getType());
+//      }
+//    };
+//    Event.setEventListener(parent, listener);
+//    Event.setEventListener(child, listener);
+//
+//    child.dispatchEvent(Document.get().createScrollEvent());
+//
+//    assertTrue("Expected child to receive event", listener.childReceived);
+//  }
+
+  @Override
+  protected void gwtSetUp() throws Exception {
+    parent = Document.get().createDivElement();
+    child = Document.get().createTextInputElement();
+    img = Document.get().createImageElement();
+
+    Document.get().getBody().appendChild(parent);
+    parent.appendChild(child);
+    parent.appendChild(img);
+
+    Event.sinkEvents(parent, ALL_EVENTS);
+    Event.sinkEvents(child, ALL_EVENTS);
+    Event.sinkEvents(img, ALL_EVENTS);
+  }
+
+  private void assertAllShiftKeysOn(Event event) {
+    assertEquals("Expecting ctrl on", true, event.getCtrlKey());
+    assertEquals("Expecting alt on", true, event.getAltKey());
+    assertEquals("Expecting shift on", true, event.getShiftKey());
+    assertEquals("Expecting meta on", true, event.getMetaKey());
+  }
+
+  private void assertMouseCoordinates(Event event) {
+    assertEquals("clientX", CLIENT_X, event.getClientX());
+    assertEquals("clientY", CLIENT_Y, event.getClientY());
+    assertEquals("screenX", SCREEN_X, event.getScreenX());
+    assertEquals("screenY", SCREEN_Y, event.getScreenY());
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java b/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
index 5593cfa..ebe60ca 100644
--- a/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
@@ -16,18 +16,23 @@
 
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.CustomButton.Face;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 
 /**
- * Test for <code>PushButton</code> as most of this widget's functionality is
- * UI based, the primary test will be in the new UI testing framework once it is
+ * Test for <code>PushButton</code> as most of this widget's functionality is UI
+ * based, the primary test will be in the new UI testing framework once it is
  * released.
  * 
  */
@@ -154,4 +159,31 @@
     assertFalse(b.isDown());
     assertFalse(b.isEnabled());
   }
+
+  public void testSyntheticClick() {
+    PushButton b = new PushButton();
+    final ArrayList<String> events = new ArrayList<String>();
+
+    b.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        events.add(event.getNativeEvent().getType());
+      }
+    });
+
+    RootPanel.get().add(b);
+
+    // Synthesize over/down/up events, which should kick off CustomButton's
+    // internal machinery to synthesize a click.
+    b.getElement().dispatchEvent(
+        Document.get().createMouseOverEvent(1, 0, 0, 0, 0, false, false, false,
+            false, Event.BUTTON_LEFT, null));
+    b.getElement().dispatchEvent(
+        Document.get().createMouseDownEvent(1, 0, 0, 0, 0, false, false, false,
+            false, Event.BUTTON_LEFT));
+    b.getElement().dispatchEvent(
+        Document.get().createMouseUpEvent(1, 0, 0, 0, 0, false, false, false,
+            false, Event.BUTTON_LEFT));
+    assertEquals("Expecting one click event", 1, events.size());
+    assertEquals("Expecting one click event", "click", events.get(0));
+  }
 }
diff --git a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
index 04a9127..ef908a6 100644
--- a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.DeferredCommand;
@@ -68,6 +70,20 @@
     assertEquals("text", dialogBox.getText());
     assertTrue(dialogBox.getHTML().equalsIgnoreCase("<b>text</b>"));
   }
+  
+  public void testSimpleCloseButtonOnModalDialog() {
+    final DialogBox dialogBox = new DialogBox(false, true);
+    Button button = new Button();
+    button.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        dialogBox.hide();
+      }
+    });
+    dialogBox.add(button);
+    dialogBox.show();
+    button.click();
+    assertFalse(dialogBox.isShowing());
+  }
 
   public void testDebugId() {
     DialogBox dBox = new DialogBox();
@@ -86,7 +102,6 @@
     // Check the header IDs
     DeferredCommand.addCommand(new Command() {
       public void execute() {
-        String prefix = UIObject.DEBUG_ID_PREFIX;
         UIObjectTest.assertDebugIdContents("myDialogBox-caption",
             "test caption");
         finishTest();
diff --git a/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java b/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
index e305a2e..7480a84 100644
--- a/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
+++ b/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
@@ -82,7 +82,6 @@
    * is called.
    */
   public void testApplyToClippedImage() {
-
     final Image image = new Image("counting-backwards.png", 12, 13, 8, 8);
 
     assertEquals(12, image.getOriginLeft());
@@ -91,27 +90,6 @@
     assertEquals(8, image.getHeight());
     assertEquals("clipped", ImageTest.getCurrentImageStateName(image));
 
-    final TestLoadListener listener = new TestLoadListener(image) {
-      @Override
-      public void onLoad(Widget sender) {
-        super.onLoad(sender);
-
-        if (image.getOriginLeft() == 12 && image.getOriginTop() == 13) {
-          ClippedImagePrototype clippedImagePrototype = new ClippedImagePrototype(
-              "counting-forwards.png", 16, 16, 16, 16);
-
-          clippedImagePrototype.applyTo(image);
-
-          assertEquals(16, image.getOriginLeft());
-          assertEquals(16, image.getOriginTop());
-          assertEquals(16, image.getWidth());
-          assertEquals(16, image.getHeight());
-          assertEquals("clipped", ImageTest.getCurrentImageStateName(image));
-        }
-      }
-    };
-    image.addLoadListener(listener);
-
     final TestLoadHandler handler = new TestLoadHandler() {
       @Override
       public void onLoad(LoadEvent event) {
@@ -137,14 +115,13 @@
         fail("The image " + image.getUrl() + " failed to load.");
       }
     });
-    
+
     RootPanel.get().add(image);
     delayTestFinish(2000);
 
     Timer t = new Timer() {
       @Override
       public void run() {
-        assertEquals(2, listener.getOnloadEventFireCount());
         assertEquals(2, handler.getOnloadEventFireCount());
         finishTest();
       }