b=381494; add optional splashscreen for our slower targets; r=bsmedberg
authorVladimir Vukicevic <vladimir@pobox.com>
Tue, 16 Jun 2009 11:59:35 -0700
changeset 29279 31fd342897c763817c6a51df4157d19775db9b93
parent 29278 5324789e3d4243ab67eb9f002a28236ec0bc8bd8
child 29280 543def0d7efb569837e3a7d3b77eff3860f11139
push idunknown
push userunknown
push dateunknown
reviewersbsmedberg
bugs381494
milestone1.9.2a1pre
b=381494; add optional splashscreen for our slower targets; r=bsmedberg
config/autoconf.mk.in
configure.in
toolkit/xre/Makefile.in
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsSplashScreen.h
toolkit/xre/nsSplashScreenDummy.cpp
toolkit/xre/nsSplashScreenWin.cpp
widget/src/windows/Makefile.in
widget/src/windows/nsWindow.cpp
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -653,9 +653,11 @@ WRAP_SYSTEM_INCLUDES = @WRAP_SYSTEM_INCL
 
 MOZ_EMBEDDING_LEVEL_DEFAULT = @MOZ_EMBEDDING_LEVEL_DEFAULT@
 MOZ_EMBEDDING_LEVEL_BASIC = @MOZ_EMBEDDING_LEVEL_BASIC@
 MOZ_EMBEDDING_LEVEL_MINIMAL = @MOZ_EMBEDDING_LEVEL_MINIMAL@
 
 HAVE_ARM_SIMD = @HAVE_ARM_SIMD@
 HAVE_ARM_NEON = @HAVE_ARM_NEON@
 
+MOZ_SPLASHSCREEN = @MOZ_SPLASHSCREEN@
+
 MOZ_THEME_FASTSTRIPE = @MOZ_THEME_FASTSTRIPE@
--- a/configure.in
+++ b/configure.in
@@ -4561,16 +4561,17 @@ MOZ_PYTHON_LIBS=
 MOZ_PYTHON_PREFIX=
 MOZ_PYTHON_VER=
 MOZ_PYTHON_VER_DOTTED=
 MOZ_RDF=1
 MOZ_REFLOW_PERF=
 MOZ_SAFE_BROWSING=
 MOZ_HELP_VIEWER=
 MOZ_SPELLCHECK=1
+MOZ_SPLASHSCREEN=
 MOZ_STATIC_MAIL_BUILD=
 MOZ_STORAGE=1
 MOZ_SVG=1
 MOZ_TIMELINE=
 MOZ_UI_LOCALE=en-US
 MOZ_UNIVERSALCHARDET=1
 MOZ_URL_CLASSIFIER=
 MOZ_USE_NATIVE_UCONV=
@@ -5591,16 +5592,28 @@ if test -n "$MOZ_SYDNEYAUDIO"; then
 linux*)
       AC_CHECK_LIB(asound, snd_pcm_open,,AC_MSG_ERROR([Ogg support on Linux requires the alsa library]))
       ;;
    esac
 fi
 fi
 
 dnl ========================================================
+dnl Splashscreen
+dnl ========================================================
+AC_ARG_ENABLE(splashscreen,
+              [  --enable-splashscreen   display splashscreen while loading (default=no)],
+              [enable_splash="yes"],[enable_splash=""])
+if test "x$enable_splash" = "xyes"; then
+  MOZ_SPLASHSCREEN=1
+  AC_DEFINE(MOZ_SPLASHSCREEN)
+fi
+AC_SUBST(MOZ_SPLASHSCREEN)
+
+dnl ========================================================
 dnl Permissions System
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(permissions,
 [  --disable-permissions   Disable permissions (popup and cookie blocking)],
     MOZ_PERMISSIONS=,
     MOZ_PERMISSIONS=1
 )
 
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -103,16 +103,24 @@ EXPORTS = \
 CPPSRCS = \
 	nsAppRunner.cpp \
 	nsConsoleWriter.cpp \
 	nsXREDirProvider.cpp \
 	nsNativeAppSupportBase.cpp \
 	nsAppData.cpp \
 	$(NULL)
 
+ifdef MOZ_SPLASHSCREEN
+ifeq ($(OS_ARCH),WINCE)
+CPPSRCS += nsSplashScreenWin.cpp
+else
+CPPSRCS += nsSplashScreenDummy.cpp
+endif
+endif
+
 DEFINES += -DIMPL_XREAPI
 
 ifndef BUILD_STATIC_LIBS
 CPPSRCS += nsEmbedFunctions.cpp
 endif
 
 ifdef MOZ_UPDATER
 CPPSRCS += nsUpdateDriver.cpp
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -132,16 +132,20 @@
 #include "nsXULAppAPI.h"
 #include "nsXREDirProvider.h"
 #include "nsToolkitCompsCID.h"
 
 #include "nsINIParser.h"
 
 #include <stdlib.h>
 
+#if defined(MOZ_SPLASHSCREEN)
+#include "nsSplashScreen.h"
+#endif
+
 #ifdef XP_UNIX
 #include <sys/stat.h>
 #include <unistd.h>
 #endif
 
 #ifdef XP_BEOS
 // execv() behaves bit differently in R5 and Zeta, looks unreliable in such situation
 //#include <unistd.h>
@@ -2550,19 +2554,32 @@ static void MOZ_gdk_display_close(GdkDis
  * allocators and therefore don't define this symbol, NSPR must search the
  * entire process, which reduces startup performance.
  *
  * By defining the symbol here, we can avoid the wasted lookup and hopefully
  * improve startup performance.
  */
 PRBool nspr_use_zone_allocator = PR_FALSE;
 
+#ifdef MOZ_SPLASHSCREEN
+#define MOZ_SPLASHSCREEN_UPDATE(_i)  do { if (splashScreen) splashScreen->Update(_i); } while(0)
+#else
+#define MOZ_SPLASHSCREEN_UPDATE(_i)  do { } while(0)
+#endif
+
 int
 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
 {
+#ifdef MOZ_SPLASHSCREEN
+  nsSplashScreen *splashScreen =
+    nsSplashScreen::GetOrCreate();
+  if (splashScreen)
+    splashScreen->Open();
+#endif
+
   nsresult rv;
   ArgResult ar;
   NS_TIMELINE_MARK("enter main");
 
 #ifdef DEBUG
   if (PR_GetEnv("XRE_MAIN_BREAK"))
     NS_BREAK();
 #endif
@@ -2657,16 +2674,18 @@ XRE_main(int argc, char* argv[], const n
     nsXREAppData* overrideAppData = const_cast<nsXREAppData*>(aAppData);
     rv = XRE_ParseAppData(overrideLF, overrideAppData);
     if (NS_FAILED(rv)) {
       Output(PR_TRUE, "Couldn't read override.ini");
       return 1;
     }
   }
 
+  MOZ_SPLASHSCREEN_UPDATE(10);
+
   ScopedAppData appData(aAppData);
   gAppData = &appData;
 
   // Check sanity and correctness of app data.
 
   if (!appData.name) {
     Output(PR_TRUE, "Error: App:Name not specified in application.ini\n");
     return 1;
@@ -2892,16 +2911,18 @@ XRE_main(int argc, char* argv[], const n
     DumpVersion();
     return 0;
   }
     
 #ifdef NS_TRACE_MALLOC
   gArgc = argc = NS_TraceMallocStartupArgs(gArgc, gArgv);
 #endif
 
+  MOZ_SPLASHSCREEN_UPDATE(20);
+
   {
     nsXREDirProvider dirProvider;
     rv = dirProvider.Initialize(gAppData->directory, gAppData->xreDirectory);
     if (NS_FAILED(rv))
       return 1;
 
     // Check for -register, which registers chrome and then exits immediately.
     ar = CheckArg("register", PR_TRUE);
@@ -3139,16 +3160,18 @@ XRE_main(int argc, char* argv[], const n
       // Write out version
       WriteVersion(profD, version, osABI,
                    dirProvider.GetGREDir(), gAppData->directory);
     }
 
     PRBool needsRestart = PR_FALSE;
     PRBool appInitiatedRestart = PR_FALSE;
 
+    MOZ_SPLASHSCREEN_UPDATE(30);
+
     // Allows the user to forcefully bypass the restart process at their
     // own risk. Useful for debugging or for tinderboxes where child 
     // processes can be problematic.
     {
       // Start the real application
       ScopedXPCOMStartup xpcom;
       rv = xpcom.Initialize();
       NS_ENSURE_SUCCESS(rv, 1); 
@@ -3239,16 +3262,18 @@ XRE_main(int argc, char* argv[], const n
             chromeObserver->Observe(cmdLine, "command-line-startup", nsnull);
           }
 
           NS_TIMELINE_ENTER("appStartup->CreateHiddenWindow");
           rv = appStartup->CreateHiddenWindow();
           NS_TIMELINE_LEAVE("appStartup->CreateHiddenWindow");
           NS_ENSURE_SUCCESS(rv, 1);
 
+          MOZ_SPLASHSCREEN_UPDATE(50);
+
           // Extension Compatibility Checking and Startup
           if (gAppData->flags & NS_XRE_ENABLE_EXTENSION_MANAGER) {
             nsCOMPtr<nsIExtensionManager> em(do_GetService("@mozilla.org/extensions/manager;1"));
             NS_ENSURE_TRUE(em, 1);
 
             if (upgraded) {
               rv = em->CheckForMismatches(&needsRestart);
               if (NS_FAILED(rv)) {
@@ -3299,16 +3324,18 @@ XRE_main(int argc, char* argv[], const n
                                workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
             NS_ENSURE_SUCCESS(rv, 1);
 #endif
 #ifdef MOZ_WIDGET_COCOA
             // Prepare Cocoa's form of Apple Event handling.
             SetupMacApplicationDelegate();
 #endif
 
+            MOZ_SPLASHSCREEN_UPDATE(70);
+
             nsCOMPtr<nsIObserverService> obsService
               (do_GetService("@mozilla.org/observer-service;1"));
             if (obsService)
               obsService->NotifyObservers(nsnull, "final-ui-startup", nsnull);
 
             appStartup->GetShuttingDown(&shuttingDown);
           }
 
@@ -3331,16 +3358,18 @@ XRE_main(int argc, char* argv[], const n
               remoteService->Startup(gAppData->name,
                                      PromiseFlatCString(profileName).get());
 #endif /* MOZ_ENABLE_XREMOTE */
 
             // enable win32 DDE responses and Mac appleevents responses
             nativeApp->Enable();
           }
 
+          MOZ_SPLASHSCREEN_UPDATE(90);
+
           NS_TIMELINE_ENTER("appStartup->Run");
           rv = appStartup->Run();
           NS_TIMELINE_LEAVE("appStartup->Run");
           if (NS_FAILED(rv)) {
             NS_ERROR("failed to run appstartup");
             gLogConsoleErrors = PR_TRUE;
           }
 
@@ -3384,16 +3413,18 @@ XRE_main(int argc, char* argv[], const n
     }
 
     // unlock the profile after ScopedXPCOMStartup object (xpcom) 
     // has gone out of scope.  see bug #386739 for more details
     profileLock->Unlock();
 
     // Restart the app after XPCOM has been shut down cleanly. 
     if (needsRestart) {
+      MOZ_SPLASHSCREEN_UPDATE(90);
+
       if (appInitiatedRestart) {
         RestoreStateForAppInitiatedRestart();
       }
       else {
         char* noEMRestart = PR_GetEnv("NO_EM_RESTART");
         if (noEMRestart && *noEMRestart) {
           PR_SetEnv("NO_EM_RESTART=1");
         }
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsSplashScreen.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is
+ *   mozilla.org
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef NS_SPLASHSCREEN_H_
+#define NS_SPLASHSCREEN_H_
+
+#include "prtypes.h"
+
+/* Note: This is not XPCOM!  This class is used before any Gecko/XPCOM
+ * support has been initialized, so any implementations should take care
+ * to use platform-native methods as much as possible.
+ */
+
+class nsSplashScreen {
+public:
+    // An implementation needs to provide these, to either get
+    // an existing splash screen, or create a new one if GetOrCreate is
+    // used.
+    static nsSplashScreen* GetOrCreate();
+    static nsSplashScreen* Get();
+public:
+    // Display the splash screen if it's not already displayed.
+    // Also resets progress to 0 and the message to empty.
+    virtual void Open() = 0;
+    virtual void Close() = 0;
+
+    /* Update the splash screen to the given progress value (0..100) */
+    virtual void Update(PRInt32 progress) = 0;
+
+    PRBool IsOpen() { return mIsOpen; }
+
+protected:
+    nsSplashScreen() : mIsOpen(PR_FALSE) { }
+    PRBool mIsOpen;
+};
+
+extern "C" {
+    nsSplashScreen *NS_GetSplashScreen(PRBool create);
+    typedef nsSplashScreen* (*NS_GetSplashScreenPtr) (PRBool);
+}
+
+#endif /* NS_SPLASHSCREEN_H_ */
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsSplashScreenDummy.cpp
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is
+ *   mozilla.org
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsSplashScreen.h"
+
+nsSplashScreen*
+nsSplashScreen::Get()
+{
+  return NULL;
+}
+
+nsSplashScreen*
+nsSplashScreen::GetOrCreate()
+{
+  return NULL;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsSplashScreenWin.cpp
@@ -0,0 +1,310 @@
+/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is
+ *   mozilla.org
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsSplashScreen.h"
+
+#include <windows.h>
+
+static ATOM gSplashScreenClass = 0;
+
+class nsSplashScreenWin;
+
+static nsSplashScreenWin *gSplashScreen = NULL;
+
+class nsSplashScreenWin :
+    public nsSplashScreen
+{
+public:
+    nsSplashScreenWin();
+
+    virtual void Open();
+    virtual void Close();
+    virtual void Update(PRInt32 progress);
+
+protected:
+    HWND mDialog;
+    HBITMAP mSplashBitmap, mOldBitmap;
+    HDC mSplashBitmapDC;
+    int mWidth, mHeight;
+
+    static DWORD WINAPI ThreadProc(LPVOID splashScreen);
+
+    static LRESULT CALLBACK DialogProc (HWND hWnd,
+                                        UINT uMsg,
+                                        WPARAM wParam,
+                                        LPARAM lParam);
+
+    void OnPaint(HDC dc, const PAINTSTRUCT *ps);
+
+    PRInt32 mProgress;
+};
+
+nsSplashScreen *
+nsSplashScreen::GetOrCreate()
+{
+    if (!gSplashScreen)
+        gSplashScreen = new nsSplashScreenWin();
+
+    return gSplashScreen;
+}
+
+nsSplashScreen *
+nsSplashScreen::Get()
+{
+    return gSplashScreen;
+}
+
+nsSplashScreenWin::nsSplashScreenWin()
+    : mDialog(NULL), mSplashBitmap(NULL), mOldBitmap(NULL),
+      mSplashBitmapDC(NULL),
+      mWidth(200), mHeight(100),
+      mProgress(-1)
+{
+}
+
+void
+nsSplashScreenWin::Open()
+{
+    if (mIsOpen || mDialog)
+        return;
+
+    mIsOpen = PR_TRUE;
+
+    if (gSplashScreenClass == 0) {
+        WNDCLASS wc;
+        memset(&wc, 0, sizeof(WNDCLASS));
+
+        wc.style = CS_NOCLOSE;
+        wc.lpfnWndProc = (WNDPROC) DialogProc;
+        wc.hInstance = GetModuleHandle(0);
+        wc.hIcon = NULL;
+        wc.hCursor = NULL;
+        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+        wc.lpszMenuName = NULL;
+        wc.lpszClassName = TEXT("MozillaSplashScreen");
+
+        gSplashScreenClass = RegisterClass(&wc);
+    }
+
+    if (mSplashBitmap == NULL) {
+        wchar_t path[_MAX_PATH];
+        if (::GetModuleFileNameW(0, path, _MAX_PATH)) {
+            wchar_t *slash = wcsrchr(path, '\\');
+            if (slash != NULL)
+                slash[1] = 0;
+
+            wcscat(path, L"splash.bmp");
+
+#ifdef WINCE
+            mSplashBitmap = ::SHLoadDIBitmap(path);
+#else
+#warning splashscreen needs some code to load bitmaps on non-WinCE
+            mSplashBitmap = nsnull;
+#endif
+
+            if (mSplashBitmap) {
+                BITMAP bmo;
+                if (GetObject(mSplashBitmap, sizeof(BITMAP), &bmo) > 0) {
+                    mWidth = bmo.bmWidth;
+                    mHeight = bmo.bmHeight;
+
+                    mSplashBitmapDC = CreateCompatibleDC(NULL);
+                    mOldBitmap = (HBITMAP) SelectObject(mSplashBitmapDC, mSplashBitmap);
+                } else {
+                    DeleteObject(mSplashBitmap);
+                    mSplashBitmap = NULL;
+                }
+            }
+        }
+    }
+
+    DWORD threadID = 0;
+    CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ThreadProc, this, 0, &threadID);
+}
+
+DWORD WINAPI
+nsSplashScreenWin::ThreadProc(LPVOID splashScreen)
+{
+    nsSplashScreenWin *sp = (nsSplashScreenWin*) splashScreen;
+
+    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
+    int screenHeight = GetSystemMetrics(SM_CYSCREEN);
+
+    HWND dlg = CreateWindowEx
+        (WS_EX_NOACTIVATE /* | WS_EX_TOPMOST | WS_EX_TOOLWINDOW*/,
+         TEXT("MozillaSplashScreen"),
+         TEXT("Starting up..."),
+         WS_POPUP | WS_BORDER,
+         (screenWidth - sp->mWidth) / 2,
+         (screenHeight - sp->mHeight) / 2,
+         sp->mWidth, sp->mHeight,
+         HWND_DESKTOP,
+         NULL,
+         GetModuleHandle(0),
+         NULL);
+
+    sp->mDialog = dlg;
+
+    ShowWindow(dlg, SW_SHOW);
+    SetForegroundWindow(dlg);
+
+    MSG msg;
+    while (::GetMessage(&msg, NULL, 0, 0)) {
+        DispatchMessage(&msg);
+    }
+
+    // window was destroyed, nothing to do
+    return 0;
+}
+
+void
+nsSplashScreenWin::Close()
+{
+    if (mDialog) {
+        ShowWindow(mDialog, SW_HIDE);
+        PostMessage(mDialog, WM_QUIT, 0, 0);
+        mDialog = NULL;
+    }
+
+    if (mSplashBitmap) {
+        SelectObject(mSplashBitmapDC, mOldBitmap);
+        DeleteObject(mSplashBitmapDC);
+        DeleteObject(mSplashBitmap);
+        mOldBitmap = NULL;
+        mSplashBitmapDC = NULL;
+        mSplashBitmap = NULL;
+    }
+
+    mIsOpen = PR_FALSE;
+}
+
+void
+nsSplashScreenWin::Update(PRInt32 progress)
+{
+    if (progress >= 0)
+        mProgress = progress > 100 ? 100 : progress;
+
+    InvalidateRect(mDialog, NULL, FALSE);
+}
+
+void
+nsSplashScreenWin::OnPaint(HDC dc, const PAINTSTRUCT *ps)
+{
+    if (mSplashBitmapDC) {
+        BitBlt(dc,
+               0, 0, gSplashScreen->mWidth, gSplashScreen->mHeight,
+               gSplashScreen->mSplashBitmapDC,
+               0, 0,
+               SRCCOPY);
+    } else {
+        HBRUSH bkgr = CreateSolidBrush(RGB(200,200,200));
+        RECT r = { 0, 0, mWidth, mHeight };
+        FillRect(dc, &r, bkgr);
+        DeleteObject(bkgr);
+    }
+
+#define BOTTOM_OFFSET 10
+#define PROGRESS_HEIGHT 11
+
+    if (mProgress != -1) {
+        HBRUSH border = CreateSolidBrush(RGB(0x33,0x33,0x99));
+        HBRUSH fill = CreateSolidBrush(RGB(0x33,0x66,0xFF));
+
+        // the progress bar goes 15 pixels above the bottom of the window,
+        // and is 2/3 of the width.  The outer border is 11 px in height,
+        // which will be inset by 2 to draw the fill.
+        int leftBorder = (mWidth * 2 / 3) / 2;
+
+        // left, top, right, bottom
+        RECT outerRect = { leftBorder, mHeight - BOTTOM_OFFSET - PROGRESS_HEIGHT,
+                           mWidth - leftBorder, mHeight - BOTTOM_OFFSET };
+
+
+	HBRUSH oldBrush = (HBRUSH)SelectObject(dc, border);
+        MoveToEx(dc, outerRect.left, outerRect.top, (LPPOINT) NULL);
+        LineTo(dc, outerRect.right, outerRect.top);
+        LineTo(dc, outerRect.right, outerRect.bottom);
+        LineTo(dc, outerRect.left, outerRect.bottom);
+        LineTo(dc, outerRect.left, outerRect.top);
+        SelectObject(dc, oldBrush);
+
+        outerRect.top += 2;
+        outerRect.left += 2;
+        outerRect.right -= 2;
+        outerRect.bottom -= 1;
+
+        outerRect.right = outerRect.left + (outerRect.right - outerRect.left) * mProgress / 100;
+        FillRect(dc, &outerRect, fill);
+
+        DeleteObject(border);
+        DeleteObject(fill);
+    }
+}
+
+LRESULT CALLBACK
+nsSplashScreenWin::DialogProc (HWND hWnd,
+                               UINT uMsg,
+                               WPARAM wParam,
+                               LPARAM lParam)
+{
+    switch (uMsg) {
+        case WM_PAINT: {
+            PAINTSTRUCT ps;
+            HDC dc = BeginPaint(hWnd, &ps);
+
+            if (gSplashScreen)
+                gSplashScreen->OnPaint(dc, &ps);
+
+            EndPaint(hWnd, &ps);
+            return TRUE;
+        }
+            break;
+
+        case WM_DESTROY:
+            return TRUE;
+
+        case WM_QUIT:
+            DestroyWindow(hWnd);
+            return TRUE;
+
+        default:
+            return DefWindowProc(hWnd, uMsg, wParam, lParam);
+    }
+
+    return FALSE;
+}
--- a/widget/src/windows/Makefile.in
+++ b/widget/src/windows/Makefile.in
@@ -127,16 +127,17 @@ endif # BUILD_STATIC_LIBS
 
 
 EXPORTS		= nsdefs.h
 
 LOCAL_INCLUDES	= \
 		-I. \
 		-I$(srcdir)/../xpwidgets \
 		-I$(srcdir) \
+		-I$(topsrcdir)/toolkit/xre \
 		$(NULL)
 
 FORCE_STATIC_LIB = 1
 
 ifdef WINCE
 EXTRA_DSO_LDOPTS += ddraw.lib
 endif
 
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -81,16 +81,20 @@
 #include "nsFunctionTimer.h"
 #endif
 
 // this isn't ideal, we should figure out how to export
 // the #defines here; need this to figure out if we have
 // the DirectDraw surface or not.
 #include "cairo-features.h"
 
+#if defined(MOZ_SPLASHSCREEN)
+#include "nsSplashScreen.h"
+#endif
+
 #ifdef WINCE
 
 #include "aygshell.h"
 #include "imm.h"
 
 #ifdef WINCE_WINDOWS_MOBILE
 #define WINCE_HAVE_SOFTKB
 #include "tpcshell.h"
@@ -1638,16 +1642,29 @@ PRBool nsWindow::CanTakeFocus()
       return PR_TRUE;
     }
   }
   return PR_FALSE;
 }
 
 NS_METHOD nsWindow::Show(PRBool bState)
 {
+#if defined(MOZ_SPLASHSCREEN)
+  // we're about to show the first toplevel window,
+  // so kill off any splash screen if we had one
+  nsSplashScreen *splash = nsSplashScreen::Get();
+  if (splash && splash->IsOpen() && mWnd && bState &&
+      (mWindowType == eWindowType_toplevel ||
+       mWindowType == eWindowType_dialog ||
+       mWindowType == eWindowType_popup))
+  {
+    splash->Close();
+  }
+#endif
+
   PRBool wasVisible = mIsVisible;
   // Set the status now so that anyone asking during ShowWindow or
   // SetWindowPos would get the correct answer.
   mIsVisible = bState;
 
   if (mWnd) {
     if (bState) {
       if (!wasVisible && mWindowType == eWindowType_toplevel) {