From 9b02e2ca3fc9fc049903aaaee25a5d323f9c2e87 Mon Sep 17 00:00:00 2001 From: "law%netscape.com" Date: Wed, 23 May 2001 06:04:39 +0000 Subject: [PATCH] Bug 75599; enabling the infamous '-turbo' cmd line switch; makes nsINativeAppSupport scriptable, adds Win32 code to handle -turbo switch; and tweaks window close logic in navigator.js to 'cache' a browser window; r=cathleen, sr=alecf git-svn-id: svn://10.0.0.236/trunk@95812 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpfe/appshell/public/MANIFEST | 1 - mozilla/xpfe/appshell/public/MANIFEST_IDL | 1 + mozilla/xpfe/appshell/public/Makefile.in | 2 +- mozilla/xpfe/appshell/public/makefile.win | 2 +- ...veAppSupport.h => nsINativeAppSupport.idl} | 66 +++--- mozilla/xpfe/appshell/src/nsAppShellService.h | 1 + mozilla/xpfe/bootstrap/nsAppRunner.cpp | 43 +++- mozilla/xpfe/bootstrap/nsNativeAppSupport.h | 1 + .../xpfe/bootstrap/nsNativeAppSupportBase.cpp | 33 ++- .../xpfe/bootstrap/nsNativeAppSupportBase.h | 11 +- .../xpfe/bootstrap/nsNativeAppSupportWin.cpp | 196 ++++++++++++++++-- .../browser/resources/content/navigator.js | 68 ++++-- .../browser/resources/content/navigator.xul | 2 +- .../resources/content/navigatorOverlay.xul | 2 +- .../startup/public/nsINativeAppSupport.idl | 158 ++++++++++++++ 15 files changed, 509 insertions(+), 78 deletions(-) rename mozilla/xpfe/appshell/public/{nsINativeAppSupport.h => nsINativeAppSupport.idl} (74%) create mode 100644 mozilla/xpfe/components/startup/public/nsINativeAppSupport.idl diff --git a/mozilla/xpfe/appshell/public/MANIFEST b/mozilla/xpfe/appshell/public/MANIFEST index abe22e16055..9679594c848 100644 --- a/mozilla/xpfe/appshell/public/MANIFEST +++ b/mozilla/xpfe/appshell/public/MANIFEST @@ -8,4 +8,3 @@ nsIWebShellWindow.h nsIDOMXPConnectFactory.h nsINetSupportDialogService.h nsISplashScreen.h -nsINativeAppSupport.h diff --git a/mozilla/xpfe/appshell/public/MANIFEST_IDL b/mozilla/xpfe/appshell/public/MANIFEST_IDL index 237f42e821c..aa34bba8b55 100644 --- a/mozilla/xpfe/appshell/public/MANIFEST_IDL +++ b/mozilla/xpfe/appshell/public/MANIFEST_IDL @@ -7,4 +7,5 @@ nsICmdLineService.idl nsIWindowMediator.idl nsIXULWindow.idl nsIUserInfo.idl +nsINativeAppSupport.idl diff --git a/mozilla/xpfe/appshell/public/Makefile.in b/mozilla/xpfe/appshell/public/Makefile.in index a3bdd9b9348..615a0b393ac 100644 --- a/mozilla/xpfe/appshell/public/Makefile.in +++ b/mozilla/xpfe/appshell/public/Makefile.in @@ -34,7 +34,6 @@ EXPORTS = \ nsAppShellCIDs.h \ nsIDOMXPConnectFactory.h \ nsISplashScreen.h \ - nsINativeAppSupport.h \ $(NULL) XPIDLSRCS = \ @@ -45,6 +44,7 @@ XPIDLSRCS = \ nsIXULWindow.idl \ nsIUserInfo.idl \ nsITimingService.idl \ + nsINativeAppSupport.idl \ $(NULL) ifeq ($(MOZ_WIDGET_TOOLKIT),mac) diff --git a/mozilla/xpfe/appshell/public/makefile.win b/mozilla/xpfe/appshell/public/makefile.win index c25d5f3fbbd..8bb5e0065f1 100644 --- a/mozilla/xpfe/appshell/public/makefile.win +++ b/mozilla/xpfe/appshell/public/makefile.win @@ -33,13 +33,13 @@ XPIDLSRCS = \ .\nsIXULWindow.idl \ .\nsIUserInfo.idl \ .\nsITimingService.idl \ + .\nsINativeAppSupport.idl \ $(NULL) EXPORTS = \ nsIWebShellWindow.h \ nsAppShellCIDs.h \ nsISplashScreen.h \ - nsINativeAppSupport.h \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/xpfe/appshell/public/nsINativeAppSupport.h b/mozilla/xpfe/appshell/public/nsINativeAppSupport.idl similarity index 74% rename from mozilla/xpfe/appshell/public/nsINativeAppSupport.h rename to mozilla/xpfe/appshell/public/nsINativeAppSupport.idl index c9c9abe92bd..6305162bf01 100644 --- a/mozilla/xpfe/appshell/public/nsINativeAppSupport.h +++ b/mozilla/xpfe/appshell/public/nsINativeAppSupport.idl @@ -20,15 +20,8 @@ * Contributor(s): * Bill Law */ -#ifndef nsINativeAppSupport_h__ -#define nsINativeAppSupport_h__ -#include "nsISupports.h" -#include "nsISplashScreen.h" - -// 5fdf8480-1f98-11d4-8077-00600811a9c3 -#define NS_INATIVEAPPSUPPORT_IID \ - { 0x5fdf8480, 0x1f98, 0x11d4, { 0x80, 0x77, 0x00, 0x60, 0x08, 0x11, 0xa9, 0xc3 } } +#include "nsISupports.idl" /* nsINativeAppSupport * @@ -48,10 +41,15 @@ * interface is instantiated by somewhat unconventional means. * * To create the implementor of this interface, you call the function - * NS_CreateNativeAppSupport. + * NS_CreateNativeAppSupport. This is done in the startup code + * in mozilla/xpfe/bootstrap. + * + * You can use this interface by obtaining an instance via the + * "nativeAppSupport" attribute of the nsIAppShellService + * interface/service. * * The interface provides these functions: - * Start - You call this to inform the native app support that the + * start - You call this to inform the native app support that the * application is starting. In addition, it serves as a * query as to whether the application should continue to * run. In that respect, it is rougly equivalent to the @@ -69,7 +67,7 @@ * successfully passed to the instance of the * application acting as a DDE server. * - * Stop - You call this to inform the native app support that the + * stop - You call this to inform the native app support that the * application *wishes* to terminate. If the returned boolean * value is PR_FALSE, then the application should continue * (as if there were still additional top-level windows open). @@ -80,7 +78,7 @@ * acting as DDE clients, then this function will * return PR_FALSE. * - * Quit - Like Stop, but this method *forces* termination (or more + * quit - Like Stop, but this method *forces* termination (or more * precisely, indicates that the application is about to be * terminated regardless of what a call to Stop might have * returned. @@ -112,31 +110,49 @@ * is quitting. For this reason, the call to Quit * should be deferred as long as possible. * - * ShowSplashScreen - Causes the platform-specific splash screen to be + * showSplashScreen - Causes the platform-specific splash screen to be * displayed. This is a replacement for the old * method of invoking the Show() method on the * nsISplashScreen interface obtained by calling * NS_CreateSplashScreen. * - * HideSplashScreen - Causes the splash screen to be removed (if it is + * hideSplashScreen - Causes the splash screen to be removed (if it is * being shown). This replaces the old method of * invoking the Hide() method on the nsISplashScreen * interface maintained by the app shell service. * + * cacheBrowserWindow - Takes an about-to-be-closed navigator window + * and "caches it" for later use. It returns an + * indicator of whether the window was actually + * cached. If that result is false, then the + * caller should close the window normally. + * + * This interface has these attributes: + * isServerMode - Boolean attribute indicating whether the application + * is running in "server mode." Server mode means the + * application was started to pre-load shared-libraries, + * initialize services, and open a hidden Navigator window + * in order to quickly surface that window when the user + * launches the application in the normal mode. This + * mode is currently Win32-only (and may really only make + * sense there) and is intended to be initiated from the + * Windows startup folder at system initialization. */ -class nsINativeAppSupport : public nsISupports { -public: - NS_DEFINE_STATIC_IID_ACCESSOR( NS_INATIVEAPPSUPPORT_IID ) +interface nsIDOMWindow; + +[scriptable, uuid(5fdf8480-1f98-11d4-8077-00600811a9c3)] +interface nsINativeAppSupport : nsISupports { // Startup/shutdown. - NS_IMETHOD Start( PRBool *result ) = 0; - NS_IMETHOD Stop( PRBool *result ) = 0; - NS_IMETHOD Quit() = 0; + boolean start(); + boolean stop(); + void quit(); // Splash screen functions. - NS_IMETHOD ShowSplashScreen() = 0; - NS_IMETHOD HideSplashScreen() = 0; + void showSplashScreen(); + void hideSplashScreen(); -}; // class nsINativeAppSupport - -#endif // nsINativeAppSupport_h__ + // Server mode. + attribute boolean isServerMode; + boolean cacheBrowserWindow(in nsIDOMWindow aWindow); +}; diff --git a/mozilla/xpfe/appshell/src/nsAppShellService.h b/mozilla/xpfe/appshell/src/nsAppShellService.h index a8b98ec3331..f293b682c76 100644 --- a/mozilla/xpfe/appshell/src/nsAppShellService.h +++ b/mozilla/xpfe/appshell/src/nsAppShellService.h @@ -32,6 +32,7 @@ //Interfaces Needed #include "nsIXULWindow.h" #include "nsIWindowMediator.h" +#include "nsISplashScreen.h" class nsAppShellService : public nsIAppShellService, public nsIObserver, diff --git a/mozilla/xpfe/bootstrap/nsAppRunner.cpp b/mozilla/xpfe/bootstrap/nsAppRunner.cpp index fdd1dd26967..f6a38ac571a 100644 --- a/mozilla/xpfe/bootstrap/nsAppRunner.cpp +++ b/mozilla/xpfe/bootstrap/nsAppRunner.cpp @@ -69,6 +69,7 @@ // Interfaces Needed #include "nsIXULWindow.h" #include "nsIWebBrowserChrome.h" +#include "nsIDocShell.h" // for X remote support #ifdef MOZ_ENABLE_XREMOTE @@ -255,7 +256,8 @@ static nsresult OpenWindow(const char *urlstr, const PRUnichar *args) static nsresult OpenChromeURL( const char * urlstr, PRInt32 height = NS_SIZETOCONTENT, - PRInt32 width = NS_SIZETOCONTENT ) + PRInt32 width = NS_SIZETOCONTENT, + nsIDOMWindow **aResult = nsnull ) { #ifdef DEBUG_CMD_LINE printf("OpenChromeURL(%s,%d,%d)\n",urlstr,height,width); @@ -276,6 +278,20 @@ OpenChromeURL( const char * urlstr, nsIWebBrowserChrome::CHROME_ALL, width, height, getter_AddRefs(newWindow)); + // Check if caller wants resulting window. + if(aResult) { + // Always return 0 if we don't have a window. + *aResult = nsnull; + // If window open was OK, then pass result as nsIDOMWindow. + if (NS_SUCCEEDED(rv) && newWindow) { + nsCOMPtr docShell; + if (NS_SUCCEEDED(newWindow->GetDocShell(getter_AddRefs(docShell)))) { + nsCOMPtr newDOMWin = do_GetInterface(docShell); + *aResult = newDOMWin; + NS_IF_ADDREF(*aResult); + } + } + } return rv; } @@ -620,7 +636,7 @@ static nsresult DoOnShutdown() } -static nsresult OpenBrowserWindow(PRInt32 height, PRInt32 width) +static nsresult OpenBrowserWindow(PRInt32 height, PRInt32 width, nsIDOMWindow **aResult) { nsresult rv; nsCOMPtr handler(do_GetService(NS_BROWSERSTARTUPHANDLER_CONTRACTID, &rv)); @@ -630,7 +646,7 @@ static nsresult OpenBrowserWindow(PRInt32 height, PRInt32 width) rv = handler->GetChromeUrlForTask(getter_Copies(chromeUrlForTask)); if (NS_FAILED(rv)) return rv; - rv = OpenChromeURL(chromeUrlForTask, height, width ); + rv = OpenChromeURL(chromeUrlForTask, height, width, aResult); if (NS_FAILED(rv)) return rv; return rv; @@ -712,7 +728,26 @@ static nsresult Ensure1Window( nsICmdLineService* cmdLineArgs) if ((const char*)tempString) PR_sscanf(tempString, "%d", &height); - rv = OpenBrowserWindow(height, width); + nsCOMPtr browserWin; + rv = OpenBrowserWindow(height, width, getter_AddRefs(browserWin)); + + // See if we're in running in server mode. + if (NS_SUCCEEDED(rv) && browserWin) { + nsCOMPtr appShellService(do_GetService(kAppShellServiceCID)); + if (appShellService) { + nsCOMPtr nativeApp; + appShellService->GetNativeAppSupport(getter_AddRefs(nativeApp)); + if (nativeApp) { + PRBool serverMode = PR_FALSE; + nativeApp->GetIsServerMode(&serverMode); + if (serverMode) { + // Then cache (i.e., hide) this browser window. + PRBool cached = PR_FALSE; + nativeApp->CacheBrowserWindow(browserWin, &cached); + } + } + } + } } } return rv; diff --git a/mozilla/xpfe/bootstrap/nsNativeAppSupport.h b/mozilla/xpfe/bootstrap/nsNativeAppSupport.h index 6ef5267d585..6f5bb1e6b4c 100644 --- a/mozilla/xpfe/bootstrap/nsNativeAppSupport.h +++ b/mozilla/xpfe/bootstrap/nsNativeAppSupport.h @@ -21,6 +21,7 @@ */ #include "nsINativeAppSupport.h" +#include "nsISplashScreen.h" nsresult NS_CreateSplashScreen( nsISplashScreen **aResult ); diff --git a/mozilla/xpfe/bootstrap/nsNativeAppSupportBase.cpp b/mozilla/xpfe/bootstrap/nsNativeAppSupportBase.cpp index 0b7dd38cd98..bf42be1a669 100644 --- a/mozilla/xpfe/bootstrap/nsNativeAppSupportBase.cpp +++ b/mozilla/xpfe/bootstrap/nsNativeAppSupportBase.cpp @@ -24,11 +24,11 @@ nsNativeAppSupportBase::nsNativeAppSupportBase() : mRefCnt( 0 ), - mSplash( 0 ) { + mSplash( 0 ), + mServerMode( PR_FALSE ) { } nsNativeAppSupportBase::~nsNativeAppSupportBase() { - NS_IF_RELEASE( mSplash ); } // Start answer defaults to OK. @@ -57,7 +57,7 @@ nsNativeAppSupportBase::Quit() { NS_IMETHODIMP nsNativeAppSupportBase::ShowSplashScreen() { if ( !mSplash ) { - nsresult rv = CreateSplashScreen( &mSplash ); + nsresult rv = CreateSplashScreen( getter_AddRefs( mSplash ) ); } if ( mSplash ) { mSplash->Show(); @@ -70,14 +70,35 @@ NS_IMETHODIMP nsNativeAppSupportBase::HideSplashScreen() { // See if there is a splash screen object. if ( mSplash ) { + // Unhook it. + nsCOMPtr splash = mSplash; + mSplash = 0; // Hide it. - mSplash->Hide(); - // Release it. - NS_RELEASE( mSplash ); + splash->Hide(); } return NS_OK; } +NS_IMETHODIMP +nsNativeAppSupportBase::SetIsServerMode(PRBool aIsServerMode) { + mServerMode = aIsServerMode; + return NS_OK; +} + +NS_IMETHODIMP +nsNativeAppSupportBase::GetIsServerMode(PRBool *aIsServerMode) { + NS_ENSURE_ARG( aIsServerMode ); + *aIsServerMode = mServerMode; + return NS_OK; +} + +NS_IMETHODIMP +nsNativeAppSupportBase::CacheBrowserWindow(nsIDOMWindow *aWindow, PRBool *aResult) { + NS_ENSURE_ARG( aResult ); + *aResult = PR_FALSE; + return NS_OK; +} + // Default implementation doesn't have a splash screen. NS_IMETHODIMP nsNativeAppSupportBase::CreateSplashScreen( nsISplashScreen **splash ) { diff --git a/mozilla/xpfe/bootstrap/nsNativeAppSupportBase.h b/mozilla/xpfe/bootstrap/nsNativeAppSupportBase.h index cf6b0f765b6..d5e5c84c494 100644 --- a/mozilla/xpfe/bootstrap/nsNativeAppSupportBase.h +++ b/mozilla/xpfe/bootstrap/nsNativeAppSupportBase.h @@ -22,6 +22,8 @@ */ #include "nsNativeAppSupport.h" +#include "nsCOMPtr.h" + // nsNativeAppSupportBase // // This is a default implementation of the nsINativeAppSupport interface @@ -39,11 +41,7 @@ public: ~nsNativeAppSupportBase(); // nsINativeAppSupport methods. - NS_IMETHOD Start( PRBool *result ); - NS_IMETHOD Stop( PRBool *result ); - NS_IMETHOD Quit(); - NS_IMETHOD ShowSplashScreen(); - NS_IMETHOD HideSplashScreen(); + NS_DECL_NSINATIVEAPPSUPPORT NS_IMETHOD CreateSplashScreen( nsISplashScreen **splash ); @@ -53,6 +51,7 @@ public: NS_IMETHOD QueryInterface( const nsIID &iid, void**p ); nsrefcnt mRefCnt; - nsISplashScreen *mSplash; + nsCOMPtr mSplash; + PRBool mServerMode; }; // class nsSplashScreenWin diff --git a/mozilla/xpfe/bootstrap/nsNativeAppSupportWin.cpp b/mozilla/xpfe/bootstrap/nsNativeAppSupportWin.cpp index 0b38210efff..1b092274b0c 100644 --- a/mozilla/xpfe/bootstrap/nsNativeAppSupportWin.cpp +++ b/mozilla/xpfe/bootstrap/nsNativeAppSupportWin.cpp @@ -32,6 +32,11 @@ #include "nsIDOMWindow.h" #include "nsISupportsPrimitives.h" #include "nsIWindowWatcher.h" +#include "nsIDOMWindowInternal.h" +#include "nsIScriptGlobalObject.h" +#include "nsIDocShell.h" +#include "nsIBaseWindow.h" +#include "nsIAppShellService.h" #include #include #include @@ -242,6 +247,8 @@ public: NS_IMETHOD Start( PRBool *aResult ); NS_IMETHOD Stop( PRBool *aResult ); NS_IMETHOD Quit(); + NS_IMETHOD SetIsServerMode( PRBool aIsServerMode ); + NS_IMETHOD CacheBrowserWindow( nsIDOMWindow *aWindow, PRBool *aResult ); // The "old" Start method (renamed). NS_IMETHOD StartDDE(); @@ -249,7 +256,7 @@ public: // Utility function to handle a Win32-specific command line // option: "-console", which dynamically creates a Windows // console. - static void CheckConsole(); + void CheckConsole(); private: static HDDEDATA CALLBACK HandleDDENotification( UINT uType, @@ -262,7 +269,10 @@ private: ULONG dwData2 ); static void HandleRequest( LPBYTE request ); static nsresult GetCmdLineArgs( LPBYTE request, nsICmdLineService **aResult ); - static nsresult OpenWindow( const char *urlstr, const char *args ); + static nsresult OpenWindow( const char *urlstr, const char *args, nsIDOMWindow **aResult = 0 ); + static nsresult OpenBrowserWindow( const char *args ); + static nsresult ReParent( nsIDOMWindowInternal *window, HWND newParent ); + static nsCOMPtr mCachedWin; static int mConversations; static HSZ mApplication, mTopic; static DWORD mInstance; @@ -493,6 +503,18 @@ nsNativeAppSupportWin::CheckConsole() { } // Don't bother doing this more than once. break; + } else if ( strcmp( "-turbo", __argv[i] ) == 0 + || + strcmp( "/turbo", __argv[i] ) == 0 + || + strcmp( "-server", __argv[i] ) == 0 + || + strcmp( "/server", __argv[i] ) == 0 ) { + // Start in server mode (and suppress splash screen). + SetIsServerMode( PR_TRUE ); + __argv[i] = "-nosplash"; // Bit of a hack, but it works! + // Ignore other args. + break; } } return; @@ -503,9 +525,12 @@ nsNativeAppSupportWin::CheckConsole() { nsresult NS_CreateNativeAppSupport( nsINativeAppSupport **aResult ) { if ( aResult ) { - *aResult = new nsNativeAppSupportWin; - if ( *aResult ) { - NS_ADDREF( *aResult ); + nsNativeAppSupportWin *pNative = new nsNativeAppSupportWin; + if ( pNative ) { + *aResult = pNative; + NS_ADDREF( *aResult ); + // Check for dynamic console creation request. + pNative->CheckConsole(); } else { return NS_ERROR_OUT_OF_MEMORY; } @@ -513,8 +538,6 @@ NS_CreateNativeAppSupport( nsINativeAppSupport **aResult ) { return NS_ERROR_NULL_POINTER; } - // Check for dynamic console creation request. - nsNativeAppSupportWin::CheckConsole(); return NS_OK; } @@ -553,6 +576,7 @@ NS_CreateSplashScreen( nsISplashScreen **aResult ) { #define MOZ_DDE_EXEC_TIMEOUT 15000 // Static member definitions. +nsCOMPtr nsNativeAppSupportWin::mCachedWin = 0; int nsNativeAppSupportWin::mConversations = 0; HSZ nsNativeAppSupportWin::mApplication = 0; HSZ nsNativeAppSupportWin::mTopic = 0; @@ -613,7 +637,7 @@ struct MessageWindow { 0 ) ), // create struct NS_ERROR_FAILURE ); - #ifdef MOZ_DEBUG_DDE + #if MOZ_DEBUG_DDE printf( "Message window = 0x%08X\n", (int)mHandle ); #endif @@ -632,7 +656,7 @@ struct MessageWindow { if ( msg == WM_COPYDATA ) { // This is an incoming request. COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lp; - #ifdef MOZ_DEBUG_DDE + #if MOZ_DEBUG_DDE printf( "Incoming request: %s\n", (const char*)cds->lpData ); #endif (void)nsNativeAppSupportWin::HandleRequest( (LPBYTE)cds->lpData ); @@ -668,9 +692,9 @@ nsNativeAppSupportWin::Start( PRBool *aResult ) { *aResult = PR_FALSE; // Grab mutex first. - int retval; - UINT id = ID_DDE_APPLICATION_NAME; - retval = LoadString( (HINSTANCE) NULL, id, (LPTSTR) nameBuffer, sizeof(nameBuffer) ); + int retval; + UINT id = ID_DDE_APPLICATION_NAME; + retval = LoadString( (HINSTANCE) NULL, id, (LPTSTR) nameBuffer, sizeof(nameBuffer) ); if ( retval == 0 ) { // No app name; just keep running. *aResult = PR_TRUE; @@ -917,7 +941,7 @@ nsNativeAppSupportWin::HandleRequest( LPBYTE request ) { #if MOZ_DEBUG_DDE printf( "Launching browser on url [%s]...\n", (const char*)arg ); #endif - (void)OpenWindow( "chrome://navigator/content/", arg ); + (void)OpenBrowserWindow( arg ); } else if (NS_SUCCEEDED(args->GetCmdLineValue("-chrome", getter_Copies(arg))) && (const char*)arg ) { @@ -941,6 +965,16 @@ nsNativeAppSupportWin::HandleRequest( LPBYTE request ) { printf( "Launching mail...\n" ); #endif (void)OpenWindow( "chrome://messenger/content/", "" ); + } else if ( NS_SUCCEEDED( args->GetCmdLineValue( "-kill", getter_Copies(arg))) && + (const char*)arg ) { + // Turn off server mode. + nsCOMPtr appShell = do_GetService( "@mozilla.org/appshell/appShellService;1" ); + nsCOMPtr native; + if ( appShell && + NS_SUCCEEDED( appShell->GetNativeAppSupport( getter_AddRefs( native ) ) ) && + native ) { + native->SetIsServerMode( PR_FALSE ); + } } else { #if MOZ_DEBUG_DDE printf( "Unknown request [%s]\n", (char*) request ); @@ -957,9 +991,9 @@ nsNativeAppSupportWin::HandleRequest( LPBYTE request ) { if (defaultArgs) { nsCString url; url.AssignWithConversion( defaultArgs ); - OpenWindow("chrome://navigator/content/", (const char*)url); + OpenBrowserWindow((const char*)url); } else { - OpenWindow("chrome://navigator/content/", "about:blank"); + OpenBrowserWindow("about:blank"); } } @@ -1123,10 +1157,14 @@ nsNativeAppSupportWin::GetCmdLineArgs( LPBYTE request, nsICmdLineService **aResu } nsresult -nsNativeAppSupportWin::OpenWindow( const char*urlstr, const char *args ) { +nsNativeAppSupportWin::OpenWindow( const char*urlstr, const char *args, nsIDOMWindow **aResult ) { nsresult rv = NS_ERROR_FAILURE; + if ( aResult ) { + *aResult = 0; + } + nsCOMPtr wwatch(do_GetService("@mozilla.org/embedcomp/window-watcher;1")); nsCOMPtr sarg(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); if (sarg) @@ -1136,10 +1174,134 @@ nsNativeAppSupportWin::OpenWindow( const char*urlstr, const char *args ) { nsCOMPtr newWindow; rv = wwatch->OpenWindow(0, urlstr, "_blank", "chrome,dialog=no,all", sarg, getter_AddRefs(newWindow)); -#ifdef MOZ_DEBUG_DDE + if ( aResult ) { + // Caller wants resulting window. + *aResult = newWindow; + NS_IF_ADDREF( *aResult ); + } +#if MOZ_DEBUG_DDE } else { printf("Get WindowWatcher (or create string) failed\n"); #endif } return rv; } + +static char procPropertyName[] = "MozillaProcProperty"; + +// Subclass procedure used to filter out WM_SETFOCUS messages while reparenting. +static LRESULT CALLBACK focusFilterProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { + if ( uMsg == WM_SETFOCUS ) { + // Don't let Mozilla's window procedure see this. + return 0; + } else { + // Pass on all other messages to Mozilla's window proc. + HANDLE oldProc = ::GetProp( hwnd, procPropertyName ); + if ( oldProc ) { + return ::CallWindowProc( (WNDPROC)oldProc, hwnd, uMsg, wParam, lParam ); + } else { + // Last resort is the default window proc. + return ::DefWindowProc( hwnd, uMsg, wParam, lParam ); + } + } +} + +nsresult +nsNativeAppSupportWin::ReParent( nsIDOMWindowInternal *window, HWND newParent ) { + nsCOMPtr ppScriptGlobalObj( do_QueryInterface(window) ); + if ( !ppScriptGlobalObj ) { + return NS_ERROR_FAILURE; + } + nsCOMPtr ppDocShell; + ppScriptGlobalObj->GetDocShell( getter_AddRefs( ppDocShell ) ); + if ( !ppDocShell ) { + return NS_ERROR_FAILURE; + } + nsCOMPtr ppBaseWindow( do_QueryInterface( ppDocShell ) ); + if ( !ppBaseWindow ) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr ppWidget; + ppBaseWindow->GetMainWidget( getter_AddRefs( ppWidget ) ); + HWND hMainFrame = (HWND)ppWidget->GetNativeData( NS_NATIVE_WIDGET ); + if ( !hMainFrame ) { + return NS_ERROR_FAILURE; + } + + // Filter out WM_SETFOCUS messages while reparenting to + // other than the desktop. + // + // For some reason, Windows generates one and it causes + // our focus/activation code to assert. + LONG oldProc = 0; + if ( newParent ) { + // Subclass the window. + oldProc = ::SetWindowLong( hMainFrame, + GWL_WNDPROC, + (LONG)(WNDPROC)focusFilterProc ); + + // Store old procedure in window so it is available within + // focusFilterProc. + ::SetProp( hMainFrame, procPropertyName, (HANDLE)oldProc ); + } + + // Reset the parent. + ::SetParent( hMainFrame, newParent ); + + // Restore old procedure. + if ( newParent ) { + ::SetWindowLong( hMainFrame, GWL_WNDPROC, oldProc ); + ::RemoveProp( hMainFrame, procPropertyName ); + } + + return NS_OK; +} + +nsresult +nsNativeAppSupportWin::OpenBrowserWindow( const char *args ) { + nsresult rv = NS_OK; + // Check if we have a cached (hidden) window. + if ( mCachedWin ) { + nsCOMPtr win = mCachedWin; + // Drop window from cache. + mCachedWin = 0; + // Show it. + ReParent( win, 0 ); + } else { + // No cached window, open a new one. + rv = OpenWindow( "chrome://navigator/content", args ); + } + return rv; +} + +NS_IMETHODIMP +nsNativeAppSupportWin::SetIsServerMode( PRBool aIsServerMode ) { + // Pas to base class implementation. + nsresult rv = nsNativeAppSupportBase::SetIsServerMode( aIsServerMode ); + if ( NS_SUCCEEDED(rv) && !aIsServerMode && mCachedWin ) { + // Server mode is now off. Discard cached window. + mCachedWin->Close(); + mCachedWin = 0; + } + return rv; +} + +NS_IMETHODIMP +nsNativeAppSupportWin::CacheBrowserWindow(nsIDOMWindow *aWindow, PRBool *aResult) { + NS_ENSURE_ARG( aResult ); + *aResult = PR_FALSE; + // Cache this window if we don't already have one. + if ( !mCachedWin ) { + NS_ENSURE_ARG( aWindow ); + nsresult rv = NS_OK; + mCachedWin = do_QueryInterface( aWindow, &rv ); + if ( NS_SUCCEEDED( rv ) ) { + // We cached this window; tell caller so they don't close it. + *aResult = PR_TRUE; + // Re-parent it to hide it. + ReParent( mCachedWin, (HWND)MessageWindow() ); + } + } + return NS_OK; +} diff --git a/mozilla/xpfe/browser/resources/content/navigator.js b/mozilla/xpfe/browser/resources/content/navigator.js index b90ad85d05b..3e50d39a79e 100644 --- a/mozilla/xpfe/browser/resources/content/navigator.js +++ b/mozilla/xpfe/browser/resources/content/navigator.js @@ -348,6 +348,58 @@ function Startup() } } +function BrowserFlushBookmarksAndHistory() { + // Flush bookmakrs and history (used when window closes or is cached). + try { + // If bookmarks are dirty, flush 'em to disk + var bmks = Components.classes["@mozilla.org/browser/bookmarks-service;1"] + .getService(Components.interfaces.nsIRDFRemoteDataSource); + bmks.Flush(); + + // give history a chance at flushing to disk also + var history = Components.classes["@mozilla.org/browser/global-history;1"] + .getService(Components.interfaces.nsIRDFRemoteDataSource); + history.Flush(); + } catch(ex) { + } +} + +function BrowserCanClose() { + // Check for "server mode." + try { + var appShellSvc = Components.classes["@mozilla.org/appshell/appShellService;1"] + .getService(Components.interfaces.nsIAppShellService); + var nativeSupport = appShellSvc.nativeAppSupport; + if (nativeSupport && nativeSupport.isServerMode) { + // Give native app a chance to cache this window. + if (nativeSupport.cacheBrowserWindow(window)) { + // Window is "cached" so don't close it. + + // But flush bookmarks and history, as if we did close it. + BrowserFlushBookmarksAndHistory(); + + // Reset session history. + var webNav = getWebNavigation(); + if (webNav) { + try { + webNav.sessionHistory.PurgeHistory( webNav.sessionHistory.count ); + } catch(ex) { + } + } + + // Go to blank page. + loadURI( "about:blank" ); + + // This stops the close. + return false; + } + } + } catch (ex) { + } + // Ok to close window. + return true; +} + function Shutdown() { var browser = getBrowser(); @@ -364,21 +416,7 @@ function Shutdown() window.XULBrowserWindow.destroy(); window.XULBrowserWindow = null; - try { - // If bookmarks are dirty, flush 'em to disk - var bmks = Components.classes["@mozilla.org/browser/bookmarks-service;1"] - .getService(Components.interfaces.nsIRDFRemoteDataSource); - bmks.Flush(); - } catch (ex) { - } - - try { - // give history a chance at flushing to disk also - var history = Components.classes["@mozilla.org/browser/global-history;1"] - .getService(Components.interfaces.nsIRDFRemoteDataSource); - history.Flush(); - } catch (ex) { - } + BrowserFlushBookmarksAndHistory(); // unregister us as a pref listener pref.removeObserver(window.buttonPrefListener.domain, diff --git a/mozilla/xpfe/browser/resources/content/navigator.xul b/mozilla/xpfe/browser/resources/content/navigator.xul index 04d7ffc2870..6eeb4d6cf97 100644 --- a/mozilla/xpfe/browser/resources/content/navigator.xul +++ b/mozilla/xpfe/browser/resources/content/navigator.xul @@ -45,7 +45,7 @@ Contributor(s): ______________________________________. --> - + diff --git a/mozilla/xpfe/components/startup/public/nsINativeAppSupport.idl b/mozilla/xpfe/components/startup/public/nsINativeAppSupport.idl new file mode 100644 index 00000000000..6305162bf01 --- /dev/null +++ b/mozilla/xpfe/components/startup/public/nsINativeAppSupport.idl @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Bill Law + */ + +#include "nsISupports.idl" + +/* nsINativeAppSupport + * + * This "pseudo" (in the XPCOM sense) interface provides for + * platform-specific general aplication support: + * o It subsumes the old "NS_CanRun" and "NS_CreateSplashScreen" + * functions that managed display of the application splash + * screen at startup. + * o It manages the details of the simple DDE communication + * supported on the Win32 platform (it is the addition of this + * item that prompted the creation of this interface. + * + * Due to the nature of the beast, this interface is not a full-blown + * XPCOM component. The primary reason is that objects that implement + * this interface generally must be operational *before* XPCOM (or any + * of the rest of Mozilla) are initialized. As a result, this + * interface is instantiated by somewhat unconventional means. + * + * To create the implementor of this interface, you call the function + * NS_CreateNativeAppSupport. This is done in the startup code + * in mozilla/xpfe/bootstrap. + * + * You can use this interface by obtaining an instance via the + * "nativeAppSupport" attribute of the nsIAppShellService + * interface/service. + * + * The interface provides these functions: + * start - You call this to inform the native app support that the + * application is starting. In addition, it serves as a + * query as to whether the application should continue to + * run. In that respect, it is rougly equivalent to the + * NS_CanStart function, which it replaces. + * + * If the returned boolean result is PR_FALSE, then the + * application should exit without further processing. In + * such cases, the returned nsresult indicates whether the + * reason to exit is due to an error or not. + * + * Win32 Note: In the case of starting a second instance + * of this executable, this function will return + * PR_FALSE and nsresult==NS_OK. This means that + * the command line arguments have been + * successfully passed to the instance of the + * application acting as a DDE server. + * + * stop - You call this to inform the native app support that the + * application *wishes* to terminate. If the returned boolean + * value is PR_FALSE, then the application should continue + * (as if there were still additional top-level windows open). + * + * Win32 Note: If this is the instance of the application + * acting as the DDE server, and there are current + * DDE conversations active with other instances + * acting as DDE clients, then this function will + * return PR_FALSE. + * + * quit - Like Stop, but this method *forces* termination (or more + * precisely, indicates that the application is about to be + * terminated regardless of what a call to Stop might have + * returned. + * + * This method is intended to be called when the user selects + * the "Quit" option (close all windows and exit). + * + * Win32 Note: Stop is problematic in the case of "Quit" (close + * all windows and exit the application) because + * either we don't Quit or (potentially) we lose + * requests coming from other instances of the + * application. The strategy is to give preference + * to the user's explicit Quit request. In the + * unlikely event that a request is pending from + * another instance of the application, then such + * requests are essentially ignored. This is + * roughly equivalent to handling that request by + * opening a new window, followed by immediately + * closing it. Since this is the same as if the + * request came in immediately before the Quit + * call (versus immediately after it), no harm. + * + * There is an exposure here: Upon return from this + * function, any DDE connect request (for Mozilla) + * will fail and other instances of the application + * will start up as a DDE server. In that case, + * those instances may do things that conflict with + * the subsequent shutting down of the instance that + * is quitting. For this reason, the call to Quit + * should be deferred as long as possible. + * + * showSplashScreen - Causes the platform-specific splash screen to be + * displayed. This is a replacement for the old + * method of invoking the Show() method on the + * nsISplashScreen interface obtained by calling + * NS_CreateSplashScreen. + * + * hideSplashScreen - Causes the splash screen to be removed (if it is + * being shown). This replaces the old method of + * invoking the Hide() method on the nsISplashScreen + * interface maintained by the app shell service. + * + * cacheBrowserWindow - Takes an about-to-be-closed navigator window + * and "caches it" for later use. It returns an + * indicator of whether the window was actually + * cached. If that result is false, then the + * caller should close the window normally. + * + * This interface has these attributes: + * isServerMode - Boolean attribute indicating whether the application + * is running in "server mode." Server mode means the + * application was started to pre-load shared-libraries, + * initialize services, and open a hidden Navigator window + * in order to quickly surface that window when the user + * launches the application in the normal mode. This + * mode is currently Win32-only (and may really only make + * sense there) and is intended to be initiated from the + * Windows startup folder at system initialization. + */ + +interface nsIDOMWindow; + +[scriptable, uuid(5fdf8480-1f98-11d4-8077-00600811a9c3)] +interface nsINativeAppSupport : nsISupports { + // Startup/shutdown. + boolean start(); + boolean stop(); + void quit(); + + // Splash screen functions. + void showSplashScreen(); + void hideSplashScreen(); + + // Server mode. + attribute boolean isServerMode; + boolean cacheBrowserWindow(in nsIDOMWindow aWindow); +};