From da40f1c4d75a54438ae8346442bb2e786da2b22e Mon Sep 17 00:00:00 2001 From: "mkaply%us.ibm.com" Date: Thu, 15 Aug 2002 14:49:44 +0000 Subject: [PATCH] #162387 r=pedemont, no sr. OK, I need this in. OS/2 menus are unusable without this. Basically, when 117730 went in, it regressed this because the fix for 101771 was no longer needed. This is backing out the 101771 fix. I have verified this doesn't break Windows. The only other platform that could be an issue is Mac, but it shouldn't be because Mac uses native menus. No other platform handles clipSiblings. If this does break something, you would see it as menus appearing behind other menus. git-svn-id: svn://10.0.0.236/trunk@127369 18797224-902f-48f8-a5cc-f745e15eee43 --- .../layout/xul/base/src/nsMenuPopupFrame.cpp | 1 - .../xpfe/bootstrap/nsNativeAppSupportOS2.cpp | 1033 ++++++++++------- .../xpfe/bootstrap/nsNativeAppSupportOS2.h | 10 + 3 files changed, 595 insertions(+), 449 deletions(-) diff --git a/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp b/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp index d8a43c72f79..dd9e1985c5f 100644 --- a/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -221,7 +221,6 @@ nsMenuPopupFrame::Init(nsIPresContext* aPresContext, widgetData.mWindowType = eWindowType_popup; widgetData.mContentType = nsIDocShellTreeItem::typeChrome; widgetData.mBorderStyle = eBorderStyle_default; - widgetData.clipSiblings = PR_TRUE; nsCOMPtr parentContent; aContent->GetParent(*getter_AddRefs(parentContent)); diff --git a/mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.cpp b/mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.cpp index e2dea75307f..edcef1ed26c 100644 --- a/mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.cpp +++ b/mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.cpp @@ -22,10 +22,14 @@ * IBM Corp. */ -// For server mode systray icon. -#include "nsIStringBundle.h" +#define INCL_PM +#define INCL_GPI +#define INCL_DOS +#define INCL_DOSERRORS +#include #include "nsNativeAppSupportBase.h" +#include "nsNativeAppSupportOS2.h" #include "nsString.h" #include "nsICmdLineService.h" #include "nsCOMPtr.h" @@ -57,38 +61,19 @@ #include "nsIJSContextStack.h" #include "nsIWindowMediator.h" -#define INCL_PM -#define INCL_GPI -#define INCL_DOS -#define INCL_DOSERRORS -#include -#include -#include -#include -#include -#include "nsNativeAppSupportOS2.h" +#include -#define TURBO_QUIT 1 +#include "prprf.h" // getting from nsAppRunner. Use to help track down arguments. extern char ** __argv; extern int __argc; - -typedef ULONG DWORD; -typedef PBYTE LPBYTE; -typedef HDATA HDDEDATA; -#define CP_WINANSI 0 // When 0 is specified for codepage on these - // dde functions, it will use the codepage - // that is associated with the current thread. - // CP_WINANSI in win32 means that the non - // unicode version of DdeCreateStringHandle - // was used. - // Adding to support DDE #define ID_MESSAGEWINDOW 0xDEAF + /* trying to keep this like Window's COPYDATASTRUCT, but a compiler error is * forcing me to add chBuff so that we can append the data to the end of the * structure @@ -104,7 +89,6 @@ typedef struct _COPYDATASTRUCT char szCommandLine[2*CCHMAXPATH]; - static HWND hwndForDOMWindow( nsISupports * ); static @@ -221,9 +205,13 @@ struct Mutex { : mName( name ), mHandle( 0 ), mState( -1 ) { - DosCreateMutexSem( mName.get(), &mHandle, 0, FALSE ); + /* OS/2 named semaphores must begin with "\\SEM32\\" to be valid */ + mName.Insert("\\SEM32\\", 0); + APIRET rc = DosCreateMutexSem( mName.get(), &mHandle, 0, FALSE ); #if MOZ_DEBUG_DDE - printf( "CreateMutex error = 0x%08X\n", (int)GetLastError() ); + if ( rc != NO_ERROR ) { + printf( "CreateMutex error = 0x%08X\n", rc ); + } #endif } ~Mutex() { @@ -234,7 +222,7 @@ struct Mutex { APIRET rc = DosCloseMutexSem( mHandle ); #if MOZ_DEBUG_DDE if ( rc != NO_ERROR ) { - printf( "CloseHandle error = 0x%08X\n", (int)GetLastError() ); + printf( "CloseHandle error = 0x%08X\n", rc ); } #endif } @@ -360,29 +348,31 @@ public: NS_IMETHOD SetIsServerMode( PRBool isServerMode ); NS_IMETHOD EnsureProfile(nsICmdLineService* args); - // The "old" Start method (renamed). NS_IMETHOD StartDDE(); // Utility function to handle a Win32-specific command line // option: "-console", which dynamically creates a Windows // console. - void CheckConsole(); + // On OS/2, we use the return from CheckConsole to determine + // whether or not to use the OS/2 specific turbo mode + nsresult CheckConsole(); private: static HDDEDATA APIENTRY HandleDDENotification( ULONG idInst, - USHORT uType, - USHORT uFmt, - HCONV hconv, - HSZ hsz1, - HSZ hsz2, - HDDEDATA hdata, - ULONG dwData1, - ULONG dwData2 ); + USHORT uType, + USHORT uFmt, + HCONV hconv, + HSZ hsz1, + HSZ hsz2, + HDDEDATA hdata, + ULONG dwData1, + ULONG dwData2 ); static void HandleRequest( LPBYTE request, PRBool newWindow = PR_TRUE ); static nsCString ParseDDEArg( HSZ args, int index ); static void ActivateLastWindow(); - static HDDEDATA CreateDDEData( DWORD value ); + static HDDEDATA CreateDDEData( DWORD value ); + static HDDEDATA CreateDDEData( LPBYTE value, DWORD len ); static PRBool InitTopicStrings(); static int FindTopic( HSZ topic ); static nsresult GetCmdLineArgs( LPBYTE request, nsICmdLineService **aResult ); @@ -390,8 +380,6 @@ private: static nsresult OpenBrowserWindow( const char *args, PRBool newWindow = PR_TRUE ); static nsresult ReParent( nsISupports *window, HWND newParent ); static nsresult GetStartupURL(nsICmdLineService *args, nsCString& taskURL); - static void SetupSysTrayIcon(); - static void RemoveSysTrayIcon(); static int mConversations; @@ -402,18 +390,17 @@ private: topicVersion, topicRegisterViewer, topicUnRegisterViewer, + topicGetWindowInfo, // Note: Insert new values above this line!!!!! topicCount // Count of the number of real topics }; -#ifdef DOWENEED - static NOTIFYICONDATA mIconData; - static HMENU mTrayIconMenu; -#endif /* DOWENEED */ static HSZ mApplication, mTopics[ topicCount ]; static DWORD mInstance; static char *mAppName; static nsIDOMWindow *mInitialWindow; + static PRBool mForceProfileStartup; + static char mMutexName[]; static PRBool mUseDDE; friend struct MessageWindow; }; // nsNativeAppSupportOS2 @@ -441,24 +428,6 @@ nsSplashScreenOS2::Show() { NS_IMETHODIMP nsSplashScreenOS2::Hide() { if ( mDlg ) { -#ifdef DOWENEED - // Fix for bugs: - // http://bugzilla.mozilla.org/show_bug.cgi?id=26581 - // http://bugzilla.mozilla.org/show_bug.cgi?id=65974 - // http://bugzilla.mozilla.org/show_bug.cgi?id=29172 - // http://bugzilla.mozilla.org/show_bug.cgi?id=45805 - // As the splash-screen is in a seperate thread, Windows considers - // this the "foreground" thread. When our main windows on the main - // thread are activated, they are treated like windows from a different - // application, so Windows 2000 and 98 both leave the window in the background. - // Therefore, we post a message to the splash-screen thread that includes - // the hwnd of the window we want moved to the foreground. This thread - // can then successfully bring the top-level window to the foreground. - nsCOMPtr topLevel; - GetMostRecentWindow(nsnull, getter_AddRefs( topLevel ) ); - HWND hWndTopLevel = topLevel ? hwndForDOMWindow(topLevel) : 0; -#endif /* DOWENEED */ - // Dismiss the dialog. WinPostMsg(mDlg, WM_CLOSE, 0, 0); mDlg = 0; @@ -629,26 +598,9 @@ MRESULT EXPENTRY DialogProc( HWND dlg, ULONG msg, MPARAM mp1, MPARAM mp2 ) { WinEndPaint( hps ); return (MRESULT)TRUE; } -#ifdef DOWENEED - else if (msg == WM_CLOSE) { - // Before killing ourself, set the top-level current. - // See comments in nsSplashScreenWin::Hide() above. - HWND topLevel = (HWND)mp2; - if (topLevel) - ::SetForegroundWindow(topLevel); - // Destroy the dialog - ::EndDialog(dlg, 0); - // Release custom bitmap (if there is one). - HBITMAP bitmap = (HBITMAP)wp; - if ( bitmap ) { - ::DeleteObject( bitmap ); - } - } -#endif /* DOWENEED */ return WinDefDlgProc (dlg, msg, mp1, mp2); } - void nsSplashScreenOS2::SetDialog( HWND dlg ) { // Save dialog handle. mDlg = dlg; @@ -671,60 +623,19 @@ void _Optlink ThreadProc(void *splashScreen) { // _endthread(); } -void +#define TURBOD "mozturbo.exe" + +PRBool gAbortServer = PR_FALSE; + +nsresult nsNativeAppSupportOS2::CheckConsole() { + nsresult rv = NS_OK; + for ( int i = 1; i < __argc; i++ ) { if ( strcmp( "-console", __argv[i] ) == 0 || strcmp( "/console", __argv[i] ) == 0 ) { -#ifdef DOWENEED - // Users wants to make sure we have a console. - // Try to allocate one. - BOOL rc = ::AllocConsole(); - if ( rc ) { - // Console allocated. Fix it up so that output works in - // all cases. See http://support.microsoft.com/support/kb/articles/q105/3/05.asp. - - // stdout - int hCrt = ::_open_osfhandle( (long)GetStdHandle( STD_OUTPUT_HANDLE ), - _O_TEXT ); - if ( hCrt != -1 ) { - FILE *hf = ::_fdopen( hCrt, "w" ); - if ( hf ) { - *stdout = *hf; - ::fprintf( stdout, "stdout directed to dynamic console\n" ); - } - } - - // stderr - hCrt = ::_open_osfhandle( (long)::GetStdHandle( STD_ERROR_HANDLE ), - _O_TEXT ); - if ( hCrt != -1 ) { - FILE *hf = ::_fdopen( hCrt, "w" ); - if ( hf ) { - *stderr = *hf; - ::fprintf( stderr, "stderr directed to dynamic console\n" ); - } - } - - // stdin? - /* Don't bother for now. - hCrt = ::_open_osfhandle( (long)::GetStdHandle( STD_INPUT_HANDLE ), - _O_TEXT ); - if ( hCrt != -1 ) { - FILE *hf = ::_fdopen( hCrt, "r" ); - if ( hf ) { - *stdin = *hf; - } - } - */ - } else { - // Failed. Probably because there already is one. - // There's little we can do, in any case. - } - // Don't bother doing this more than once. - break; -#endif /* DOWENEED */ + /* Figure out some magic way to create a console on OS/2 */ } else if ( strcmp( "-turbo", __argv[i] ) == 0 || strcmp( "/turbo", __argv[i] ) == 0 @@ -732,14 +643,62 @@ nsNativeAppSupportOS2::CheckConsole() { 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; + struct stat st; + int statrv = stat(TURBOD, &st); + + /* If we can't find the turbo EXE, use the Mozilla turbo */ + if (statrv == 0) { + RESULTCODES rcodes; + APIRET rc; + CHAR pszArgString[CCHMAXPATH]; + strcpy(pszArgString, TURBOD); + strcat(pszArgString, " -l -p "); + strcat(pszArgString, __argv[0]); + pszArgString[strlen(TURBOD)] = '\0'; + + rc = DosExecPgm(NULL,0,EXEC_BACKGROUND, + pszArgString, + 0, &rcodes, + TURBOD); + rv = NS_ERROR_FAILURE; + } else { + // Start in server mode (and suppress splash screen). + mServerMode = PR_TRUE; + mShouldShowUI = PR_FALSE; + __argv[i] = "-nosplash"; // Bit of a hack, but it works! + // Ignore other args. + } } } - return; + + for ( int j = 1; j < __argc; j++ ) { + if (strcmp("-killAll", __argv[j]) == 0 || strcmp("/killAll", __argv[j]) == 0 || + strcmp("-kill", __argv[j]) == 0 || strcmp("/kill", __argv[j]) == 0) { + struct stat st; + int statrv = stat(TURBOD, &st); + + /* If we can't find the turbo EXE, use the Mozilla turbo */ + if (statrv == 0) { + RESULTCODES rcodes; + APIRET rc; + CHAR pszArgString[CCHMAXPATH]; + strcpy(pszArgString, TURBOD); + strcat(pszArgString, " -u"); + pszArgString[strlen(TURBOD)] = '\0'; + + rc = DosExecPgm(NULL,0,EXEC_BACKGROUND, + pszArgString, + 0, &rcodes, + TURBOD); + rv = NS_ERROR_FAILURE; + } else { + gAbortServer = PR_TRUE; + } + break; + } + } + + return rv; } @@ -749,10 +708,13 @@ NS_CreateNativeAppSupport( nsINativeAppSupport **aResult ) { if ( aResult ) { nsNativeAppSupportOS2 *pNative = new nsNativeAppSupportOS2; if ( pNative ) { + // Check for dynamic console creation request. + if NS_FAILED(pNative->CheckConsole()) { + delete pNative; + return NS_ERROR_FAILURE; + } *aResult = pNative; NS_ADDREF( *aResult ); - // Check for dynamic console creation request. - pNative->CheckConsole(); } else { return NS_ERROR_OUT_OF_MEMORY; } @@ -798,10 +760,6 @@ NS_CreateSplashScreen( nsISplashScreen **aResult ) { // Constants #define MOZ_DDE_APPLICATION "Mozilla" -#ifdef XP_OS2 -/* os/2 named semaphores must begin with "\\SEM32\\" to be valid */ -#define MOZ_MUTEX_PREPEND "\\SEM32\\" -#endif /* XP_OS2 */ #define MOZ_STARTUP_MUTEX_NAME "StartupMutex" #define MOZ_DDE_START_TIMEOUT 30000 #define MOZ_DDE_STOP_TIMEOUT 15000 @@ -813,7 +771,8 @@ const char * const topicNames[] = { "WWW_OpenURL", "WWW_CancelProgress", "WWW_Version", "WWW_RegisterViewer", - "WWW_UnRegisterViewer" }; + "WWW_UnRegisterViewer", + "WWW_GetWindowInfo" }; // Static member definitions. int nsNativeAppSupportOS2::mConversations = 0; @@ -821,6 +780,7 @@ HSZ nsNativeAppSupportOS2::mApplication = 0; HSZ nsNativeAppSupportOS2::mTopics[nsNativeAppSupportOS2::topicCount] = { 0 }; DWORD nsNativeAppSupportOS2::mInstance = 0; nsIDOMWindow* nsNativeAppSupportOS2::mInitialWindow = nsnull; +PRBool nsNativeAppSupportOS2::mForceProfileStartup = PR_FALSE; // Added this as pmddeml has no api like this @@ -959,16 +919,7 @@ BOOL SetupOS2ddeml() return( bRC ); } -#ifdef DOWENEED -NOTIFYICONDATA nsNativeAppSupportOS2::mIconData = { sizeof(NOTIFYICONDATA), - 0, - 1, - NIF_ICON | NIF_MESSAGE | NIF_TIP, - WM_USER, - 0, - 0 }; -HMENU nsNativeAppSupportOS2::mTrayIconMenu = 0; -#endif /* DOWENEED */ +char nsNativeAppSupportOS2::mMutexName[ 128 ] = { 0 }; // Message window encapsulation. @@ -1014,16 +965,16 @@ struct MessageWindow { */ const char * pszClassName = className(); mHandle = WinCreateWindow( HWND_OBJECT, - pszClassName, - NULL, // name - WS_DISABLED, // style - 0,0, // x, y - 0,0, // cx,cy - HWND_DESKTOP,// owner - HWND_BOTTOM, // hwndbehind - ID_MESSAGEWINDOW, // id - NULL, // pCtlData - NULL ); // pres params + pszClassName, + NULL, // name + WS_DISABLED, // style + 0,0, // x, y + 0,0, // cx,cy + HWND_DESKTOP,// owner + HWND_BOTTOM, // hwndbehind + ID_MESSAGEWINDOW, // id + NULL, // pCtlData + NULL ); // pres params #if MOZ_DEBUG_DDE printf( "Message window = 0x%08X\n", (int)mHandle ); @@ -1032,9 +983,27 @@ struct MessageWindow { return NS_OK; } + // Destory: Get rid of window and reset mHandle. + NS_IMETHOD Destroy() { + nsresult retval = NS_OK; + + if ( mHandle ) { + // DestroyWindow can only destroy windows created from + // the same thread. + BOOL desRes = WinDestroyWindow( mHandle ); + if ( FALSE != desRes ) { + mHandle = NULL; + } + else { + retval = NS_ERROR_FAILURE; + } + } + + return retval; + } + // SendRequest: Pass string via WM_COPYDATA to message window. NS_IMETHOD SendRequest( const char *cmd ) { -#ifdef XP_OS2 /* Nothing like WM_COPYDATA in OS/2, where the OS allows pointers to be * passed to a different process and automatically accessible by that * process. So we have to create shared mem on our side and then the @@ -1071,10 +1040,6 @@ struct MessageWindow { } WinSendMsg( mHandle, WM_COPYDATA, 0, (MPARAM)pcds ); DosFreeMem( pvData ); -#else - COPYDATASTRUCT cds = { 0, strlen( cmd ) + 1, (void*)cmd }; - ::SendMessage( mHandle, WM_COPYDATA, 0, (LPARAM)&cds ); -#endif /* XP_OS2 */ return NS_OK; } @@ -1088,62 +1053,19 @@ struct MessageWindow { if ( msg == WM_COPYDATA ) { // This is an incoming request. COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lp; -#ifdef XP_OS2 DosGetSharedMem( (PVOID)cds, PAG_READ|PAG_WRITE ); -#endif /* XP_OS2 */ #if MOZ_DEBUG_DDE printf( "Incoming request: %s\n", (const char*)cds->lpData ); #endif (void)nsNativeAppSupportOS2::HandleRequest( (LPBYTE)cds->lpData ); } -#ifdef DOWENEED - else if ( msg == WM_USER ) { - if ( lp == WM_RBUTTONUP ) { - // Show menu with Exit disabled/enabled appropriately. - nsCOMPtr win; - GetMostRecentWindow( 0, getter_AddRefs( win ) ); - ::EnableMenuItem( nsNativeAppSupportWin::mTrayIconMenu, 1, win ? MF_GRAYED : MF_ENABLED ); - POINT pt; - GetCursorPos( &pt ); - SetForegroundWindow(msgWindow); - int selectedItem = ::TrackPopupMenu( nsNativeAppSupportWin::mTrayIconMenu, - TPM_NONOTIFY | TPM_RETURNCMD | - TPM_RIGHTBUTTON, - pt.x, - pt.y, - 0, - msgWindow, - 0 ); - - switch (selectedItem) { - case TURBO_QUIT: - (void)nsNativeAppSupportWin::HandleRequest( (LPBYTE)"mozilla -kill" ); - break; - } - PostMessage(msgWindow, WM_NULL, 0, 0); - } else if ( lp == WM_LBUTTONDBLCLK ) { - // Activate window or open a new one. - nsCOMPtr win; - GetMostRecentWindow( 0, getter_AddRefs( win ) ); - if ( win ) { - activateWindow( win ); - } else { - // This will do the default thing and open a new window. - (void)nsNativeAppSupportWin::HandleRequest( (LPBYTE)"mozilla" ); - } - } - } -#endif /* DOWENEED */ - -#ifdef XP_OS2 /* We have to return a FALSE from WM_CREATE or this window will never * get off of the ground */ else if ( msg == WM_CREATE ) { rc = (MRESULT)FALSE; } -#endif /* XP_OS2 */ return rc; } @@ -1173,6 +1095,12 @@ nsNativeAppSupportOS2::Start( PRBool *aResult ) { NS_ENSURE_ARG( aResult ); NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED ); + if (getenv("MOZ_NO_REMOTE")) + { + *aResult = PR_TRUE; + return NS_OK; + } + nsresult rv = NS_ERROR_FAILURE; *aResult = PR_FALSE; @@ -1186,7 +1114,6 @@ nsNativeAppSupportOS2::Start( PRBool *aResult ) { // Grab mutex first. int retval; UINT id = ID_DDE_APPLICATION_NAME; - char nameBuf[ 128 ]; retval = WinLoadString( NULLHANDLE, NULLHANDLE, id, sizeof(nameBuffer), nameBuffer ); if ( retval == 0 ) { // No app name; just keep running. @@ -1195,30 +1122,26 @@ nsNativeAppSupportOS2::Start( PRBool *aResult ) { } // Build mutex name from app name. - char mutexName[128]; - sprintf( mutexName, "%s%s%s", MOZ_MUTEX_PREPEND, nameBuffer, MOZ_STARTUP_MUTEX_NAME ); - Mutex startupLock = Mutex( mutexName ); + PR_snprintf( mMutexName, sizeof mMutexName, "%s%s", nameBuffer, MOZ_STARTUP_MUTEX_NAME ); + Mutex startupLock = Mutex( mMutexName ); NS_ENSURE_TRUE( startupLock.Lock( MOZ_DDE_START_TIMEOUT ), NS_ERROR_FAILURE ); -#ifdef XP_OS2 /* We need to have a message queue to do the MessageWindow stuff (for both * Create() and SendRequest()). If we don't have one, make it now. * If we are going to end up going away right after ::Start() returns, * then make sure to clean up the message queue. */ MQINFO mqinfo; - HAB hab; - HMQ hmqCurrent = WinQueryQueueInfo( HMQ_CURRENT, &mqinfo, - sizeof( MQINFO ) ); + HAB hab; + HMQ hmqCurrent = WinQueryQueueInfo( HMQ_CURRENT, &mqinfo, + sizeof( MQINFO ) ); if( !hmqCurrent ) { hab = WinInitialize( 0 ); hmqCurrent = WinCreateMsgQueue( hab, 0 ); } -#endif /* XP_OS */ - // Search for existing message window. MessageWindow msgWindow; if ( (HWND)msgWindow ) { @@ -1227,35 +1150,31 @@ nsNativeAppSupportOS2::Start( PRBool *aResult ) { rv = msgWindow.SendRequest( cmd ); } else { // We will be server. - rv = msgWindow.Create(); - if ( NS_SUCCEEDED( rv ) ) { - if (mUseDDE) { - // Start up DDE server. - this->StartDDE(); + if (!gAbortServer) { + rv = msgWindow.Create(); + if ( NS_SUCCEEDED( rv ) ) { + if (mUseDDE) { + // Start up DDE server. + this->StartDDE(); + } + // Tell caller to spin message loop. + *aResult = PR_TRUE; } - // Tell caller to spin message loop. - *aResult = PR_TRUE; } } startupLock.Unlock(); -#ifdef XP_OS2 if( *aResult == PR_FALSE ) { /* This process isn't going to continue much longer. Make sure that we * clean up the message queue */ - if( hmqCurrent ) - { - WinDestroyMsgQueue( hmqCurrent ); - } - if( hab ) - { - WinTerminate( hab ); - } + if (hmqCurrent) + WinDestroyMsgQueue(hmqCurrent); + if (hab) + WinTerminate(hab); } -#endif /* XP_OS2 */ return rv; } @@ -1294,21 +1213,23 @@ NS_IMETHODIMP nsNativeAppSupportOS2::StartDDE() { NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED ); - BOOL bDdemlReady = SetupOS2ddeml(); - UINT rc = DDEERR_NOT_INITIALIZED; - if( bDdemlReady == TRUE ) - { - rc = (UINT) WinDdeInitialize( - &mInstance, - nsNativeAppSupportOS2::HandleDDENotification, - APPCLASS_STANDARD, - 0 ); + /* Get entrypoints for PMDDEML */ + BOOL bDDEML = SetupOS2ddeml(); + + /* If we couldn't initialize DDEML, set mUSEDDE to PR_FALSE */ + /* so we don't do anything else DDE related */ + if (!bDDEML) { + mUseDDE = PR_FALSE; + return NS_OK; } // Initialize DDE. - NS_ENSURE_TRUE( DDEERR_NO_ERROR == rc, NS_ERROR_FAILURE ); - - + NS_ENSURE_TRUE( DDEERR_NO_ERROR == WinDdeInitialize( &mInstance, + nsNativeAppSupportOS2::HandleDDENotification, + APPCLASS_STANDARD, + 0 ), + NS_ERROR_FAILURE ); + // Allocate DDE strings. NS_ENSURE_TRUE( ( mApplication = WinDdeCreateStringHandle( mAppName, CP_WINANSI ) ) && InitTopicStrings(), NS_ERROR_FAILURE ); @@ -1336,7 +1257,7 @@ nsNativeAppSupportOS2::Stop( PRBool *aResult ) { return rv; } - Mutex ddeLock( MOZ_STARTUP_MUTEX_NAME ); + Mutex ddeLock( mMutexName ); if ( ddeLock.Lock( MOZ_DDE_STOP_TIMEOUT ) ) { if ( mConversations == 0 ) { @@ -1353,13 +1274,26 @@ nsNativeAppSupportOS2::Stop( PRBool *aResult ) { *aResult = PR_TRUE; } - return rv; } // Terminate DDE regardless. NS_IMETHODIMP nsNativeAppSupportOS2::Quit() { + // If another process wants to look for the message window, they need + // to wait to hold the lock, in which case they will not find the + // window as we will destroy ours under our lock. + // When the mutex goes off the stack, it is unlocked via destructor. + Mutex mutexLock(mMutexName); + NS_ENSURE_TRUE(mutexLock.Lock(MOZ_DDE_START_TIMEOUT), NS_ERROR_FAILURE ); + + // If we've got a message window to receive IPC or new window requests, + // get rid of it as we are shutting down. + // Note: Destroy calls DestroyWindow, which will only work on a window + // created by the same thread. + MessageWindow mw; + mw.Destroy(); + if ( mInstance ) { // Unregister application name. WinDdeNameService( mInstance, mApplication, 0, DNS_UNREGISTER ); @@ -1383,7 +1317,7 @@ nsNativeAppSupportOS2::Quit() { PRBool NS_CanRun() { - return PR_TRUE; + return PR_FALSE; /* We do this so that we can bail if we are using custom turbo mode */ } #if MOZ_DEBUG_DDE @@ -1439,6 +1373,25 @@ static nsCString hszValue( DWORD, HSZ ) { #endif +// Utility function to escape double-quotes within a string. +static void escapeQuotes( nsAString &aString ) { + PRInt32 offset = -1; + while( 1 ) { + // Find next '"'. + offset = aString.FindChar( '"', ++offset ); + if ( offset == kNotFound ) { + // No more quotes, exit. + break; + } else { + // Insert back-slash ahead of the '"'. + aString.Insert( PRUnichar('\\'), offset ); + // Increment offset because we just inserted a slash + offset++; + } + } + return; +} + HDDEDATA APIENTRY nsNativeAppSupportOS2::HandleDDENotification( ULONG idInst, // DDEML instance USHORT uType, // transaction type @@ -1481,21 +1434,132 @@ nsNativeAppSupportOS2::HandleDDENotification( ULONG idInst, // DDEML instanc switch ( FindTopic( hsz1 ) ) { case topicOpenURL: { // Open a given URL... - nsCString url = ParseDDEArg( hsz2, 0 ); + + // Default is to open in current window. + PRBool new_window = PR_FALSE; + + // Get the URL from the first argument in the command. + nsCAutoString url( ParseDDEArg( hsz2, 0 ) ); + + // Read the 3rd argument in the command to determine if a + // new window is to be used. + nsCAutoString windowID( ParseDDEArg( hsz2, 2 ) ); + + // "0" means to open the URL in a new window. + if ( windowID.Equals( "0" ) ) { + new_window = PR_TRUE; + } + // Make it look like command line args. url.Insert( "mozilla -url ", 0 ); #if MOZ_DEBUG_DDE printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() ); #endif // Now handle it. - HandleRequest( LPBYTE( url.get() ), PR_FALSE ); + HandleRequest( LPBYTE( url.get() ), new_window ); // Return pseudo window ID. result = CreateDDEData( 1 ); break; } + case topicGetWindowInfo: { + // This topic has to get the current URL, get the current + // page title and then format the output into the DDE + // return string. The return value is "URL","Page Title", + // "Window ID" however the window ID is not used for this + // command, therefore it is returned as a null string + + // This isn't really a loop. We just use "break" + // statements to bypass the remaining steps when + // something goes wrong. + do { + // Get most recently used Nav window. + nsCOMPtr navWin; + GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(), + getter_AddRefs( navWin ) ); + if ( !navWin ) { + // There is not a window open + break; + } + // Get content window. + nsCOMPtr content; + navWin->GetContent( getter_AddRefs( content ) ); + if ( !content ) { + break; + } + // Convert that to internal interface. + nsCOMPtr internalContent( do_QueryInterface( content ) ); + if ( !internalContent ) { + break; + } + // Get location. + nsCOMPtr location; + internalContent->GetLocation( getter_AddRefs( location ) ); + if ( !location ) { + break; + } + // Get href for URL. + nsAutoString url; + if ( NS_FAILED( location->GetHref( url ) ) ) { + break; + } + // Escape any double-quotes. + escapeQuotes( url ); + + // Now for the title; first, get the "window" JS object. + nsCOMPtr scrGlobalObj( do_QueryInterface( internalContent ) ); + if ( !scrGlobalObj ) { + break; + } + // Then the doc shell... + nsCOMPtr docShell; + scrGlobalObj->GetDocShell( getter_AddRefs( docShell ) ); + if ( !docShell ) { + break; + } + // And from that the base window... + nsCOMPtr baseWindow( do_QueryInterface( docShell ) ); + if ( !baseWindow ) { + break; + } + // And from the base window we can get the title. + nsXPIDLString title; + if(!baseWindow) { + break; + } + baseWindow->GetTitle(getter_Copies(title)); + // Escape any double-quotes in the title. + escapeQuotes( title ); + + // Use a string buffer for the output data, first + // save a quote. + nsCAutoString outpt( NS_LITERAL_CSTRING("\"") ); + // Now copy the URL converting the Unicode string + // to a single-byte ASCII string + outpt.Append( NS_LossyConvertUCS2toASCII( url ) ); + // Add the "," used to separate the URL and the page + // title + outpt.Append( NS_LITERAL_CSTRING("\",\"") ); + // Now copy the current page title to the return string + outpt.Append( NS_LossyConvertUCS2toASCII( title.get() )); + // Fill out the return string with the remainin ","" + outpt.Append( NS_LITERAL_CSTRING( "\",\"\"" )); + + // Create a DDE handle to a char string for the data + // being returned, this copies and creates a "shared" + // copy of the DDE response until the calling APP + // reads it and says it can be freed. + result = CreateDDEData( (LPBYTE)(const char*)outpt.get(), + outpt.Length() + 1 ); +#if MOZ_DEBUG_DDE + printf( "WWW_GetWindowInfo->%s\n", outpt.get() ); +#endif + } while ( PR_FALSE ); + break; + } case topicActivate: { // Activate a Nav window... nsCString windowID = ParseDDEArg( hsz2, 0 ); + // 4294967295 is decimal for 0xFFFFFFFF which is also a // correct value to do that Activate last window stuff if ( windowID.Equals( "-1" ) || @@ -1545,7 +1609,33 @@ nsNativeAppSupportOS2::HandleDDENotification( ULONG idInst, // DDEML instanc #if MOZ_DEBUG_DDE printf( "Handling dde request: [%s]...\n", (char*)request ); #endif - HandleRequest( request ); + // Default is to open in current window. + PRBool new_window = PR_FALSE; + + // Get the URL from the first argument in the command. + HSZ args = WinDdeCreateStringHandle( (PSZ)request, CP_WINANSI ); + nsCAutoString url( ParseDDEArg( args, 0 ) ); + + // Read the 3rd argument in the command to determine if a + // new window is to be used. + nsCAutoString windowID( ParseDDEArg( args, 2 ) ); + + // "0" means to open the URL in a new window. + if ( windowID.Equals( "0" ) ) { + new_window = PR_TRUE; + } + + // Make it look like command line args. + url.Insert( "mozilla -url ", 0 ); +#if MOZ_DEBUG_DDE + printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() ); +#endif + // Now handle it. + HandleRequest( LPBYTE( url.get() ), new_window ); + // Release the args string. + WinDdeFreeStringHandle( args ); + // Release the data. +// DdeUnaccessData( hdata ); result = (HDDEDATA)DDE_FACK; } else { result = (HDDEDATA)DDE_NOTPROCESSED; @@ -1558,6 +1648,27 @@ nsNativeAppSupportOS2::HandleDDENotification( ULONG idInst, // DDEML instanc return result; } +// Utility function to advance to end of quoted string. +// p+offset must point to the comma preceding the arg on entry. +// On return, p+result points to the closing '"' (or end of the string +// if the closing '"' is missing) if the arg is quoted. If the arg +// is not quoted, then p+result will point to the first character +// of the arg. +static PRInt32 advanceToEndOfQuotedArg( const char *p, PRInt32 offset, PRInt32 len ) { + // Check whether the current arg is quoted. + if ( p[++offset] == '"' ) { + // Advance past the closing quote. + while ( offset < len && p[++offset] != '"' ) { + // If the current character is a backslash, then the + // next character can't be a *real* '"', so skip it. + if ( p[offset] == '\\' ) { + offset++; + } + } + } + return offset; +} + // Utility to parse out argument from a DDE item string. nsCString nsNativeAppSupportOS2::ParseDDEArg( HSZ args, int index ) { nsCString result; @@ -1568,22 +1679,39 @@ nsCString nsNativeAppSupportOS2::ParseDDEArg( HSZ args, int index ) { temp.SetLength( argLen + 1 ); // Now get the string contents. WinDdeQueryString( args, (char*)temp.get(), temp.Length(), CP_WINANSI ); - // Parse out the given arg. We assume there's no commas within quoted strings - // (which may not be accurate, but makes life so much easier). + // Parse out the given arg. const char *p = temp.get(); - // Skip index commas. - PRInt32 offset = index ? temp.FindChar( ',', 0, index ) : 0; - if ( offset != -1 ) { - // Desired argument starts there and ends at next comma. - PRInt32 end = temp.FindChar( ',', offset+1 ); - if ( end == -1 ) { - // Rest of string. - end = temp.Length(); + // offset points to the comma preceding the desired arg. + PRInt32 offset = -1; + // Skip commas till we get to the arg we want. + while( index-- ) { + // If this arg is quoted, then go to closing quote. + offset = advanceToEndOfQuotedArg( p, offset, argLen ); + // Find next comma. + offset = temp.FindChar( ',', offset ); + if ( offset == kNotFound ) { + // No more commas, give up. + return result; } - // Extract result. - result.Assign( temp.get() + offset, end - offset ); } + // The desired argument starts just past the preceding comma, + // which offset points to, and extends until the following + // comma (or the end of the string). + // + // Since the argument might be enclosed in quotes, we need to + // deal with that before searching for the terminating comma. + // We advance offset so it ends up pointing to the start of + // the argument we want. + PRInt32 end = advanceToEndOfQuotedArg( p, offset++, argLen ); + // Find next comma (or end of string). + end = temp.FindChar( ',', end ); + if ( end == kNotFound ) { + // Arg is the rest of the string. + end = argLen; + } + // Extract result. + result.Assign( p + offset, end - offset ); } return result; } @@ -1601,12 +1729,16 @@ void nsNativeAppSupportOS2::ActivateLastWindow() { } HDDEDATA nsNativeAppSupportOS2::CreateDDEData( DWORD value ) { - HDDEDATA result = WinDdeCreateDataHandle( (LPBYTE)&value, - sizeof value, - 0, - mApplication, - CF_TEXT, - 0 ); + return CreateDDEData( (LPBYTE)&value, sizeof value ); +} + +HDDEDATA nsNativeAppSupportOS2::CreateDDEData( LPBYTE value, DWORD len ) { + HDDEDATA result = WinDdeCreateDataHandle( value, + len, + 0, + mApplication, + CF_TEXT, + 0 ); return result; } @@ -1617,6 +1749,14 @@ HDDEDATA nsNativeAppSupportOS2::CreateDDEData( DWORD value ) { // unfortunately (if you can fix that, please do). void nsNativeAppSupportOS2::HandleRequest( LPBYTE request, PRBool newWindow ) { + + // if initial hidden window is still being displayed, we need to ignore requests + // because such requests might not function properly. See bug 147223 for details + + if (mInitialWindow) { + return; + } + // Parse command line. nsCOMPtr args; @@ -1658,12 +1798,16 @@ nsNativeAppSupportOS2::HandleRequest( LPBYTE request, PRBool newWindow ) { return; } - // try using the command line service to get the url - nsCString taskURL; - rv = GetStartupURL(args, taskURL); - if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(nativeApp->EnsureProfile(args))) { - (void)OpenWindow(taskURL.get(), ""); - return; + // try for the "-profilemanager" argument, in which case we want the + // profile manager to appear, but only if there are no windows open + + rv = args->GetCmdLineValue( "-profilemanager", getter_Copies(arg)); + if ( NS_SUCCEEDED(rv) && (const char*)arg ) { // -profilemanager on command line + nsCOMPtr window; + GetMostRecentWindow(0, getter_AddRefs(window)); + if (!window) { // there are no open windows + mForceProfileStartup = PR_TRUE; + } } // try for the "-kill" argument, to shut down the server @@ -1693,7 +1837,49 @@ nsNativeAppSupportOS2::HandleRequest( LPBYTE request, PRBool newWindow ) { return; } - // ok, no idea what the param is. + // Try standard startup's command-line handling logic from nsAppRunner.cpp... + + // Need profile before opening windows. + rv = nativeApp->EnsureProfile(args); + if (NS_FAILED(rv)) return; + + // This will tell us whether the command line processing opened a window. + PRBool windowOpened = PR_FALSE; + + // If there are no command line arguments, then we want to open windows + // based on startup prefs (which say to open navigator and/or mailnews + // and/or composer), or, open just a Navigator window. We do the former + // if there are no open windows (i.e., we're in turbo mode), the latter + // if there are open windows. Note that we call DoCommandLines in the + // case where there are no command line args but there are windows open + // (i.e., with heedStartupPrefs==PR_FALSE) despite the fact that it may + // not actually do anything in that case. That way we're covered if the + // logic in DoCommandLines changes. Note that we cover this case below + // by opening a navigator window if DoCommandLines doesn't open one. We + // have to cover that case anyway, because DoCommandLines won't open a + // window when given "mozilla -foobar" or the like. + PRBool heedStartupPrefs = PR_FALSE; + PRInt32 argc = 0; + args->GetArgc( &argc ); + if ( argc <= 1 ) { + // Use startup prefs iff there are no windows currently open. + nsCOMPtr win; + GetMostRecentWindow( 0, getter_AddRefs( win ) ); + if ( !win ) { + heedStartupPrefs = PR_TRUE; + } + } + + // Process command line options. + rv = DoCommandLines( args, heedStartupPrefs, &windowOpened ); + + // If a window was opened, then we're done. + // Note that we keep on trying in the unlikely event of an error. + if (rv == NS_ERROR_NOT_AVAILABLE || rv == NS_ERROR_ABORT || windowOpened) { + return; + } + + // ok, no idea what the param is. #if MOZ_DEBUG_DDE printf( "Unknown request [%s]\n", (char*) request ); #endif @@ -1702,14 +1888,11 @@ nsNativeAppSupportOS2::HandleRequest( LPBYTE request, PRBool newWindow ) { "@mozilla.org/commandlinehandler/general-startup;1?type=browser"; nsCOMPtr handler = do_GetService(contractID, &rv); if (NS_FAILED(rv)) return; - - rv = nativeApp->EnsureProfile(args); - if (NS_FAILED(rv)) return; - + nsXPIDLString defaultArgs; rv = handler->GetDefaultArgs(getter_Copies(defaultArgs)); if (NS_FAILED(rv) || !defaultArgs) return; - + if (defaultArgs) { nsCAutoString url; url.AssignWithConversion( defaultArgs ); @@ -1879,7 +2062,6 @@ nsNativeAppSupportOS2::GetCmdLineArgs( LPBYTE request, nsICmdLineService **aResu // at this point if we were launched invisibly in -turbo mode, and // the profile mgr needed to show UI (to pick from multiple profiles). // At this point, we can show UI, so call DoProfileStartUp(). - nsresult nsNativeAppSupportOS2::EnsureProfile(nsICmdLineService* args) { @@ -1891,16 +2073,30 @@ nsNativeAppSupportOS2::EnsureProfile(nsICmdLineService* args) if (NS_FAILED(rv)) return rv; // If we have a profile, everything is fine. + // unless mForceProfileStartup is TRUE. This flag is set when the + // last window is closed in -turbo mode. When TRUE, it forces the + // profile UI to come up at the beginning of the next -turbo session + // even if we currently have a profile. PRBool haveProfile; rv = profileMgr->IsCurrentProfileAvailable(&haveProfile); - if (NS_SUCCEEDED(rv) && haveProfile) + if (!mForceProfileStartup && NS_SUCCEEDED(rv) && haveProfile) return NS_OK; // If the profile selection is happening, fail. PRBool doingProfileStartup; rv = profileMgr->GetIsStartingUp(&doingProfileStartup); if (NS_FAILED(rv) || doingProfileStartup) return NS_ERROR_FAILURE; - rv = appShell->DoProfileStartup(args, PR_TRUE); + + // See if profile manager is being suppressed via -silent flag. + PRBool canInteract = PR_TRUE; + nsXPIDLCString arg; + if (NS_SUCCEEDED(args->GetCmdLineValue("-silent", getter_Copies(arg))) && (const char*)arg) { + canInteract = PR_FALSE; + } + rv = appShell->DoProfileStartup(args, canInteract); + + mForceProfileStartup = PR_FALSE; + return rv; } @@ -1926,27 +2122,6 @@ nsNativeAppSupportOS2::OpenWindow( const char*urlstr, const char *args ) { return rv; } -static char procPropertyName[] = "MozillaProcProperty"; - -#ifdef DOWENEED -// 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 ); - } - } -} -#endif /* DOWENEED */ - HWND hwndForDOMWindow( nsISupports *window ) { nsCOMPtr ppScriptGlobalObj( do_QueryInterface(window) ); if ( !ppScriptGlobalObj ) { @@ -1970,41 +2145,15 @@ HWND hwndForDOMWindow( nsISupports *window ) { nsresult nsNativeAppSupportOS2::ReParent( nsISupports *window, HWND newParent ) { - HWND hMainFrame = hwndForDOMWindow( window ); - if ( !hMainFrame ) { + HWND hMainClient = hwndForDOMWindow( window ); + if ( !hMainClient ) { return NS_ERROR_FAILURE; } - -#ifdef DOWENEED - // 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 ); - } -#endif /* DOWENEED */ + HWND hMainFrame = WinQueryWindow(hMainClient, QW_PARENT); // Reset the parent. WinSetParent( hMainFrame, newParent, FALSE ); -#ifdef DOWENEED - // Restore old procedure. - if ( newParent ) { - ::SetWindowLong( hMainFrame, GWL_WNDPROC, oldProc ); - ::RemoveProp( hMainFrame, procPropertyName ); - } -#endif /* DOWENEED */ - return NS_OK; } @@ -2111,69 +2260,6 @@ nsNativeAppSupportOS2::OpenBrowserWindow( const char *args, PRBool newWindow ) { return OpenWindow( "chrome://navigator/content", args ); } -#ifdef DOWENEED -// Utility function that sets up system tray icon. -void -nsNativeAppSupportWin::SetupSysTrayIcon() { - // Messages go to the hidden window. - mIconData.hWnd = (HWND)MessageWindow(); - - // Icon is our default application icon. - mIconData.hIcon = ::LoadIcon( ::GetModuleHandle( NULL ), IDI_APPLICATION ), - - // Tooltip is the brand short name. - mIconData.szTip[0] = 0; - nsCOMPtr svc( do_GetService( NS_STRINGBUNDLE_CONTRACTID ) ); - if ( svc ) { - nsCOMPtr bundle1; - svc->CreateBundle( "chrome://global/locale/brand.properties", getter_AddRefs( bundle1 ) ); - if ( bundle1 ) { - nsXPIDLString tooltip; - bundle1->GetStringFromName( NS_LITERAL_STRING( "brandShortName" ).get(), - getter_Copies( tooltip ) ); - // (damned strings...) - ::strncpy( mIconData.szTip, - NS_LossyConvertUCS2toASCII(tooltip).get(), - sizeof mIconData.szTip - 1 ); - } - // Build menu. - nsCOMPtr bundle2; - svc->CreateBundle( "chrome://communicator/locale/profile/profileManager.properties", - getter_AddRefs( bundle2 ) ); - nsAutoString exitText; - if ( bundle2 ) { - nsXPIDLString text; - bundle2->GetStringFromName( NS_LITERAL_STRING( "exitButton" ).get(), - getter_Copies( text ) ); - exitText = (const PRUnichar*)text; - } - if ( exitText.IsEmpty() ) { - // Fall back to this. - exitText = NS_LITERAL_STRING( "Exit" ); - } - - // Create menu and add item. - mTrayIconMenu = ::CreatePopupMenu(); - ::AppendMenuW( mTrayIconMenu, MF_STRING, TURBO_QUIT, exitText.get() ); - - } - - // Add the tray icon. - ::Shell_NotifyIcon( NIM_ADD, &mIconData ); -} - -// Utility function to remove the system tray icon. -void -nsNativeAppSupportWin::RemoveSysTrayIcon() { - // Remove the tray icon. - ::Shell_NotifyIcon( NIM_DELETE, &mIconData ); - // Delete the menu. - ::DestroyMenu( mTrayIconMenu ); -} -#endif /* DOWENEED */ - - - // This opens a special browser window for purposes of priming the pump for // server mode (getting stuff into the caching, loading .dlls, etc.). The // window will have these attributes: @@ -2182,10 +2268,15 @@ nsNativeAppSupportWin::RemoveSysTrayIcon() { // - Pass magic arg to cause window to close in onload handler. NS_IMETHODIMP nsNativeAppSupportOS2::StartServerMode() { -#ifdef DOWENEED - // Turn on system tray icon. - SetupSysTrayIcon(); -#endif /* DOWENEED */ + + if (mShouldShowUI) { + // We dont have to anything anymore. The native UI + // will create the window + return NS_OK; + } + + // Since native UI wont create any window, we create a hidden window + // so thing work alright. // Create some of the objects we'll need. nsCOMPtr ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); @@ -2209,22 +2300,23 @@ nsNativeAppSupportOS2::StartServerMode() { // Put args into array. if ( NS_FAILED( argArray->AppendElement( arg1 ) ) || - NS_FAILED( argArray->AppendElement( arg2 ) ) ) { + NS_FAILED( argArray->AppendElement( arg2 ) ) ) { return NS_OK; } // Now open the window. nsCOMPtr newWindow; ww->OpenWindow( 0, - "chrome://navigator/content", - "_blank", - "chrome,dialog=no,toolbar=no", - argArray, - getter_AddRefs( newWindow ) ); + "chrome://navigator/content", + "_blank", + "chrome,dialog=no,toolbar=no", + argArray, + getter_AddRefs( newWindow ) ); if ( !newWindow ) { return NS_OK; } + mInitialWindow = newWindow; // Hide this window by re-parenting it (to ensure it doesn't appear). ReParent( newWindow, (HWND)MessageWindow() ); @@ -2234,62 +2326,107 @@ nsNativeAppSupportOS2::StartServerMode() { NS_IMETHODIMP nsNativeAppSupportOS2::SetIsServerMode( PRBool isServerMode ) { - // If it is being turned off, remove systray icon. - if ( mServerMode && !isServerMode ) { -#ifdef DOWENEED - RemoveSysTrayIcon(); -#endif /* DOWENEED */ - } return nsNativeAppSupportBase::SetIsServerMode( isServerMode ); } NS_IMETHODIMP nsNativeAppSupportOS2::OnLastWindowClosing( nsIXULWindow *aWindow ) { - nsresult rv; - - if (!mServerMode) + if ( !mServerMode ) return NS_OK; // If the last window closed is our special "turbo" window made // in StartServerMode(), don't do anything. nsCOMPtr docShell; - (void)aWindow->GetDocShell(getter_AddRefs(docShell)); - nsCOMPtr domWindow(do_GetInterface(docShell)); - if (domWindow == mInitialWindow) { + ( void )aWindow->GetDocShell( getter_AddRefs( docShell ) ); + nsCOMPtr domWindow( do_GetInterface( docShell ) ); + if ( domWindow == mInitialWindow ) { mInitialWindow = nsnull; return NS_OK; } - nsCOMPtr profileMgr(do_GetService(NS_PROFILE_CONTRACTID, &rv)); - if (NS_FAILED(rv)) return rv; - rv = profileMgr->ShutDownCurrentProfile(nsIProfile::SHUTDOWN_PERSIST); - if (NS_FAILED(rv)) return rv; - - return NS_OK; -} + // If the last window closed is our confirmation dialog, + // don't do anything. + if ( mLastWindowIsConfirmation ) { + mLastWindowIsConfirmation = PR_FALSE; + return NS_OK; + } - -// go through the command line arguments, and try to load a handler -// for one, and when we do, get the chrome URL for its task -nsresult -nsNativeAppSupportOS2::GetStartupURL(nsICmdLineService *args, nsCString& taskURL) -{ nsresult rv; - - nsCOMPtr handler; - // see if there is a handler - rv = args->GetHandlerForParam(nsnull, getter_AddRefs(handler)); - if (NS_FAILED(rv)) return rv; - - // ok, from here on out, failures really are fatal - nsXPIDLCString url; - rv = handler->GetChromeUrlForTask(getter_Copies(url)); - if (NS_FAILED(rv)) return rv; + // If activated by the browser.turbo.singleProfileOnly pref, + // check for multi-profile situation and turn off turbo mode + // if there are multiple profiles. + PRBool singleProfileOnly = PR_FALSE; + nsCOMPtr prefService( do_GetService( NS_PREF_CONTRACTID, &rv ) ); + if ( NS_SUCCEEDED( rv ) ) { + prefService->GetBoolPref( "browser.turbo.singleProfileOnly", &singleProfileOnly ); + } + if ( singleProfileOnly ) { + nsCOMPtr profileMgr( do_GetService( NS_PROFILE_CONTRACTID, &rv ) ); + if ( NS_SUCCEEDED( rv ) ) { + PRInt32 profileCount = 0; + if ( NS_SUCCEEDED( profileMgr->GetProfileCount( &profileCount ) ) && + profileCount > 1 ) { + // Turn off turbo mode and quit the application. + SetIsServerMode( PR_FALSE ); + nsCOMPtr appShell = + do_GetService( "@mozilla.org/appshell/appShellService;1", &rv); + if ( NS_SUCCEEDED( rv ) ) { + appShell->Quit(); + } + return NS_OK; + } + } + } - taskURL.Assign(url.get()); + nsCOMPtr appShell = + do_GetService( "@mozilla.org/appshell/appShellService;1", &rv); + if ( NS_SUCCEEDED( rv ) ) { + // Instead of staying alive, launch a new instance of the application and then + // terminate for real. We take steps to ensure that the new instance will run + // as a "server process" and not try to pawn off its request back on this + // instance. + + // Grab mutex. Process termination will release it. + Mutex mutexLock = Mutex(mMutexName); + NS_ENSURE_TRUE(mutexLock.Lock(MOZ_DDE_START_TIMEOUT), NS_ERROR_FAILURE ); + + // Turn off MessageWindow so the other process can't see us. + MessageWindow mw; + mw.Destroy(); + + // Launch another instance. + char buffer[ CCHMAXPATH ]; + // Same application as this one. + PPIB ppib; + PTIB ptib; + DosGetInfoBlocks( &ptib, &ppib ); + DosQueryModuleName( ppib->pib_hmte, CCHMAXPATH, buffer ); + + // Now do the OS/2 stuff... + STARTDATA startData = {0}; + ULONG idSession; + PID pid; + char pszObjectBuffer[CCHMAXPATH]; + + startData.PgmName = buffer; + startData.Length = sizeof(startData); + startData.Related = SSF_RELATED_INDEPENDENT; + startData.ObjectBuffer = pszObjectBuffer; + startData.ObjectBuffLen = CCHMAXPATH; + startData.InheritOpt = SSF_INHERTOPT_PARENT; + // The new process must run in turbo mode (no splash screen, no window, etc.). + startData.PgmInputs = " -turbo"; + + DosStartSession(&startData, &idSession, &pid); + + // Turn off turbo mode and quit the application. + SetIsServerMode( PR_FALSE ); + appShell->Quit(); + + // Done. This app will now commence shutdown. + } return NS_OK; } - diff --git a/mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.h b/mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.h index 6a16d5ea328..a7eb9d5ab8d 100644 --- a/mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.h +++ b/mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.h @@ -324,3 +324,13 @@ BOOL (* APIENTRY WinDdeUninitialize)(HDDEINST); #endif /* _H_DDEML */ +typedef ULONG DWORD; +typedef PBYTE LPBYTE; +typedef HDATA HDDEDATA; + +#define CP_WINANSI 0 // When 0 is specified for codepage on these + // dde functions, it will use the codepage + // that is associated with the current thread. + // CP_WINANSI in win32 means that the non + // unicode version of DdeCreateStringHandle + // was used.