1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is Mozilla Communicator client code.
15
* The Initial Developer of the Original Code is Netscape Communications
16
* Corporation. Portions created by Netscape are
17
* Copyright (C) 1998 Netscape Communications Corporation. All
21
* Bill Law law@netscape.com
28
#define INCL_DOSERRORS
31
#include "nsNativeAppSupportBase.h"
32
#include "nsNativeAppSupportOS2.h"
34
#include "nsICmdLineService.h"
36
#include "nsXPIDLString.h"
37
#include "nsIComponentManager.h"
38
#include "nsIServiceManager.h"
39
#include "nsICmdLineHandler.h"
40
#include "nsIDOMWindow.h"
42
#include "nsISupportsPrimitives.h"
43
#include "nsISupportsArray.h"
44
#include "nsIWindowWatcher.h"
45
#include "nsIDOMWindowInternal.h"
46
#include "nsIScriptGlobalObject.h"
47
#include "nsIDocShell.h"
48
#include "nsIBaseWindow.h"
49
#include "nsIWidget.h"
50
#include "nsIAppShellService.h"
51
#include "nsIProfileInternal.h"
52
#include "nsIXULWindow.h"
53
#include "nsIInterfaceRequestor.h"
54
#include "nsIInterfaceRequestorUtils.h"
56
#include "nsIPromptService.h"
58
#include "nsIObserverService.h"
60
#include "nsPaletteOS2.h"
62
// These are needed to load a URL in a browser window.
63
#include "nsIDOMLocation.h"
64
#include "nsIJSContextStack.h"
65
#include "nsIWindowMediator.h"
74
// getting from nsAppRunner. Use to help track down arguments.
75
extern char ** __argv;
78
/* trying to keep this like Window's COPYDATASTRUCT, but a compiler error is
79
* forcing me to add chBuff so that we can append the data to the end of the
82
typedef struct _COPYDATASTRUCT
88
}COPYDATASTRUCT, *PCOPYDATASTRUCT;
89
#define WM_COPYDATA (WM_USER + 60)
91
char szCommandLine[2*CCHMAXPATH];
93
static HWND hwndForDOMWindow( nsISupports * );
97
GetMostRecentWindow(const PRUnichar* aType, nsIDOMWindowInternal** aWindow) {
99
nsCOMPtr<nsIWindowMediator> med( do_GetService( NS_WINDOWMEDIATOR_CONTRACTID, &rv ) );
100
if ( NS_FAILED( rv ) )
104
return med->GetMostRecentWindow( aType, aWindow );
106
return NS_ERROR_FAILURE;
111
activateWindow( nsIDOMWindowInternal *win ) {
112
// Try to get native window handle.
113
HWND hwnd = hwndForDOMWindow( win );
116
/* if we are looking at a client window, then we really probably want
117
* the frame so that we can manipulate THAT
119
LONG id = WinQueryWindowUShort( hwnd, QWS_ID );
120
if( id == FID_CLIENT )
122
hwnd = WinQueryWindow( hwnd, QW_PARENT );
125
// Restore the window in case it is minimized.
126
// Use the OS call, if possible.
127
WinSetWindowPos( hwnd, 0L, 0L, 0L, 0L, 0L,
128
SWP_SHOW | SWP_RESTORE | SWP_ACTIVATE );
130
// Use internal method.
137
// Define this macro to 1 to get DDE debugging output.
138
#define MOZ_DEBUG_DDE 0
142
#define MOZ_DEBUG_DDE 1
145
class nsSplashScreenOS2 : public nsISplashScreen {
148
~nsSplashScreenOS2();
153
// nsISupports methods
154
NS_IMETHOD_(nsrefcnt) AddRef() {
158
NS_IMETHOD_(nsrefcnt) Release() {
166
NS_IMETHOD QueryInterface( const nsIID &iid, void**p ) {
170
if ( iid.Equals( NS_GET_IID( nsISplashScreen ) ) ) {
171
nsISplashScreen *result = this;
174
} else if ( iid.Equals( NS_GET_IID( nsISupports ) ) ) {
175
nsISupports *result = NS_STATIC_CAST( nsISupports*, this );
182
rv = NS_ERROR_NULL_POINTER;
187
void SetDialog( HWND dlg );
189
static nsSplashScreenOS2* GetPointer( HWND dlg );
198
}; // class nsSplashScreenOS2
200
MRESULT EXPENTRY DialogProc( HWND dlg, ULONG msg, MPARAM mp1, MPARAM mp2 );
201
void ThreadProc (void *splashScreen);
203
// Simple Win32 mutex wrapper.
205
Mutex( const char *name )
209
/* OS/2 named semaphores must begin with "\\SEM32\\" to be valid */
210
mName.Insert("\\SEM32\\", 0);
211
APIRET rc = DosCreateMutexSem( mName.get(), &mHandle, 0, FALSE );
213
if ( rc != NO_ERROR ) {
214
printf( "CreateMutex error = 0x%08X\n", rc );
220
// Make sure we release it if we own it.
223
APIRET rc = DosCloseMutexSem( mHandle );
225
if ( rc != NO_ERROR ) {
226
printf( "CloseHandle error = 0x%08X\n", rc );
231
BOOL Lock( DWORD timeout ) {
234
printf( "Waiting (%d msec) for DDE mutex...\n", (int)timeout );
236
mState = DosRequestMutexSem( mHandle, timeout );
238
printf( "...wait complete, result = 0x%08X\n", (int)mState );
240
return mState == NO_ERROR;
246
if ( mHandle && mState == NO_ERROR ) {
248
printf( "Releasing DDE mutex\n" );
250
DosReleaseMutexSem( mHandle );
262
* This section describes the Win32 DDE service implementation for
263
* Mozilla. DDE is used on Win32 platforms to communicate between
264
* separate instances of mozilla.exe (or other Mozilla-based
265
* executables), or, between the Win32 desktop shell and Mozilla.
267
* The first instance of Mozilla will become the "server" and
268
* subsequent executables (and the shell) will use DDE to send
269
* requests to that process. The requests are DDE "execute" requests
270
* that pass the command line arguments.
272
* Mozilla registers the DDE application "Mozilla" and currently
273
* supports only the "WWW_OpenURL" topic. This should be reasonably
274
* compatible with applications that interfaced with Netscape
275
* Communicator (and its predecessors?). Note that even that topic
276
* may not be supported in a compatible fashion as the command-line
277
* options for Mozilla are different than for Communiator.
279
* It is imperative that at most one instance of Mozilla execute in
280
* "server mode" at any one time. The "native app support" in Mozilla
281
* on Win32 ensures that only the server process performs XPCOM
282
* initialization (that is not required for subsequent client processes
283
* to communicate with the server process).
285
* To guarantee that only one server starts up, a Win32 "mutex" is used
286
* to ensure only one process executes the server-detection code. That
287
* code consists of initializing DDE and doing a DdeConnect to Mozilla's
288
* application/topic. If that connection succeeds, then a server process
289
* must be running already.
291
* Otherwise, no server has started. In that case, the current process
292
* calls DdeNameService to register that application/topic. Only at that
293
* point does the mutex get released.
295
* There are a couple of subtleties that one should be aware of:
297
* 1. It is imperative that DdeInitialize be called only after the mutex
298
* lock has been obtained. The reason is that at shutdown, DDE
299
* notifications go out to all initialized DDE processes. Thus, if
300
* the mutex is owned by a terminating intance of Mozilla, then
301
* calling DdeInitialize and then WaitForSingleObject will cause the
302
* DdeUninitialize from the terminating process to "hang" until the
303
* process waiting for the mutex times out (and can then service the
304
* notification that the DDE server is terminating). So, don't mess
305
* with the sequence of things in the startup/shutdown logic.
307
* 2. All mutex requests are made with a reasonably long timeout value and
308
* are designed to "fail safe" (i.e., a timeout is treated as failure).
310
* 3. An attempt has been made to minimize the degree to which the main
311
* Mozilla application logic needs to be aware of the DDE mechanisms
312
* implemented herein. As a result, this module surfaces a very
313
* large-grained interface, consisting of simple start/stop methods.
314
* As a consequence, details of certain scenarios can be "lost."
315
* Particularly, incoming DDE requests can arrive after this module
316
* initiates the DDE server, but before Mozilla is initialized to the
317
* point where those requests can be serviced (e.g., open a browser
318
* window to a particular URL). Since the client process sends the
319
* request early on, it may not be prepared to respond to that error.
320
* Thus, such situations may fail silently. The design goal is that
321
* they fail harmlessly. Refinements on this point will be made as
322
* details emerge (and time permits).
327
* A significant DDE bug in Windows is causing Mozilla to get wedged at
328
* startup. This is detailed in Bugzill bug 53952
329
* (http://bugzilla.mozilla.org/show_bug.cgi?id=53952).
331
* To resolve this, we are using a new strategy:
332
* o Use a "message window" to detect that Mozilla is already running and
333
* to pass requests from a second instance back to the first;
334
* o Run only as a "DDE server" (not as DDE client); this avoids the
335
* problematic call to DDEConnect().
337
* We still use the mutex semaphore to protect the code that detects
338
* whether Mozilla is already running.
341
class nsNativeAppSupportOS2 : public nsNativeAppSupportBase
344
// Overrides of base implementation.
345
NS_IMETHOD Start( PRBool *aResult );
346
NS_IMETHOD Stop( PRBool *aResult );
348
NS_IMETHOD StartServerMode();
349
NS_IMETHOD OnLastWindowClosing();
350
NS_IMETHOD SetIsServerMode( PRBool isServerMode );
351
NS_IMETHOD EnsureProfile(nsICmdLineService* args);
353
// The "old" Start method (renamed).
354
NS_IMETHOD StartDDE();
356
// Utility function to handle a Win32-specific command line
357
// option: "-console", which dynamically creates a Windows
359
// On OS/2, we use the return from CheckConsole to determine
360
// whether or not to use the OS/2 specific turbo mode
361
PRBool CheckConsole();
364
static HDDEDATA APIENTRY HandleDDENotification( ULONG idInst,
373
static void HandleRequest( LPBYTE request, PRBool newWindow = PR_TRUE );
374
static nsCString ParseDDEArg( HSZ args, int index );
375
static void ActivateLastWindow();
376
static HDDEDATA CreateDDEData( DWORD value );
377
static HDDEDATA CreateDDEData( LPBYTE value, DWORD len );
378
static PRBool InitTopicStrings();
379
static int FindTopic( HSZ topic );
380
static nsresult GetCmdLineArgs( LPBYTE request, nsICmdLineService **aResult );
381
static nsresult OpenWindow( const char *urlstr, const char *args );
382
static nsresult OpenBrowserWindow( const char *args, PRBool newWindow = PR_TRUE );
383
static nsresult ReParent( nsISupports *window, HWND newParent );
384
static nsresult GetStartupURL(nsICmdLineService *args, nsCString& taskURL);
387
static int mConversations;
394
topicUnRegisterViewer,
396
// Note: Insert new values above this line!!!!!
397
topicCount // Count of the number of real topics
400
static HSZ mApplication, mTopics[ topicCount ];
401
static DWORD mInstance;
402
static char *mAppName;
403
static PRBool mInitialWindowActive;
404
static PRBool mForceProfileStartup;
405
static char mMutexName[];
406
static PRBool mUseDDE;
407
friend struct MessageWindow;
408
}; // nsNativeAppSupportOS2
410
nsSplashScreenOS2::nsSplashScreenOS2()
411
: mDlg( 0 ), mBitmap( 0 ), mRefCnt( 0 ),
412
hdcMemory( 0 ), hpsMemory( 0 ), mBitmapCX(0), mBitmapCY(0) {
415
nsSplashScreenOS2::~nsSplashScreenOS2() {
417
printf( "splash screen dtor called\n" );
419
// Make sure dialog is gone.
424
nsSplashScreenOS2::Show() {
425
//Spawn new thread to display real splash screen.
426
int handle = _beginthread( ThreadProc, NULL, 16384, (void *)this );
431
nsSplashScreenOS2::Hide() {
433
// Dismiss the dialog.
434
WinPostMsg(mDlg, WM_CLOSE, 0, 0);
436
GpiSetBitmap(hpsMemory, NULLHANDLE);
438
GpiDeleteBitmap(mBitmap);
442
DevCloseDC(hdcMemory);
446
GpiDestroyPS(hpsMemory);
453
HBITMAP LoadAndSetBitmapFromFile(HPS hps, PSZ pszFilename)
455
FILE *fp = fopen(pszFilename, "rb");
459
fseek(fp, 0, SEEK_END );
460
ULONG cbFile = ftell(fp);
465
fseek(fp, 0, SEEK_SET );
466
PBYTE pBitmapData = (PBYTE)malloc(cbFile);
467
fread((PVOID)pBitmapData, cbFile, 1, fp);
470
PBITMAPFILEHEADER2 pbfh2 = (PBITMAPFILEHEADER2)pBitmapData;
471
PBITMAPINFOHEADER2 pbmp2 = NULL;
473
switch (pbfh2->usType)
475
case BFT_BITMAPARRAY:
477
* If this is a Bitmap-Array, adjust pointer to the normal
478
* file header. We'll just use the first bitmap in the
479
* array and ignore other device forms.
481
pbfh2 = &(((PBITMAPARRAYFILEHEADER2) pBitmapData)->bfh2);
482
pbmp2 = &pbfh2->bmp2;
485
pbmp2 = &pbfh2->bmp2;
490
case BFT_COLORPOINTER:
501
if (pbmp2->cbFix == sizeof(BITMAPINFOHEADER))
502
lScans = (LONG) ((PBITMAPINFOHEADER)pbmp2)->cy;
506
HBITMAP hbmp = GpiCreateBitmap(hps, pbmp2, 0L, NULL, NULL);
512
if (GpiSetBitmap(hps, hbmp) == HBM_ERROR) {
513
GpiDeleteBitmap(hbmp);
518
LONG lScansSet = GpiSetBitmapBits(hps, 0L, lScans, pBitmapData + pbfh2->offBits,
519
(PBITMAPINFO2) pbmp2);
522
if (lScansSet != lScans) {
523
GpiSetBitmap(hps, NULLHANDLE);
524
GpiDeleteBitmap(hbmp);
532
nsSplashScreenOS2::LoadBitmap() {
533
hdcMemory = DevOpenDC((HAB)0, OD_MEMORY, "*", 0L, NULL, 0L);
534
SIZEL sizel = {0, 0};
535
hpsMemory = GpiCreatePS((HAB)0, hdcMemory, &sizel,
536
PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
538
// Check for '<program-name>.bmp" in same directory as executable.
541
char fileName[CCHMAXPATH];
542
DosGetInfoBlocks( &ptib, &ppib);
543
DosQueryModuleName( ppib->pib_hmte, CCHMAXPATH, fileName);
544
int fileNameLen = strlen(fileName);
545
if (fileNameLen >=3) {
546
fileName[ fileNameLen - 3 ] = 0;
547
strcat( fileName, "bmp" );
548
// Try to load bitmap from that file.
549
mBitmap = LoadAndSetBitmapFromFile(hpsMemory, fileName);
552
mBitmap = GpiLoadBitmap(hpsMemory, NULL, IDB_SPLASH, 0L, 0L);
553
GpiSetBitmap(hpsMemory, mBitmap);
555
BITMAPINFOHEADER bitmap;
556
bitmap.cbFix = sizeof(BITMAPINFOHEADER);
557
GpiQueryBitmapParameters(mBitmap, &bitmap);
558
mBitmapCX = bitmap.cx;
559
mBitmapCY = bitmap.cy;
562
MRESULT EXPENTRY DialogProc( HWND dlg, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
563
if ( msg == WM_INITDLG ) {
564
// Store dialog handle.
565
nsSplashScreenOS2 *splashScreen = (nsSplashScreenOS2*)mp2;
567
splashScreen->SetDialog( dlg );
569
// Try to load customized bitmap.
570
splashScreen->LoadBitmap();
573
/* Size and center the splash screen correctly. The flags in the
574
* dialog template do not do the right thing if the user's
575
* machine is using large fonts.
577
HBITMAP hbitmap = splashScreen->mBitmap;
579
WinSetWindowPos( dlg,
581
WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN )/2 - splashScreen->mBitmapCX/2,
582
WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN )/2 - splashScreen->mBitmapCY/2,
583
splashScreen->mBitmapCX,
584
splashScreen->mBitmapCY,
585
SWP_ACTIVATE | SWP_MOVE | SWP_SIZE );
586
WinShowWindow( dlg, TRUE );
588
return (MRESULT)FALSE;
590
else if ( msg == WM_PAINT ) {
591
nsSplashScreenOS2 *splashScreen = (nsSplashScreenOS2*)WinQueryWindowPtr( dlg, QWL_USER );
592
HPS hps = WinBeginPaint (dlg, NULLHANDLE, NULL);
594
nsPaletteOS2::SelectGlobalPalette(hps, dlg);
597
POINTL aptl[8] = {0, 0, splashScreen->mBitmapCX, splashScreen->mBitmapCY,
602
GpiBitBlt( hps, splashScreen->hpsMemory, 3L, aptl, ROP_SRCCOPY, 0L );
604
return (MRESULT)TRUE;
607
else if ( msg == WM_REALIZEPALETTE ) {
608
HPS hps = WinGetPS(dlg);
609
nsPaletteOS2::SelectGlobalPalette(hps, dlg);
611
WinInvalidateRect( dlg, 0, TRUE);
612
return (MRESULT)TRUE;
615
return WinDefDlgProc (dlg, msg, mp1, mp2);
618
void nsSplashScreenOS2::SetDialog( HWND dlg ) {
619
// Save dialog handle.
621
// Store this pointer in the dialog.
622
WinSetWindowPtr( mDlg, QWL_USER, this );
625
nsSplashScreenOS2 *nsSplashScreenOS2::GetPointer( HWND dlg ) {
626
// Get result from dialog user data.
627
PVOID data = WinQueryWindowPtr( dlg, QWL_USER );
628
return (nsSplashScreenOS2*)data;
631
void ThreadProc(void *splashScreen) {
632
HAB hab = WinInitialize( 0 );
633
HMQ hmq = WinCreateMsgQueue( hab, 0 );
634
WinDlgBox( HWND_DESKTOP, HWND_DESKTOP, (PFNWP)DialogProc, NULLHANDLE, IDD_SPLASH, (MPARAM)splashScreen );
635
WinDestroyMsgQueue( hmq );
640
#define TURBOD "mozturbo.exe"
642
PRBool gAbortServer = PR_FALSE;
645
nsNativeAppSupportOS2::CheckConsole() {
646
CHAR pszAppPath[CCHMAXPATH];
649
DosGetInfoBlocks(&ptib, &ppib);
650
DosQueryModuleName(ppib->pib_hmte, CCHMAXPATH, pszAppPath);
651
*strrchr(pszAppPath, '\\') = '\0'; // XXX DBCS misery
653
for ( int i = 1; i < __argc; i++ ) {
654
if ( strcmp( "-console", __argv[i] ) == 0
656
strcmp( "/console", __argv[i] ) == 0 ) {
657
/* Figure out some magic way to create a console on OS/2 */
658
} else if ( strcmp( "-turbo", __argv[i] ) == 0
660
strcmp( "/turbo", __argv[i] ) == 0
662
strcmp( "-server", __argv[i] ) == 0
664
strcmp( "/server", __argv[i] ) == 0 ) {
667
CHAR pszTurboPath[CCHMAXPATH];
669
strcpy(pszTurboPath, pszAppPath);
670
strcat(pszTurboPath, "\\");
671
strcat(pszTurboPath, TURBOD);
672
int statrv = stat(pszTurboPath, &st);
674
/* If we can't find the turbo EXE, use the Mozilla turbo */
677
CHAR pszArgString[CCHMAXPATH];
679
strcpy(pszArgString, pszTurboPath);
680
strcat(pszArgString, " -l -p ");
681
strcat(pszArgString, pszAppPath);
682
pszArgString[strlen(pszTurboPath)] = '\0';
684
DosExecPgm(NULL,0,EXEC_BACKGROUND,
688
return PR_FALSE; /* Don't start the app */
690
// Start in server mode (and suppress splash screen).
691
mServerMode = PR_TRUE;
692
mShouldShowUI = PR_FALSE;
693
__argv[i] = "-nosplash"; // Bit of a hack, but it works!
694
// Ignore other args.
699
for ( int j = 1; j < __argc; j++ ) {
700
if (strcmp("-killAll", __argv[j]) == 0 || strcmp("/killAll", __argv[j]) == 0 ||
701
strcmp("-kill", __argv[j]) == 0 || strcmp("/kill", __argv[j]) == 0) {
704
CHAR pszTurboPath[CCHMAXPATH];
706
strcpy(pszTurboPath, pszAppPath);
707
strcat(pszTurboPath, "\\");
708
strcat(pszTurboPath, TURBOD);
709
int statrv = stat(pszTurboPath, &st);
711
/* If we can't find the turbo EXE, use the Mozilla turbo */
714
CHAR pszArgString[CCHMAXPATH];
716
strcpy(pszArgString, pszTurboPath);
717
strcat(pszArgString, " -u");
718
pszArgString[strlen(pszTurboPath)] = '\0';
720
DosExecPgm(NULL,0,EXEC_BACKGROUND,
724
return PR_FALSE; /* Don't start the app */
726
gAbortServer = PR_TRUE;
732
return PR_TRUE; /* Start the app */
736
// Create and return an instance of class nsNativeAppSupportOS2.
738
NS_CreateNativeAppSupport( nsINativeAppSupport **aResult ) {
740
nsNativeAppSupportOS2 *pNative = new nsNativeAppSupportOS2;
742
// Check for dynamic console creation request.
743
// If CheckConsole returns PR_FALSE, we should
744
// start the turbo daemon and close the app.
745
if (pNative->CheckConsole() == PR_FALSE) {
747
return NS_ERROR_FAILURE;
750
NS_ADDREF( *aResult );
752
return NS_ERROR_OUT_OF_MEMORY;
755
return NS_ERROR_NULL_POINTER;
761
// Create instance of OS/2 splash screen object.
763
NS_CreateSplashScreen( nsISplashScreen **aResult ) {
764
/* In order to handle -splash on the command line, */
765
/* we use a variable to handle splash. Defaults to true. */
766
/* We set it to false if you have turned off the logo */
767
/* in OS/2, but then back to true if you specify -splash. */
768
BOOL doSplashScreen = TRUE;
772
PrfQueryProfileString( HINI_USERPROFILE, "PM_ControlPanel", "LogoDisplayTime", "1", pBuffer, 3);
773
if (pBuffer[0] == '0') {
774
doSplashScreen = FALSE;
776
for ( int i = 1; i < __argc; i++ ) {
777
if ( strcmp( "-quiet", __argv[i] ) == 0
779
strcmp( "/quiet", __argv[i] ) == 0 ) {
780
doSplashScreen = FALSE;
782
if ( strcmp( "-splash", __argv[i] ) == 0
784
strcmp( "/splash", __argv[i] ) == 0 ) {
785
doSplashScreen = TRUE;
788
if (!doSplashScreen) {
791
*aResult = new nsSplashScreenOS2;
793
NS_ADDREF( *aResult );
795
return NS_ERROR_OUT_OF_MEMORY;
798
return NS_ERROR_NULL_POINTER;
805
#define MOZ_DDE_APPLICATION "Mozilla"
806
#define MOZ_STARTUP_MUTEX_NAME "StartupMutex"
807
#define MOZ_DDE_START_TIMEOUT 30000
808
#define MOZ_DDE_STOP_TIMEOUT 15000
809
#define MOZ_DDE_EXEC_TIMEOUT 15000
811
// The array entries must match the enum ordering!
812
const char * const topicNames[] = { "WWW_OpenURL",
814
"WWW_CancelProgress",
816
"WWW_RegisterViewer",
817
"WWW_UnRegisterViewer",
818
"WWW_GetWindowInfo" };
820
// Static member definitions.
821
int nsNativeAppSupportOS2::mConversations = 0;
822
HSZ nsNativeAppSupportOS2::mApplication = 0;
823
HSZ nsNativeAppSupportOS2::mTopics[nsNativeAppSupportOS2::topicCount] = { 0 };
824
DWORD nsNativeAppSupportOS2::mInstance = 0;
825
PRBool nsNativeAppSupportOS2::mInitialWindowActive = PR_FALSE;
826
PRBool nsNativeAppSupportOS2::mForceProfileStartup = PR_FALSE;
829
// Added this as pmddeml has no api like this
830
int DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
832
char chhsz1[CCHMAXPATH], chhsz2[CCHMAXPATH];
835
/* I am assuming that the strings will never be more that CCHMAXPATH in
836
* length. Safe bet (for now). To find true length, call WinDdeQueryString
837
* and pass in (hsz, NULL, 0L, 0) and it will return iLength. Passing 0
838
* for codepage will use the codepage of the current thread.
840
WinDdeQueryString( hsz1, chhsz1, sizeof( chhsz1 ), 0 );
841
WinDdeQueryString( hsz2, chhsz2, sizeof( chhsz2 ),0 );
843
rc = stricmp( chhsz1, chhsz2 );
849
char *GetCommandLine()
851
/* This function is meant to be like the Window's GetCommandLine() function.
852
* The value returned by pPIB->pib_pchcmd is of the format:
853
* <executable>\0<command line parameters>. So the first string is the
854
* .exe and the second string is what followed on the command line. Dorky,
855
* but I guess it'll have to do.
859
APIRET rc = NO_ERROR;
860
char *pchParam = NULL;
862
rc = DosGetInfoBlocks( &pTIB, &pPIB );
866
char *pchTemp = NULL;
867
pchParam = pPIB->pib_pchcmd;
868
strcpy( szCommandLine, pchParam );
869
iLen = strlen( pchParam );
871
/* szCommandLine[iLen] is '\0', so see what's next. Probably be another
872
* '\0', a space or start of the arguments
874
pchTemp = &(pchParam[iLen+1]);
876
/* At this point, szCommandLine holds just the program name. Now we
877
* go for the parameters. If our next value is a space, ignore it
878
* and go for the next character
882
szCommandLine[iLen] = ' ';
884
if( *pchTemp == ' ' )
888
strcpy( &(szCommandLine[iLen]), pchTemp );
893
return( szCommandLine );
896
typedef struct _DDEMLFN
900
} DDEMLFN, *PDDEMLFN;
902
DDEMLFN ddemlfnTable[] =
904
{ (PFN *)&WinDdeAbandonTransaction ,100 },
905
{ (PFN *)&WinDdeAccessData ,101 },
906
{ (PFN *)&WinDdeAddData ,102 },
907
{ (PFN *)&WinDdeSubmitTransaction ,103 },
908
{ (PFN *)&WinDdeCompareStringHandles ,104 },
909
{ (PFN *)&WinDdeConnect ,105 },
910
{ (PFN *)&WinDdeConnectList ,106 },
911
{ (PFN *)&WinDdeCreateDataHandle ,107 },
912
{ (PFN *)&WinDdeCreateStringHandle ,108 },
913
{ (PFN *)&WinDdeDisconnect ,109 },
914
{ (PFN *)&WinDdeDisconnectList ,110 },
915
{ (PFN *)&WinDdeEnableCallback ,111 },
916
{ (PFN *)&WinDdeFreeDataHandle ,112 },
917
{ (PFN *)&WinDdeFreeStringHandle ,113 },
918
{ (PFN *)&WinDdeGetData ,114 },
919
{ (PFN *)&WinDdeInitialize ,116 },
920
{ (PFN *)&WinDdeKeepStringHandle ,117 },
921
{ (PFN *)&WinDdeNameService ,118 },
922
{ (PFN *)&WinDdePostAdvise ,119 },
923
{ (PFN *)&WinDdeQueryConvInfo ,120 },
924
{ (PFN *)&WinDdeQueryNextServer ,121 },
925
{ (PFN *)&WinDdeQueryString ,122 },
926
{ (PFN *)&WinDdeReconnect ,123 },
927
{ (PFN *)&WinDdeSetUserHandle ,124 },
928
{ (PFN *)&WinDdeUninitialize ,126 },
932
/* SetupOS2ddeml makes sure that we can get pointers to all of the DDEML
933
* functions in demlfnTable using entrypoints. If we can't find one of them
934
* or can't load pmddeml.dll, then returns FALSE
939
HMODULE hmodDDEML = NULLHANDLE;
940
APIRET rc = NO_ERROR;
943
rc = DosLoadModule( NULL, 0, "PMDDEML", &hmodDDEML );
947
/* all of this had better work. Get ready to be a success! */
949
for( i; ddemlfnTable[i].ord != 0; i++ )
951
rc = DosQueryProcAddr( hmodDDEML, ddemlfnTable[i].ord, NULL,
952
ddemlfnTable[i].fn );
955
/* we're horked. Return rc = horked */
965
char nsNativeAppSupportOS2::mMutexName[ 128 ] = { 0 };
968
// Message window encapsulation.
969
struct MessageWindow {
970
// ctor/dtor are simplistic
972
// Try to find window.
976
char classname[CCHMAXPATH];
978
mHandle = NULLHANDLE;
980
hatomtbl = WinQuerySystemAtomTable();
981
mMsgWindowAtom = WinFindAtom(hatomtbl, className());
982
if (mMsgWindowAtom == 0)
984
// If there is not atom in the system table for this class name, then
985
// we can assume that the app is not currently running.
986
mMsgWindowAtom = WinAddAtom(hatomtbl, className());
988
// Found an existing atom for this class name. Cycle through existing
989
// windows and see if one with our window id and class name already
991
henum = WinBeginEnumWindows(HWND_OBJECT);
992
while ((hwndNext = WinGetNextWindow(henum)) != NULLHANDLE)
994
if (WinQueryWindowUShort(hwndNext, QWS_ID) == (USHORT)mMsgWindowAtom)
996
WinQueryClassName(hwndNext, CCHMAXPATH, classname);
997
if (strcmp(classname, className()) == 0)
1011
// Class name: appName + "MessageWindow"
1012
static const char *className() {
1013
static char classNameBuffer[128];
1014
static char *mClassName = 0;
1015
if ( !mClassName ) {
1016
sprintf( classNameBuffer,
1018
nsNativeAppSupportOS2::mAppName,
1020
mClassName = classNameBuffer;
1025
// Create: Register class and create window.
1026
NS_IMETHOD Create() {
1028
// Register the window class.
1029
NS_ENSURE_TRUE( WinRegisterClass( 0, className(),
1030
(PFNWP)&MessageWindow::WindowProc,
1034
/* Giving a size but offscreen so that won't be seen, even if all
1035
* goes wrong. Giving a size so that can be seen and understood by
1038
const char * pszClassName = className();
1039
mHandle = WinCreateWindow( HWND_OBJECT,
1042
WS_DISABLED, // style
1045
HWND_DESKTOP,// owner
1046
HWND_BOTTOM, // hwndbehind
1047
(USHORT)mMsgWindowAtom, // id
1049
NULL ); // pres params
1052
printf( "Message window = 0x%08X\n", (int)mHandle );
1058
// Destory: Get rid of window and reset mHandle.
1059
NS_IMETHOD Destroy() {
1060
nsresult retval = NS_OK;
1063
HATOMTBL hatomtbl = WinQuerySystemAtomTable();
1064
WinDeleteAtom(hatomtbl, mMsgWindowAtom);
1066
// DestroyWindow can only destroy windows created from
1068
BOOL desRes = WinDestroyWindow( mHandle );
1069
if ( FALSE != desRes ) {
1073
retval = NS_ERROR_FAILURE;
1080
// SendRequest: Pass string via WM_COPYDATA to message window.
1081
NS_IMETHOD SendRequest( const char *cmd ) {
1082
/* Nothing like WM_COPYDATA in OS/2, where the OS allows pointers to be
1083
* passed to a different process and automatically accessible by that
1084
* process. So we have to create shared mem on our side and then the
1085
* process that gets the WM_COPYDATA message has to do a
1086
* DosGetSharedMem on this pointer to be able to access the data
1089
COPYDATASTRUCT *pcds;
1090
APIRET rc = NO_ERROR;
1091
PVOID pvData = NULL;
1092
ULONG ulSize = sizeof(COPYDATASTRUCT)+strlen(cmd)+1;
1093
rc = DosAllocSharedMem( &pvData, NULL, ulSize,
1094
(PAG_COMMIT|PAG_READ|PAG_WRITE|OBJ_GETTABLE) );
1096
if( rc != NO_ERROR )
1098
/* don't even try doing anything else. Windows doesn't worry about
1099
* errors so I guess that we shouldn't either
1104
memset( pvData, '\0', ulSize );
1105
pcds = (COPYDATASTRUCT *)(pvData);
1107
pcds->cbData = strlen(cmd)+1;
1108
/* put the data in the buffer space immediately after the
1111
pcds->lpData = &(pcds->chBuff);
1114
strcpy( (char *)pcds->lpData, cmd );
1116
WinSendMsg( mHandle, WM_COPYDATA, 0, (MPARAM)pcds );
1117
DosFreeMem( pvData );
1123
static MRESULT EXPENTRY WindowProc( HWND msgWindow, ULONG msg, MPARAM wp,
1126
MRESULT rc = (MRESULT)TRUE;
1128
if ( msg == WM_COPYDATA ) {
1129
// This is an incoming request.
1130
COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lp;
1131
DosGetSharedMem( (PVOID)cds, PAG_READ|PAG_WRITE );
1133
printf( "Incoming request: %s\n", (const char*)cds->lpData );
1135
(void)nsNativeAppSupportOS2::HandleRequest( (LPBYTE)cds->lpData );
1138
/* We have to return a FALSE from WM_CREATE or this window will never
1139
* get off of the ground
1141
else if ( msg == WM_CREATE ) {
1142
rc = (MRESULT)FALSE;
1150
USHORT mMsgWindowAtom;
1151
}; // struct MessageWindow
1153
static char nameBuffer[128] = { 0 };
1154
char *nsNativeAppSupportOS2::mAppName = nameBuffer;
1155
PRBool nsNativeAppSupportOS2::mUseDDE = PR_FALSE;
1157
/* Start: Tries to find the "message window" to determine if it
1158
* exists. If so, then Mozilla is already running. In that
1159
* case, we use the handle to the "message" window and send
1160
* a request corresponding to this process's command line
1163
* If not, then this is the first instance of Mozilla. In
1164
* that case, we create and set up the message window.
1166
* The checking for existance of the message window must
1167
* be protected by use of a mutex semaphore.
1170
nsNativeAppSupportOS2::Start( PRBool *aResult ) {
1171
NS_ENSURE_ARG( aResult );
1172
NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED );
1174
if (getenv("MOZ_NO_REMOTE"))
1180
nsresult rv = NS_ERROR_FAILURE;
1181
*aResult = PR_FALSE;
1183
for ( int i = 1; i < __argc; i++ ) {
1184
if ( strcmp( "-dde", __argv[i] ) == 0 ||
1185
strcmp( "/dde", __argv[i] ) == 0 ) {
1190
// Grab mutex first.
1192
UINT id = ID_DDE_APPLICATION_NAME;
1193
retval = WinLoadString( NULLHANDLE, NULLHANDLE, id, sizeof(nameBuffer), nameBuffer );
1194
if ( retval == 0 ) {
1195
// No app name; just keep running.
1200
// Build mutex name from app name.
1201
PR_snprintf( mMutexName, sizeof mMutexName, "%s%s", nameBuffer, MOZ_STARTUP_MUTEX_NAME );
1202
Mutex startupLock = Mutex( mMutexName );
1204
NS_ENSURE_TRUE( startupLock.Lock( MOZ_DDE_START_TIMEOUT ), NS_ERROR_FAILURE );
1206
/* We need to have a message queue to do the MessageWindow stuff (for both
1207
* Create() and SendRequest()). If we don't have one, make it now.
1208
* If we are going to end up going away right after ::Start() returns,
1209
* then make sure to clean up the message queue.
1213
HMQ hmqCurrent = WinQueryQueueInfo( HMQ_CURRENT, &mqinfo,
1217
hab = WinInitialize( 0 );
1218
hmqCurrent = WinCreateMsgQueue( hab, 0 );
1221
// Search for existing message window.
1222
MessageWindow msgWindow;
1223
if ( msgWindow.getHWND() ) {
1224
// We are a client process. Pass request to message window.
1225
char *cmd = GetCommandLine();
1226
rv = msgWindow.SendRequest( cmd );
1228
// We will be server.
1229
if (!gAbortServer) {
1230
rv = msgWindow.Create();
1231
if ( NS_SUCCEEDED( rv ) ) {
1233
// Start up DDE server.
1236
// Tell caller to spin message loop.
1242
startupLock.Unlock();
1244
if( *aResult == PR_FALSE )
1246
/* This process isn't going to continue much longer. Make sure that we
1247
* clean up the message queue
1250
WinDestroyMsgQueue(hmqCurrent);
1259
nsNativeAppSupportOS2::InitTopicStrings() {
1260
for ( int i = 0; i < topicCount; i++ ) {
1261
if ( !( mTopics[ i ] = WinDdeCreateStringHandle( (PSZ)topicNames[ i ], CP_WINANSI ) ) ) {
1269
nsNativeAppSupportOS2::FindTopic( HSZ topic ) {
1270
for ( int i = 0; i < topicCount; i++ ) {
1271
if ( DdeCmpStringHandles( topic, mTopics[i] ) == 0 ) {
1278
// Start DDE server.
1280
// This used to be the Start() method when we were using DDE as the
1281
// primary IPC mechanism between secondary Mozilla processes and the
1282
// initial "server" process.
1284
// Now, it simply initializes the DDE server. The caller must check
1285
// that this process is to be the server, and, must acquire the DDE
1286
// startup mutex semaphore prior to calling this routine. See ::Start(),
1289
nsNativeAppSupportOS2::StartDDE() {
1290
NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED );
1292
/* Get entrypoints for PMDDEML */
1293
BOOL bDDEML = SetupOS2ddeml();
1295
/* If we couldn't initialize DDEML, set mUSEDDE to PR_FALSE */
1296
/* so we don't do anything else DDE related */
1303
NS_ENSURE_TRUE( DDEERR_NO_ERROR == WinDdeInitialize( &mInstance,
1304
nsNativeAppSupportOS2::HandleDDENotification,
1309
// Allocate DDE strings.
1310
NS_ENSURE_TRUE( ( mApplication = WinDdeCreateStringHandle( mAppName, CP_WINANSI ) ) && InitTopicStrings(),
1313
// Next step is to register a DDE service.
1314
NS_ENSURE_TRUE( WinDdeNameService( mInstance, mApplication, 0, DNS_REGISTER ), NS_ERROR_FAILURE );
1317
printf( "DDE server started\n" );
1323
// If no DDE conversations are pending, terminate DDE.
1325
nsNativeAppSupportOS2::Stop( PRBool *aResult ) {
1326
NS_ENSURE_ARG( aResult );
1327
NS_ENSURE_TRUE( mInstance, NS_ERROR_NOT_INITIALIZED );
1329
nsresult rv = NS_OK;
1336
Mutex ddeLock( mMutexName );
1338
if ( ddeLock.Lock( MOZ_DDE_STOP_TIMEOUT ) ) {
1339
if ( mConversations == 0 ) {
1342
*aResult = PR_FALSE;
1348
// No DDE application name specified, but that's OK. Just
1356
// Terminate DDE regardless.
1358
nsNativeAppSupportOS2::Quit() {
1359
// If another process wants to look for the message window, they need
1360
// to wait to hold the lock, in which case they will not find the
1361
// window as we will destroy ours under our lock.
1362
// When the mutex goes off the stack, it is unlocked via destructor.
1363
Mutex mutexLock(mMutexName);
1364
NS_ENSURE_TRUE(mutexLock.Lock(MOZ_DDE_START_TIMEOUT), NS_ERROR_FAILURE );
1366
// If we've got a message window to receive IPC or new window requests,
1367
// get rid of it as we are shutting down.
1368
// Note: Destroy calls DestroyWindow, which will only work on a window
1369
// created by the same thread.
1374
// Unregister application name.
1375
WinDdeNameService( mInstance, mApplication, 0, DNS_UNREGISTER );
1376
// Clean up strings.
1377
if ( mApplication ) {
1378
WinDdeFreeStringHandle( mApplication );
1381
for ( int i = 0; i < topicCount; i++ ) {
1383
WinDdeFreeStringHandle( mTopics[i] );
1387
WinDdeUninitialize( mInstance );
1396
return PR_FALSE; /* We do this so that we can bail if we are using custom turbo mode */
1400
// Macro to generate case statement for a given XTYP value.
1401
#define XTYP_CASE(t) \
1402
case t: result = #t; break
1404
static nsCString uTypeDesc( UINT uType ) {
1407
XTYP_CASE(XTYP_ADVSTART);
1408
XTYP_CASE(XTYP_CONNECT);
1409
XTYP_CASE(XTYP_ADVREQ);
1410
XTYP_CASE(XTYP_REQUEST);
1411
XTYP_CASE(XTYP_WILDCONNECT);
1412
XTYP_CASE(XTYP_ADVDATA);
1413
XTYP_CASE(XTYP_EXECUTE);
1414
XTYP_CASE(XTYP_POKE);
1415
XTYP_CASE(XTYP_ADVSTOP);
1416
XTYP_CASE(XTYP_CONNECT_CONFIRM);
1417
XTYP_CASE(XTYP_DISCONNECT);
1418
XTYP_CASE(XTYP_ERROR);
1419
XTYP_CASE(XTYP_MONITOR);
1420
XTYP_CASE(XTYP_REGISTER);
1421
XTYP_CASE(XTYP_XACT_COMPLETE);
1422
XTYP_CASE(XTYP_UNREGISTER);
1423
default: result = "XTYP_?????";
1428
static nsCString hszValue( DWORD instance, HSZ hsz ) {
1429
// Extract string from HSZ.
1430
nsCString result("[");
1431
DWORD len = WinDdeQueryString( hsz, NULL, NULL, CP_WINANSI );
1434
WinDdeQueryString( hsz, buffer, sizeof buffer, CP_WINANSI );
1441
// These are purely a safety measure to avoid the infamous "won't
1442
// build non-debug" type Tinderbox flames.
1443
static nsCString uTypeDesc( UINT ) {
1444
return nsCString( "?" );
1446
static nsCString hszValue( DWORD, HSZ ) {
1447
return nsCString( "?" );
1452
// Utility function to escape double-quotes within a string.
1453
static void escapeQuotes( nsAString &aString ) {
1454
PRInt32 offset = -1;
1457
offset = aString.FindChar( '"', ++offset );
1458
if ( offset == kNotFound ) {
1459
// No more quotes, exit.
1462
// Insert back-slash ahead of the '"'.
1463
aString.Insert( PRUnichar('\\'), offset );
1464
// Increment offset because we just inserted a slash
1472
nsNativeAppSupportOS2::HandleDDENotification( ULONG idInst, // DDEML instance
1473
USHORT uType, // transaction type
1474
USHORT uFmt, // clipboard data format
1475
HCONV hconv, // handle to the conversation
1476
HSZ hsz1, // handle to a string
1477
HSZ hsz2, // handle to a string
1478
HDDEDATA hdata, // handle to a global memory object
1479
ULONG dwData1, // transaction-specific data
1480
ULONG dwData2 ) { // transaction-specific data
1483
printf( "DDE: uType =%s\n", uTypeDesc( uType ).get() );
1484
printf( " uFmt =%u\n", (unsigned)uFmt );
1485
printf( " hconv =%08x\n", (int)hconv );
1486
printf( " hsz1 =%08x:%s\n", (int)hsz1, hszValue( mInstance, hsz1 ).get() );
1487
printf( " hsz2 =%08x:%s\n", (int)hsz2, hszValue( mInstance, hsz2 ).get() );
1488
printf( " hdata =%08x\n", (int)hdata );
1489
printf( " dwData1=%08x\n", (int)dwData1 );
1490
printf( " dwData2=%08x\n", (int)dwData2 );
1493
HDDEDATA result = 0;
1494
if ( uType & XCLASS_BOOL ) {
1497
// Make sure its for our service/topic.
1498
if ( FindTopic( hsz1 ) != -1 ) {
1499
// We support this connection.
1500
result = (HDDEDATA)1;
1503
case XTYP_CONNECT_CONFIRM:
1504
// We don't care about the conversation handle, at this point.
1505
result = (HDDEDATA)1;
1508
} else if ( uType & XCLASS_DATA ) {
1509
if ( uType == XTYP_REQUEST ) {
1510
switch ( FindTopic( hsz1 ) ) {
1511
case topicOpenURL: {
1512
// Open a given URL...
1514
// Default is to open in current window.
1515
PRBool new_window = PR_FALSE;
1517
// Get the URL from the first argument in the command.
1518
nsCAutoString url( ParseDDEArg( hsz2, 0 ) );
1520
// Read the 3rd argument in the command to determine if a
1521
// new window is to be used.
1522
nsCAutoString windowID( ParseDDEArg( hsz2, 2 ) );
1524
// "0" means to open the URL in a new window.
1525
if ( windowID.Equals( "0" ) ) {
1526
new_window = PR_TRUE;
1529
// Make it look like command line args.
1530
url.Insert( "mozilla -url ", 0 );
1532
printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() );
1535
HandleRequest( LPBYTE( url.get() ), new_window );
1536
// Return pseudo window ID.
1537
result = CreateDDEData( 1 );
1540
case topicGetWindowInfo: {
1541
// This topic has to get the current URL, get the current
1542
// page title and then format the output into the DDE
1543
// return string. The return value is "URL","Page Title",
1544
// "Window ID" however the window ID is not used for this
1545
// command, therefore it is returned as a null string
1547
// This isn't really a loop. We just use "break"
1548
// statements to bypass the remaining steps when
1549
// something goes wrong.
1551
// Get most recently used Nav window.
1552
nsCOMPtr<nsIDOMWindowInternal> navWin;
1553
GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(),
1554
getter_AddRefs( navWin ) );
1556
// There is not a window open
1559
// Get content window.
1560
nsCOMPtr<nsIDOMWindow> content;
1561
navWin->GetContent( getter_AddRefs( content ) );
1565
// Convert that to internal interface.
1566
nsCOMPtr<nsIDOMWindowInternal> internalContent( do_QueryInterface( content ) );
1567
if ( !internalContent ) {
1571
nsCOMPtr<nsIDOMLocation> location;
1572
internalContent->GetLocation( getter_AddRefs( location ) );
1576
// Get href for URL.
1578
if ( NS_FAILED( location->GetHref( url ) ) ) {
1581
// Escape any double-quotes.
1582
escapeQuotes( url );
1584
// Now for the title; first, get the "window" script global object.
1585
nsCOMPtr<nsIScriptGlobalObject> scrGlobalObj( do_QueryInterface( internalContent ) );
1586
if ( !scrGlobalObj ) {
1589
// Then from its doc shell get the base window...
1590
nsCOMPtr<nsIBaseWindow> baseWindow =
1591
do_QueryInterface( scrGlobalObj->GetDocShell() );
1592
if ( !baseWindow ) {
1595
// And from the base window we can get the title.
1596
nsXPIDLString title;
1600
baseWindow->GetTitle(getter_Copies(title));
1601
// Escape any double-quotes in the title.
1602
escapeQuotes( title );
1604
// Use a string buffer for the output data, first
1606
nsCAutoString outpt( NS_LITERAL_CSTRING("\"") );
1607
// Now copy the URL converting the Unicode string
1608
// to a single-byte ASCII string
1609
outpt.Append( NS_LossyConvertUCS2toASCII( url ) );
1610
// Add the "," used to separate the URL and the page
1612
outpt.Append( NS_LITERAL_CSTRING("\",\"") );
1613
// Now copy the current page title to the return string
1614
outpt.Append( NS_LossyConvertUCS2toASCII( title.get() ));
1615
// Fill out the return string with the remainin ",""
1616
outpt.Append( NS_LITERAL_CSTRING( "\",\"\"" ));
1618
// Create a DDE handle to a char string for the data
1619
// being returned, this copies and creates a "shared"
1620
// copy of the DDE response until the calling APP
1621
// reads it and says it can be freed.
1622
result = CreateDDEData( (LPBYTE)(const char*)outpt.get(),
1623
outpt.Length() + 1 );
1625
printf( "WWW_GetWindowInfo->%s\n", outpt.get() );
1627
} while ( PR_FALSE );
1630
case topicActivate: {
1631
// Activate a Nav window...
1632
nsCString windowID = ParseDDEArg( hsz2, 0 );
1634
// 4294967295 is decimal for 0xFFFFFFFF which is also a
1635
// correct value to do that Activate last window stuff
1636
if ( windowID.Equals( "-1" ) ||
1637
windowID.Equals( "4294967295" ) ) {
1638
// We only support activating the most recent window (or a new one).
1639
ActivateLastWindow();
1640
// Return pseudo window ID.
1641
result = CreateDDEData( 1 );
1645
case topicVersion: {
1646
// Return version. We're restarting at 1.0!
1647
DWORD version = 1 << 16; // "1.0"
1648
result = CreateDDEData( version );
1651
case topicRegisterViewer: {
1652
// Register new viewer (not implemented).
1653
result = CreateDDEData( PR_FALSE );
1656
case topicUnRegisterViewer: {
1657
// Unregister new viewer (not implemented).
1658
result = CreateDDEData( PR_FALSE );
1664
} else if ( uType & XTYP_POKE ) {
1665
switch ( FindTopic( hsz1 ) ) {
1666
case topicCancelProgress: {
1667
// "Handle" progress cancel (actually, pretty much ignored).
1668
result = (HDDEDATA)DDE_FACK;
1675
} else if ( uType & XCLASS_FLAGS ) {
1676
if ( uType == XTYP_EXECUTE ) {
1677
// Prove that we received the request.
1679
LPBYTE request = (LPBYTE)WinDdeAccessData( hdata, &bytes );
1681
printf( "Handling dde request: [%s]...\n", (char*)request );
1683
// Default is to open in current window.
1684
PRBool new_window = PR_FALSE;
1686
// Get the URL from the first argument in the command.
1687
HSZ args = WinDdeCreateStringHandle( (PSZ)request, CP_WINANSI );
1688
nsCAutoString url( ParseDDEArg( args, 0 ) );
1690
// Read the 3rd argument in the command to determine if a
1691
// new window is to be used.
1692
nsCAutoString windowID( ParseDDEArg( args, 2 ) );
1694
// "0" means to open the URL in a new window.
1695
if ( windowID.Equals( "0" ) ) {
1696
new_window = PR_TRUE;
1699
// Make it look like command line args.
1700
url.Insert( "mozilla -url ", 0 );
1702
printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() );
1705
HandleRequest( LPBYTE( url.get() ), new_window );
1706
// Release the args string.
1707
WinDdeFreeStringHandle( args );
1708
// Release the data.
1709
// DdeUnaccessData( hdata );
1710
result = (HDDEDATA)DDE_FACK;
1712
result = (HDDEDATA)DDE_NOTPROCESSED;
1714
} else if ( uType & XCLASS_NOTIFICATION ) {
1717
printf( "DDE result=%d (0x%08X)\n", (int)result, (int)result );
1722
// Utility function to advance to end of quoted string.
1723
// p+offset must point to the comma preceding the arg on entry.
1724
// On return, p+result points to the closing '"' (or end of the string
1725
// if the closing '"' is missing) if the arg is quoted. If the arg
1726
// is not quoted, then p+result will point to the first character
1728
static PRInt32 advanceToEndOfQuotedArg( const char *p, PRInt32 offset, PRInt32 len ) {
1729
// Check whether the current arg is quoted.
1730
if ( p[++offset] == '"' ) {
1731
// Advance past the closing quote.
1732
while ( offset < len && p[++offset] != '"' ) {
1733
// If the current character is a backslash, then the
1734
// next character can't be a *real* '"', so skip it.
1735
if ( p[offset] == '\\' ) {
1743
// Utility to parse out argument from a DDE item string.
1744
nsCString nsNativeAppSupportOS2::ParseDDEArg( HSZ args, int index ) {
1746
DWORD argLen = WinDdeQueryString( args, NULL, NULL, CP_WINANSI );
1749
// Ensure result's buffer is sufficiently big.
1750
temp.SetLength( argLen + 1 );
1751
// Now get the string contents.
1752
WinDdeQueryString( args, temp.BeginWriting(), temp.Length(), CP_WINANSI );
1753
// Parse out the given arg.
1754
const char *p = temp.get();
1755
// offset points to the comma preceding the desired arg.
1756
PRInt32 offset = -1;
1757
// Skip commas till we get to the arg we want.
1759
// If this arg is quoted, then go to closing quote.
1760
offset = advanceToEndOfQuotedArg( p, offset, argLen );
1762
offset = temp.FindChar( ',', offset );
1763
if ( offset == kNotFound ) {
1764
// No more commas, give up.
1769
// The desired argument starts just past the preceding comma,
1770
// which offset points to, and extends until the following
1771
// comma (or the end of the string).
1773
// Since the argument might be enclosed in quotes, we need to
1774
// deal with that before searching for the terminating comma.
1775
// We advance offset so it ends up pointing to the start of
1776
// the argument we want.
1777
PRInt32 end = advanceToEndOfQuotedArg( p, offset++, argLen );
1778
// Find next comma (or end of string).
1779
end = temp.FindChar( ',', end );
1780
if ( end == kNotFound ) {
1781
// Arg is the rest of the string.
1785
result.Assign( p + offset, end - offset );
1790
void nsNativeAppSupportOS2::ActivateLastWindow() {
1791
nsCOMPtr<nsIDOMWindowInternal> navWin;
1792
GetMostRecentWindow( NS_LITERAL_STRING("navigator:browser").get(), getter_AddRefs( navWin ) );
1794
// Activate that window.
1795
activateWindow( navWin );
1797
// Need to create a Navigator window, then.
1798
OpenBrowserWindow( "about:blank" );
1802
HDDEDATA nsNativeAppSupportOS2::CreateDDEData( DWORD value ) {
1803
return CreateDDEData( (LPBYTE)&value, sizeof value );
1806
HDDEDATA nsNativeAppSupportOS2::CreateDDEData( LPBYTE value, DWORD len ) {
1807
HDDEDATA result = WinDdeCreateDataHandle( value,
1816
// Handle DDE request. The argument is the command line received by the
1817
// DDE client process. We convert that string to an nsICmdLineService
1818
// object via GetCmdLineArgs. Then, we look for certain well-known cmd
1819
// arguments. This replicates code elsewhere, to some extent,
1820
// unfortunately (if you can fix that, please do).
1822
nsNativeAppSupportOS2::HandleRequest( LPBYTE request, PRBool newWindow ) {
1824
// if initial hidden window is still being displayed, we need to ignore requests
1825
// because such requests might not function properly. See bug 147223 for details
1827
if (mInitialWindowActive) {
1831
// Parse command line.
1833
nsCOMPtr<nsICmdLineService> args;
1836
rv = GetCmdLineArgs( request, getter_AddRefs( args ) );
1837
if (NS_FAILED(rv)) return;
1839
nsCOMPtr<nsIAppShellService> appShell(do_GetService("@mozilla.org/appshell/appShellService;1", &rv));
1840
if (NS_FAILED(rv)) return;
1842
nsCOMPtr<nsINativeAppSupport> nativeApp;
1843
rv = appShell->GetNativeAppSupport(getter_AddRefs( nativeApp ));
1844
if (NS_FAILED(rv)) return;
1846
// first see if there is a url
1848
rv = args->GetURLToLoad(getter_Copies(arg));
1849
if (NS_SUCCEEDED(rv) && (const char*)arg ) {
1852
printf( "Launching browser on url [%s]...\n", (const char*)arg );
1854
if (NS_SUCCEEDED(nativeApp->EnsureProfile(args)))
1855
(void)OpenBrowserWindow( arg, newWindow );
1860
// ok, let's try the -chrome argument
1861
rv = args->GetCmdLineValue("-chrome", getter_Copies(arg));
1862
if (NS_SUCCEEDED(rv) && (const char*)arg ) {
1865
printf( "Launching chrome url [%s]...\n", (const char*)arg );
1867
if (NS_SUCCEEDED(nativeApp->EnsureProfile(args)))
1868
(void)OpenWindow( arg, "" );
1872
// try for the "-profilemanager" argument, in which case we want the
1873
// profile manager to appear, but only if there are no windows open
1875
rv = args->GetCmdLineValue( "-profilemanager", getter_Copies(arg));
1876
if ( NS_SUCCEEDED(rv) && (const char*)arg ) { // -profilemanager on command line
1877
nsCOMPtr<nsIDOMWindowInternal> window;
1878
GetMostRecentWindow(0, getter_AddRefs(window));
1879
if (!window) { // there are no open windows
1880
mForceProfileStartup = PR_TRUE;
1884
// try for the "-kill" argument, to shut down the server
1885
rv = args->GetCmdLineValue( "-kill", getter_Copies(arg));
1886
if ( NS_SUCCEEDED(rv) && (const char*)arg ) {
1887
// Turn off server mode.
1888
nsCOMPtr<nsIAppShellService> appShell =
1889
do_GetService( "@mozilla.org/appshell/appShellService;1", &rv);
1890
if (NS_FAILED(rv)) return;
1892
nsCOMPtr<nsINativeAppSupport> native;
1893
rv = appShell->GetNativeAppSupport( getter_AddRefs( native ));
1894
if (NS_SUCCEEDED(rv)) {
1895
native->SetIsServerMode( PR_FALSE );
1897
// close app if there are no more top-level windows.
1898
appShell->Quit(nsIAppShellService::eConsiderQuit);
1904
// Try standard startup's command-line handling logic from nsAppRunner.cpp...
1906
// Need profile before opening windows.
1907
rv = nativeApp->EnsureProfile(args);
1908
if (NS_FAILED(rv)) return;
1910
// This will tell us whether the command line processing opened a window.
1911
PRBool windowOpened = PR_FALSE;
1913
// If there are no command line arguments, then we want to open windows
1914
// based on startup prefs (which say to open navigator and/or mailnews
1915
// and/or composer), or, open just a Navigator window. We do the former
1916
// if there are no open windows (i.e., we're in turbo mode), the latter
1917
// if there are open windows. Note that we call DoCommandLines in the
1918
// case where there are no command line args but there are windows open
1919
// (i.e., with heedStartupPrefs==PR_FALSE) despite the fact that it may
1920
// not actually do anything in that case. That way we're covered if the
1921
// logic in DoCommandLines changes. Note that we cover this case below
1922
// by opening a navigator window if DoCommandLines doesn't open one. We
1923
// have to cover that case anyway, because DoCommandLines won't open a
1924
// window when given "mozilla -foobar" or the like.
1925
PRBool heedStartupPrefs = PR_FALSE;
1927
args->GetArgc( &argc );
1929
// Use startup prefs iff there are no windows currently open.
1930
nsCOMPtr<nsIDOMWindowInternal> win;
1931
GetMostRecentWindow( 0, getter_AddRefs( win ) );
1933
heedStartupPrefs = PR_TRUE;
1937
// Process command line options.
1938
rv = DoCommandLines( args, heedStartupPrefs, &windowOpened );
1940
// If a window was opened, then we're done.
1941
// Note that we keep on trying in the unlikely event of an error.
1942
if (rv == NS_ERROR_NOT_AVAILABLE || rv == NS_ERROR_ABORT || windowOpened) {
1946
// ok, no idea what the param is.
1948
printf( "Unknown request [%s]\n", (char*) request );
1950
// if all else fails, open a browser window
1951
const char * const contractID =
1952
"@mozilla.org/commandlinehandler/general-startup;1?type=browser";
1953
nsCOMPtr<nsICmdLineHandler> handler = do_GetService(contractID, &rv);
1954
if (NS_FAILED(rv)) return;
1956
nsXPIDLString defaultArgs;
1957
rv = handler->GetDefaultArgs(getter_Copies(defaultArgs));
1958
if (NS_FAILED(rv) || !defaultArgs) return;
1962
url.AssignWithConversion( defaultArgs );
1963
OpenBrowserWindow(url.get());
1965
OpenBrowserWindow("about:blank");
1969
// Parse command line args according to MS spec
1970
// (see "Parsing C++ Command-Line Arguments" at
1971
// http://msdn.microsoft.com/library/devprods/vs6/visualc/vclang/_pluslang_parsing_c.2b2b_.command.2d.line_arguments.htm).
1973
nsNativeAppSupportOS2::GetCmdLineArgs( LPBYTE request, nsICmdLineService **aResult ) {
1974
nsresult rv = NS_OK;
1976
int justCounting = 1;
1980
int between, quoted, bSlashCount;
1984
// We loop if we've not finished the second pass through.
1986
// Initialize if required.
1990
argc = quoted = bSlashCount = 0;
1995
// We are traversing whitespace between args.
1996
// Check for start of next arg.
1997
if ( *p != 0 && !isspace( *p ) ) {
1998
// Start of another arg.
2003
// Count the backslash.
2007
// Remember we're inside quotes.
2011
// Add character to arg.
2016
// Another space between args, ignore it.
2019
// We are processing the contents of an argument.
2020
// Check for whitespace or end.
2021
if ( *p == 0 || ( !quoted && isspace( *p ) ) ) {
2022
// Process pending backslashes (interpret them
2023
// literally since they're not followed by a ").
2024
while( bSlashCount ) {
2029
if ( !justCounting ) {
2030
argv[argc] = new char[ arg.Length() + 1 ];
2031
strcpy( argv[argc], arg.get() );
2034
// We're now between args.
2037
// Still inside argument, process the character.
2040
// First, digest preceding backslashes (if any).
2041
while ( bSlashCount > 1 ) {
2042
// Put one backsplash in arg for each pair.
2046
if ( bSlashCount ) {
2047
// Quote is literal.
2051
// Quote starts or ends a quoted section.
2053
// Check for special case of consecutive double
2054
// quotes inside a quoted section.
2055
if ( *(p+1) == '"' ) {
2056
// This implies a literal double-quote. Fake that
2057
// out by causing next double-quote to look as
2058
// if it was preceded by a backslash.
2073
// Accept any preceding backslashes literally.
2074
while ( bSlashCount ) {
2078
// Just add next char to the current arg.
2084
// Check for end of input.
2086
// Go to next character.
2089
// If on first pass, go on to second.
2090
if ( justCounting ) {
2091
// Allocate argv array.
2092
argv = new char*[ argc ];
2094
// Start second pass
2104
// OK, now create nsICmdLineService object from argc/argv.
2105
static NS_DEFINE_CID( kCmdLineServiceCID, NS_COMMANDLINE_SERVICE_CID );
2107
nsCOMPtr<nsIComponentManager> compMgr;
2108
NS_GetComponentManager(getter_AddRefs(compMgr));
2109
rv = compMgr->CreateInstance( kCmdLineServiceCID,
2111
NS_GET_IID( nsICmdLineService ),
2114
if ( NS_FAILED( rv ) || NS_FAILED( ( rv = (*aResult)->Initialize( argc, argv ) ) ) ) {
2116
printf( "Error creating command line service = 0x%08X (argc=%d, argv=0x%08X)\n", (int)rv, (int)argc, (void*)argv );
2122
delete [] argv[ --argc ];
2129
// Check to see if we have a profile. We will not have a profile
2130
// at this point if we were launched invisibly in -turbo mode, and
2131
// the profile mgr needed to show UI (to pick from multiple profiles).
2132
// At this point, we can show UI, so call DoProfileStartUp().
2134
nsNativeAppSupportOS2::EnsureProfile(nsICmdLineService* args)
2138
nsCOMPtr<nsIProfileInternal> profileMgr(do_GetService(NS_PROFILE_CONTRACTID, &rv));
2139
if (NS_FAILED(rv)) return rv;
2140
nsCOMPtr<nsIAppShellService> appShell(do_GetService("@mozilla.org/appshell/appShellService;1", &rv));
2141
if (NS_FAILED(rv)) return rv;
2143
// If we have a profile, everything is fine.
2144
// unless mForceProfileStartup is TRUE. This flag is set when the
2145
// last window is closed in -turbo mode. When TRUE, it forces the
2146
// profile UI to come up at the beginning of the next -turbo session
2147
// even if we currently have a profile.
2149
rv = profileMgr->IsCurrentProfileAvailable(&haveProfile);
2150
if (!mForceProfileStartup && NS_SUCCEEDED(rv) && haveProfile)
2153
// If the profile selection is happening, fail.
2154
PRBool doingProfileStartup;
2155
rv = profileMgr->GetIsStartingUp(&doingProfileStartup);
2156
if (NS_FAILED(rv) || doingProfileStartup) return NS_ERROR_FAILURE;
2158
// See if profile manager is being suppressed via -silent flag.
2159
PRBool canInteract = PR_TRUE;
2161
if (NS_SUCCEEDED(args->GetCmdLineValue("-silent", getter_Copies(arg)))) {
2162
if ((const char*)arg) {
2163
canInteract = PR_FALSE;
2166
rv = appShell->DoProfileStartup(args, canInteract);
2168
mForceProfileStartup = PR_FALSE;
2174
nsNativeAppSupportOS2::OpenWindow( const char*urlstr, const char *args ) {
2176
nsresult rv = NS_ERROR_FAILURE;
2178
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2179
nsCOMPtr<nsISupportsCString> sarg(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
2181
sarg->SetData(nsDependentCString(args));
2183
if (wwatch && sarg) {
2184
nsCOMPtr<nsIDOMWindow> newWindow;
2185
rv = wwatch->OpenWindow(0, urlstr, "_blank", "chrome,dialog=no,all",
2186
sarg, getter_AddRefs(newWindow));
2189
printf("Get WindowWatcher (or create string) failed\n");
2195
HWND hwndForDOMWindow( nsISupports *window ) {
2196
nsCOMPtr<nsIScriptGlobalObject> ppScriptGlobalObj( do_QueryInterface(window) );
2197
if ( !ppScriptGlobalObj ) {
2201
nsCOMPtr<nsIBaseWindow> ppBaseWindow =
2202
do_QueryInterface( ppScriptGlobalObj->GetDocShell() );
2203
if ( !ppBaseWindow ) {
2207
nsCOMPtr<nsIWidget> ppWidget;
2208
ppBaseWindow->GetMainWidget( getter_AddRefs( ppWidget ) );
2210
return (HWND)( ppWidget->GetNativeData( NS_NATIVE_WIDGET ) );
2214
nsNativeAppSupportOS2::ReParent( nsISupports *window, HWND newParent ) {
2215
HWND hMainClient = hwndForDOMWindow( window );
2216
if ( !hMainClient ) {
2217
return NS_ERROR_FAILURE;
2219
HWND hMainFrame = WinQueryWindow(hMainClient, QW_PARENT);
2221
// Reset the parent.
2222
WinSetParent( hMainFrame, newParent, FALSE );
2227
static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
2229
class SafeJSContext {
2235
JSContext *get() { return mContext; }
2238
nsCOMPtr<nsIThreadJSContextStack> mService;
2239
JSContext *mContext;
2242
SafeJSContext::SafeJSContext() : mContext(nsnull) {
2245
SafeJSContext::~SafeJSContext() {
2250
rv = mService->Pop(&cx);
2251
NS_ASSERTION(NS_SUCCEEDED(rv) && cx == mContext, "JSContext push/pop mismatch");
2255
nsresult SafeJSContext::Push() {
2258
if (mContext) // only once
2259
return NS_ERROR_FAILURE;
2261
mService = do_GetService(sJSStackContractID);
2263
rv = mService->GetSafeJSContext(&mContext);
2264
if (NS_SUCCEEDED(rv) && mContext) {
2265
rv = mService->Push(mContext);
2270
return mContext ? NS_OK : NS_ERROR_FAILURE;
2275
nsNativeAppSupportOS2::OpenBrowserWindow( const char *args, PRBool newWindow ) {
2276
nsresult rv = NS_OK;
2277
// Open the argument URL in the most recently used Navigator window.
2278
// If there is no Nav window, open a new one.
2280
// Get most recently used Nav window.
2281
nsCOMPtr<nsIDOMWindowInternal> navWin;
2282
GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(), getter_AddRefs( navWin ) );
2284
// This isn't really a loop. We just use "break" statements to fall
2285
// out to the OpenWindow call when things go awry.
2287
// If caller requires a new window, then don't use an existing one.
2292
// Have to open a new one.
2295
// Get content window.
2296
nsCOMPtr<nsIDOMWindow> content;
2297
navWin->GetContent( getter_AddRefs( content ) );
2301
// Convert that to internal interface.
2302
nsCOMPtr<nsIDOMWindowInternal> internalContent( do_QueryInterface( content ) );
2303
if ( !internalContent ) {
2307
nsCOMPtr<nsIDOMLocation> location;
2308
internalContent->GetLocation( getter_AddRefs( location ) );
2312
// Set up environment.
2313
SafeJSContext context;
2314
if ( NS_FAILED( context.Push() ) ) {
2318
nsAutoString url; url.AssignWithConversion( args );
2319
if ( NS_FAILED( location->SetHref( url ) ) ) {
2322
// Finally, if we get here, we're done.
2324
} while ( PR_FALSE );
2326
nsCOMPtr<nsICmdLineHandler> handler(do_GetService("@mozilla.org/commandlinehandler/general-startup;1?type=browser", &rv));
2327
if (NS_FAILED(rv)) return rv;
2329
nsXPIDLCString chromeUrlForTask;
2330
rv = handler->GetChromeUrlForTask(getter_Copies(chromeUrlForTask));
2331
if (NS_FAILED(rv)) return rv;
2333
// Last resort is to open a brand new window.
2334
return OpenWindow( chromeUrlForTask, args );
2337
// This opens a special browser window for purposes of priming the pump for
2338
// server mode (getting stuff into the caching, loading .dlls, etc.). The
2339
// window will have these attributes:
2340
// - Load about:blank (no home page)
2341
// - No toolbar (so there's no sidebar panels loaded, either)
2342
// - Pass magic arg to cause window to close in onload handler.
2344
nsNativeAppSupportOS2::StartServerMode() {
2346
if (mShouldShowUI) {
2347
// We dont have to anything anymore. The native UI
2348
// will create the window
2351
// Sometimes a window will have been opened even though mShouldShowUI is false
2352
// (e.g., mozilla -mail -turbo). Detect that by testing whether there's a
2353
// window already open.
2354
nsCOMPtr<nsIDOMWindowInternal> win;
2355
GetMostRecentWindow( 0, getter_AddRefs( win ) );
2357
// Window already opened, don't need this special Nav window.
2362
// Since native UI wont create any window, we create a hidden window
2363
// so thing work alright.
2365
// Create some of the objects we'll need.
2366
nsCOMPtr<nsIWindowWatcher> ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2367
nsCOMPtr<nsISupportsString> arg1(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
2368
nsCOMPtr<nsISupportsString> arg2(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
2369
if ( !ww || !arg1 || !arg2 ) {
2373
// Create the array for the arguments.
2374
nsCOMPtr<nsISupportsArray> argArray = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
2379
// arg1 is the url to load.
2380
// arg2 is the string that tells navigator.js to auto-close.
2381
arg1->SetData( NS_LITERAL_STRING( "about:blank" ) );
2382
arg2->SetData( NS_LITERAL_STRING( "turbo=yes" ) );
2384
// Put args into array.
2385
if ( NS_FAILED( argArray->AppendElement( arg1 ) ) ||
2386
NS_FAILED( argArray->AppendElement( arg2 ) ) ) {
2390
// Now open the window.
2391
nsCOMPtr<nsIDOMWindow> newWindow;
2393
"chrome://navigator/content",
2395
"chrome,dialog=no,toolbar=no",
2397
getter_AddRefs( newWindow ) );
2402
mInitialWindowActive = PR_TRUE;
2404
// Hide this window by re-parenting it (to ensure it doesn't appear).
2405
ReParent( newWindow, MessageWindow().getHWND() );
2411
nsNativeAppSupportOS2::SetIsServerMode( PRBool isServerMode ) {
2412
return nsNativeAppSupportBase::SetIsServerMode( isServerMode );
2416
nsNativeAppSupportOS2::OnLastWindowClosing() {
2421
// If the last window closed is our special "turbo" window made
2422
// in StartServerMode(), don't do anything.
2423
if ( mInitialWindowActive ) {
2424
mInitialWindowActive = PR_FALSE;
2430
// If activated by the browser.turbo.singleProfileOnly pref,
2431
// check for multi-profile situation and turn off turbo mode
2432
// if there are multiple profiles.
2433
PRBool singleProfileOnly = PR_FALSE;
2434
nsCOMPtr<nsIPref> prefService( do_GetService( NS_PREF_CONTRACTID, &rv ) );
2435
if ( NS_SUCCEEDED( rv ) ) {
2436
prefService->GetBoolPref( "browser.turbo.singleProfileOnly", &singleProfileOnly );
2438
if ( singleProfileOnly ) {
2439
nsCOMPtr<nsIProfile> profileMgr( do_GetService( NS_PROFILE_CONTRACTID, &rv ) );
2440
if ( NS_SUCCEEDED( rv ) ) {
2441
PRInt32 profileCount = 0;
2442
if ( NS_SUCCEEDED( profileMgr->GetProfileCount( &profileCount ) ) &&
2443
profileCount > 1 ) {
2444
// Turn off turbo mode and quit the application.
2445
SetIsServerMode( PR_FALSE );
2446
nsCOMPtr<nsIAppShellService> appShell =
2447
do_GetService( "@mozilla.org/appshell/appShellService;1", &rv);
2448
if ( NS_SUCCEEDED( rv ) ) {
2449
appShell->Quit(nsIAppShellService::eAttemptQuit);
2456
nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1", &rv));
2457
if (NS_FAILED(rv)) return rv;
2458
observerService->NotifyObservers(nsnull, "session-logout", nsnull);
2460
mForceProfileStartup = PR_TRUE;