~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/xpfe/bootstrap/nsNativeAppSupportOS2.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 
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/
 
7
 *
 
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.
 
12
 *
 
13
 * The Original Code is Mozilla Communicator client code.
 
14
 *
 
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
 
18
 * Rights Reserved.
 
19
 *
 
20
 * Contributor(s): 
 
21
 *   Bill Law       law@netscape.com
 
22
 *   IBM Corp.
 
23
 */
 
24
 
 
25
#define INCL_PM
 
26
#define INCL_GPI
 
27
#define INCL_DOS
 
28
#define INCL_DOSERRORS
 
29
#include <os2.h>
 
30
 
 
31
#include "nsNativeAppSupportBase.h"
 
32
#include "nsNativeAppSupportOS2.h"
 
33
#include "nsString.h"
 
34
#include "nsICmdLineService.h"
 
35
#include "nsCOMPtr.h"
 
36
#include "nsXPIDLString.h"
 
37
#include "nsIComponentManager.h"
 
38
#include "nsIServiceManager.h"
 
39
#include "nsICmdLineHandler.h"
 
40
#include "nsIDOMWindow.h"
 
41
#include "nsXPCOM.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"
 
55
#include "nsIPref.h"
 
56
#include "nsIPromptService.h"
 
57
#include "nsNetCID.h"
 
58
#include "nsIObserverService.h"
 
59
#include "nsXPCOM.h"
 
60
#include "nsPaletteOS2.h"
 
61
 
 
62
// These are needed to load a URL in a browser window.
 
63
#include "nsIDOMLocation.h"
 
64
#include "nsIJSContextStack.h"
 
65
#include "nsIWindowMediator.h"
 
66
 
 
67
 
 
68
#include <sys/stat.h>
 
69
#include <stdlib.h>
 
70
 
 
71
#include "prprf.h"
 
72
 
 
73
 
 
74
// getting from nsAppRunner.  Use to help track down arguments.
 
75
extern char ** __argv;
 
76
extern int    __argc;
 
77
 
 
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
 
80
 * structure
 
81
 */
 
82
typedef struct _COPYDATASTRUCT
 
83
{
 
84
   ULONG   dwData;
 
85
   ULONG   cbData;
 
86
   PVOID   lpData;
 
87
   CHAR    chBuff;
 
88
}COPYDATASTRUCT, *PCOPYDATASTRUCT;
 
89
#define WM_COPYDATA             (WM_USER + 60)
 
90
 
 
91
char szCommandLine[2*CCHMAXPATH];
 
92
 
 
93
static HWND hwndForDOMWindow( nsISupports * );
 
94
 
 
95
static
 
96
nsresult
 
97
GetMostRecentWindow(const PRUnichar* aType, nsIDOMWindowInternal** aWindow) {
 
98
    nsresult rv;
 
99
    nsCOMPtr<nsIWindowMediator> med( do_GetService( NS_WINDOWMEDIATOR_CONTRACTID, &rv ) );
 
100
    if ( NS_FAILED( rv ) )
 
101
        return rv;
 
102
 
 
103
    if ( med )
 
104
        return med->GetMostRecentWindow( aType, aWindow );
 
105
 
 
106
    return NS_ERROR_FAILURE;
 
107
}
 
108
 
 
109
static
 
110
void
 
111
activateWindow( nsIDOMWindowInternal *win ) {
 
112
    // Try to get native window handle.
 
113
    HWND hwnd = hwndForDOMWindow( win );
 
114
    if ( hwnd ) {
 
115
 
 
116
        /* if we are looking at a client window, then we really probably want
 
117
         * the frame so that we can manipulate THAT
 
118
         */
 
119
        LONG id = WinQueryWindowUShort( hwnd, QWS_ID );
 
120
        if( id == FID_CLIENT )
 
121
        {
 
122
           hwnd = WinQueryWindow( hwnd, QW_PARENT );
 
123
        }
 
124
 
 
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 );
 
129
    } else {
 
130
        // Use internal method.
 
131
        win->Focus();
 
132
    }
 
133
}
 
134
 
 
135
 
 
136
 
 
137
// Define this macro to 1 to get DDE debugging output.
 
138
#define MOZ_DEBUG_DDE 0
 
139
 
 
140
#ifdef DEBUG_law
 
141
#undef MOZ_DEBUG_DDE
 
142
#define MOZ_DEBUG_DDE 1
 
143
#endif
 
144
 
 
145
class nsSplashScreenOS2 : public nsISplashScreen {
 
146
public:
 
147
    nsSplashScreenOS2();
 
148
    ~nsSplashScreenOS2();
 
149
 
 
150
    NS_IMETHOD Show();
 
151
    NS_IMETHOD Hide();
 
152
 
 
153
    // nsISupports methods
 
154
    NS_IMETHOD_(nsrefcnt) AddRef() {
 
155
        mRefCnt++;
 
156
        return mRefCnt;
 
157
    }
 
158
    NS_IMETHOD_(nsrefcnt) Release() {
 
159
        --mRefCnt;
 
160
        if ( !mRefCnt ) {
 
161
            delete this;
 
162
            return 0;
 
163
        }
 
164
        return mRefCnt;
 
165
    }
 
166
    NS_IMETHOD QueryInterface( const nsIID &iid, void**p ) {
 
167
        nsresult rv = NS_OK;
 
168
        if ( p ) {
 
169
            *p = 0;
 
170
            if ( iid.Equals( NS_GET_IID( nsISplashScreen ) ) ) {
 
171
                nsISplashScreen *result = this;
 
172
                *p = result;
 
173
                NS_ADDREF( result );
 
174
            } else if ( iid.Equals( NS_GET_IID( nsISupports ) ) ) {
 
175
                nsISupports *result = NS_STATIC_CAST( nsISupports*, this );
 
176
                *p = result;
 
177
                NS_ADDREF( result );
 
178
            } else {
 
179
                rv = NS_NOINTERFACE;
 
180
            }
 
181
        } else {
 
182
            rv = NS_ERROR_NULL_POINTER;
 
183
        }
 
184
        return rv;
 
185
    }
 
186
 
 
187
    void SetDialog( HWND dlg );
 
188
    void LoadBitmap();
 
189
    static nsSplashScreenOS2* GetPointer( HWND dlg );
 
190
 
 
191
    HWND mDlg;
 
192
    HBITMAP mBitmap;
 
193
    nsrefcnt mRefCnt;
 
194
    HDC hdcMemory;
 
195
    HPS hpsMemory;
 
196
    LONG mBitmapCX;
 
197
    LONG mBitmapCY;
 
198
}; // class nsSplashScreenOS2
 
199
 
 
200
MRESULT EXPENTRY DialogProc( HWND dlg, ULONG msg, MPARAM mp1, MPARAM mp2 );
 
201
void ThreadProc (void *splashScreen);
 
202
 
 
203
// Simple Win32 mutex wrapper.
 
204
struct Mutex {
 
205
    Mutex( const char *name )
 
206
        : mName( name ),
 
207
          mHandle( 0 ),
 
208
          mState( -1 ) {
 
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 );
 
212
#if MOZ_DEBUG_DDE
 
213
        if ( rc != NO_ERROR ) {
 
214
            printf( "CreateMutex error = 0x%08X\n", rc );
 
215
        }
 
216
#endif
 
217
    }
 
218
    ~Mutex() {
 
219
        if ( mHandle ) {
 
220
            // Make sure we release it if we own it.
 
221
            Unlock();
 
222
 
 
223
            APIRET rc = DosCloseMutexSem( mHandle );
 
224
#if MOZ_DEBUG_DDE
 
225
            if ( rc != NO_ERROR ) {
 
226
                printf( "CloseHandle error = 0x%08X\n", rc );
 
227
            }
 
228
#endif
 
229
        }
 
230
    }
 
231
    BOOL Lock( DWORD timeout ) {
 
232
        if ( mHandle ) {
 
233
#if MOZ_DEBUG_DDE
 
234
            printf( "Waiting (%d msec) for DDE mutex...\n", (int)timeout );
 
235
#endif
 
236
            mState = DosRequestMutexSem( mHandle, timeout );
 
237
#if MOZ_DEBUG_DDE
 
238
            printf( "...wait complete, result = 0x%08X\n", (int)mState );
 
239
#endif
 
240
            return mState == NO_ERROR;
 
241
        } else {
 
242
            return FALSE;
 
243
        }
 
244
    }
 
245
    void Unlock() {
 
246
        if ( mHandle && mState == NO_ERROR ) {
 
247
#if MOZ_DEBUG_DDE
 
248
            printf( "Releasing DDE mutex\n" );
 
249
#endif
 
250
            DosReleaseMutexSem( mHandle );
 
251
            mState = -1;
 
252
        }
 
253
    }
 
254
private:
 
255
    nsCString mName;
 
256
    HMTX      mHandle;
 
257
    DWORD     mState;
 
258
};
 
259
 
 
260
/* DDE Notes
 
261
 *
 
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.
 
266
 *
 
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.
 
271
 *
 
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.
 
278
 *
 
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).
 
284
 *
 
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.
 
290
 * 
 
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.
 
294
 *
 
295
 * There are a couple of subtleties that one should be aware of:
 
296
 * 
 
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.
 
306
 *
 
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).
 
309
 * 
 
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).
 
323
 */
 
324
 
 
325
/* Update 2001 March
 
326
 *
 
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).
 
330
 *
 
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().
 
336
 *
 
337
 * We still use the mutex semaphore to protect the code that detects
 
338
 * whether Mozilla is already running.
 
339
 */
 
340
 
 
341
class nsNativeAppSupportOS2 : public nsNativeAppSupportBase
 
342
{
 
343
public:
 
344
    // Overrides of base implementation.
 
345
    NS_IMETHOD Start( PRBool *aResult );
 
346
    NS_IMETHOD Stop( PRBool *aResult );
 
347
    NS_IMETHOD Quit();
 
348
    NS_IMETHOD StartServerMode();
 
349
    NS_IMETHOD OnLastWindowClosing();
 
350
    NS_IMETHOD SetIsServerMode( PRBool isServerMode );
 
351
    NS_IMETHOD EnsureProfile(nsICmdLineService* args);
 
352
 
 
353
    // The "old" Start method (renamed).
 
354
    NS_IMETHOD StartDDE();
 
355
 
 
356
    // Utility function to handle a Win32-specific command line
 
357
    // option: "-console", which dynamically creates a Windows
 
358
    // console.
 
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();
 
362
 
 
363
private:
 
364
    static HDDEDATA APIENTRY HandleDDENotification( ULONG    idInst,
 
365
                                                    USHORT   uType,
 
366
                                                    USHORT   uFmt,
 
367
                                                    HCONV    hconv,
 
368
                                                    HSZ      hsz1,
 
369
                                                    HSZ      hsz2,
 
370
                                                    HDDEDATA hdata,
 
371
                                                    ULONG    dwData1,
 
372
                                                    ULONG    dwData2 );
 
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);
 
385
 
 
386
 
 
387
    static int   mConversations;
 
388
    enum {
 
389
        topicOpenURL,
 
390
        topicActivate,
 
391
        topicCancelProgress,
 
392
        topicVersion,
 
393
        topicRegisterViewer,
 
394
        topicUnRegisterViewer,
 
395
        topicGetWindowInfo,
 
396
        // Note: Insert new values above this line!!!!!
 
397
        topicCount // Count of the number of real topics
 
398
    };
 
399
 
 
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
 
409
 
 
410
nsSplashScreenOS2::nsSplashScreenOS2()
 
411
    : mDlg( 0 ), mBitmap( 0 ), mRefCnt( 0 ),
 
412
      hdcMemory( 0 ), hpsMemory( 0 ), mBitmapCX(0), mBitmapCY(0) {
 
413
}
 
414
 
 
415
nsSplashScreenOS2::~nsSplashScreenOS2() {
 
416
#if MOZ_DEBUG_DDE
 
417
    printf( "splash screen dtor called\n" );
 
418
#endif
 
419
    // Make sure dialog is gone.
 
420
    Hide();
 
421
}
 
422
 
 
423
NS_IMETHODIMP
 
424
nsSplashScreenOS2::Show() {
 
425
    //Spawn new thread to display real splash screen.
 
426
    int handle = _beginthread( ThreadProc, NULL, 16384, (void *)this );
 
427
    return NS_OK;
 
428
}
 
429
 
 
430
NS_IMETHODIMP
 
431
nsSplashScreenOS2::Hide() {
 
432
    if ( mDlg ) {
 
433
        // Dismiss the dialog.
 
434
        WinPostMsg(mDlg, WM_CLOSE, 0, 0);
 
435
        mDlg = 0;
 
436
        GpiSetBitmap(hpsMemory, NULLHANDLE);
 
437
        if (mBitmap) {
 
438
            GpiDeleteBitmap(mBitmap);
 
439
            mBitmap = 0;
 
440
        }
 
441
        if (hdcMemory) {
 
442
            DevCloseDC(hdcMemory);
 
443
            hdcMemory = 0;
 
444
        }
 
445
        if (hpsMemory) {
 
446
           GpiDestroyPS(hpsMemory);
 
447
           hpsMemory = 0;
 
448
        }
 
449
    }
 
450
    return NS_OK;
 
451
}
 
452
 
 
453
HBITMAP LoadAndSetBitmapFromFile(HPS hps, PSZ pszFilename)
 
454
{
 
455
   FILE *fp = fopen(pszFilename, "rb");
 
456
   if (fp == NULL) {
 
457
      return NULLHANDLE;
 
458
   }
 
459
   fseek(fp, 0, SEEK_END );
 
460
   ULONG cbFile = ftell(fp);
 
461
   if (cbFile ==0) {
 
462
      fclose(fp);
 
463
      return NULLHANDLE;
 
464
   }
 
465
   fseek(fp, 0, SEEK_SET );
 
466
   PBYTE pBitmapData = (PBYTE)malloc(cbFile);
 
467
   fread((PVOID)pBitmapData, cbFile, 1, fp);
 
468
   fclose(fp);
 
469
 
 
470
   PBITMAPFILEHEADER2 pbfh2 = (PBITMAPFILEHEADER2)pBitmapData;
 
471
   PBITMAPINFOHEADER2 pbmp2 = NULL;
 
472
 
 
473
   switch (pbfh2->usType)
 
474
   {
 
475
      case BFT_BITMAPARRAY:
 
476
         /*
 
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.
 
480
          */
 
481
         pbfh2 = &(((PBITMAPARRAYFILEHEADER2) pBitmapData)->bfh2);
 
482
         pbmp2 = &pbfh2->bmp2;
 
483
         break;
 
484
      case BFT_BMAP:
 
485
         pbmp2 = &pbfh2->bmp2;
 
486
         break;
 
487
      case BFT_ICON:
 
488
      case BFT_POINTER:
 
489
      case BFT_COLORICON:
 
490
      case BFT_COLORPOINTER:
 
491
      default:
 
492
         break;
 
493
   }
 
494
    
 
495
   if (pbmp2 == NULL) {
 
496
      free(pBitmapData);
 
497
      return NULLHANDLE;
 
498
   }
 
499
 
 
500
   LONG lScans;
 
501
   if (pbmp2->cbFix == sizeof(BITMAPINFOHEADER))
 
502
      lScans = (LONG) ((PBITMAPINFOHEADER)pbmp2)->cy;
 
503
   else
 
504
      lScans = pbmp2->cy;
 
505
 
 
506
   HBITMAP hbmp = GpiCreateBitmap(hps, pbmp2, 0L, NULL, NULL);
 
507
   if (!hbmp) {
 
508
      free(pBitmapData);
 
509
      return NULLHANDLE;
 
510
   }
 
511
 
 
512
   if (GpiSetBitmap(hps, hbmp) == HBM_ERROR) {
 
513
      GpiDeleteBitmap(hbmp);
 
514
      free(pBitmapData);
 
515
      return NULLHANDLE;
 
516
   }
 
517
 
 
518
   LONG lScansSet = GpiSetBitmapBits(hps, 0L, lScans, pBitmapData + pbfh2->offBits,
 
519
                                     (PBITMAPINFO2) pbmp2);
 
520
   free(pBitmapData);
 
521
 
 
522
   if (lScansSet != lScans) {
 
523
      GpiSetBitmap(hps, NULLHANDLE);
 
524
      GpiDeleteBitmap(hbmp);
 
525
      return NULLHANDLE;
 
526
   }
 
527
 
 
528
   return hbmp;
 
529
}
 
530
 
 
531
void
 
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 );
 
537
 
 
538
    // Check for '<program-name>.bmp" in same directory as executable.
 
539
    PPIB ppib;
 
540
    PTIB ptib;
 
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);
 
550
    }
 
551
    if (!mBitmap) {
 
552
        mBitmap = GpiLoadBitmap(hpsMemory, NULL, IDB_SPLASH, 0L, 0L);
 
553
        GpiSetBitmap(hpsMemory, mBitmap);
 
554
    }
 
555
    BITMAPINFOHEADER bitmap;
 
556
    bitmap.cbFix = sizeof(BITMAPINFOHEADER);
 
557
    GpiQueryBitmapParameters(mBitmap, &bitmap);
 
558
    mBitmapCX = bitmap.cx;
 
559
    mBitmapCY = bitmap.cy;
 
560
}
 
561
 
 
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;
 
566
        if ( mp2 ) {
 
567
            splashScreen->SetDialog( dlg );
 
568
 
 
569
            // Try to load customized bitmap.
 
570
            splashScreen->LoadBitmap();
 
571
        }
 
572
 
 
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.
 
576
         */ 
 
577
        HBITMAP hbitmap = splashScreen->mBitmap;
 
578
        if ( hbitmap ) {
 
579
            WinSetWindowPos( dlg,
 
580
                             HWND_TOP,
 
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 );
 
587
        }
 
588
        return (MRESULT)FALSE;
 
589
    }
 
590
    else if ( msg == WM_PAINT ) {
 
591
        nsSplashScreenOS2 *splashScreen = (nsSplashScreenOS2*)WinQueryWindowPtr( dlg, QWL_USER );
 
592
        HPS hps = WinBeginPaint (dlg, NULLHANDLE, NULL);
 
593
#if 0
 
594
        nsPaletteOS2::SelectGlobalPalette(hps, dlg);
 
595
#endif
 
596
        GpiErase (hps);
 
597
        POINTL aptl[8] = {0, 0, splashScreen->mBitmapCX, splashScreen->mBitmapCY,
 
598
                          0, 0, 0, 0,
 
599
                          0, 0, 0, 0,
 
600
                          0, 0, 0, 0};
 
601
 
 
602
        GpiBitBlt( hps, splashScreen->hpsMemory, 3L, aptl, ROP_SRCCOPY, 0L );
 
603
        WinEndPaint( hps );
 
604
        return (MRESULT)TRUE;
 
605
    }
 
606
#if 0
 
607
    else if ( msg == WM_REALIZEPALETTE ) {
 
608
        HPS hps = WinGetPS(dlg);
 
609
        nsPaletteOS2::SelectGlobalPalette(hps, dlg);
 
610
        WinReleasePS(hps);
 
611
        WinInvalidateRect( dlg, 0, TRUE);
 
612
        return (MRESULT)TRUE;
 
613
    }
 
614
#endif
 
615
    return WinDefDlgProc (dlg, msg, mp1, mp2);
 
616
}
 
617
 
 
618
void nsSplashScreenOS2::SetDialog( HWND dlg ) {
 
619
    // Save dialog handle.
 
620
    mDlg = dlg;
 
621
    // Store this pointer in the dialog.
 
622
    WinSetWindowPtr( mDlg, QWL_USER, this );
 
623
}
 
624
 
 
625
nsSplashScreenOS2 *nsSplashScreenOS2::GetPointer( HWND dlg ) {
 
626
    // Get result from dialog user data.
 
627
    PVOID data = WinQueryWindowPtr( dlg, QWL_USER );
 
628
    return (nsSplashScreenOS2*)data;
 
629
}
 
630
 
 
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 );
 
636
    WinTerminate( hab );
 
637
//    _endthread();
 
638
}
 
639
 
 
640
#define TURBOD "mozturbo.exe"
 
641
 
 
642
PRBool gAbortServer = PR_FALSE;
 
643
 
 
644
PRBool
 
645
nsNativeAppSupportOS2::CheckConsole() {
 
646
    CHAR pszAppPath[CCHMAXPATH];
 
647
    PPIB ppib;
 
648
    PTIB ptib;
 
649
    DosGetInfoBlocks(&ptib, &ppib);
 
650
    DosQueryModuleName(ppib->pib_hmte, CCHMAXPATH, pszAppPath);
 
651
    *strrchr(pszAppPath, '\\') = '\0'; // XXX DBCS misery
 
652
 
 
653
    for ( int i = 1; i < __argc; i++ ) {
 
654
        if ( strcmp( "-console", __argv[i] ) == 0
 
655
             ||
 
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
 
659
                    ||
 
660
                    strcmp( "/turbo", __argv[i] ) == 0
 
661
                    ||
 
662
                    strcmp( "-server", __argv[i] ) == 0                                              
 
663
                    ||
 
664
                    strcmp( "/server", __argv[i] ) == 0 ) {         
 
665
 
 
666
            struct stat st;
 
667
            CHAR pszTurboPath[CCHMAXPATH];
 
668
 
 
669
            strcpy(pszTurboPath, pszAppPath);
 
670
            strcat(pszTurboPath, "\\");
 
671
            strcat(pszTurboPath, TURBOD);
 
672
            int statrv = stat(pszTurboPath, &st);
 
673
 
 
674
            /* If we can't find the turbo EXE, use the Mozilla turbo */
 
675
            if (statrv == 0) {
 
676
              RESULTCODES rcodes;
 
677
              CHAR pszArgString[CCHMAXPATH];
 
678
 
 
679
              strcpy(pszArgString, pszTurboPath);
 
680
              strcat(pszArgString, " -l -p ");
 
681
              strcat(pszArgString, pszAppPath);
 
682
              pszArgString[strlen(pszTurboPath)] = '\0';
 
683
       
 
684
              DosExecPgm(NULL,0,EXEC_BACKGROUND,
 
685
                         pszArgString,
 
686
                         0, &rcodes,
 
687
                         pszTurboPath);
 
688
              return PR_FALSE; /* Don't start the app */
 
689
            } else {
 
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.
 
695
            }
 
696
        }
 
697
    }
 
698
 
 
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) {
 
702
 
 
703
            struct stat st;
 
704
            CHAR pszTurboPath[CCHMAXPATH];
 
705
 
 
706
            strcpy(pszTurboPath, pszAppPath);
 
707
            strcat(pszTurboPath, "\\");
 
708
            strcat(pszTurboPath, TURBOD);
 
709
            int statrv = stat(pszTurboPath, &st);
 
710
 
 
711
            /* If we can't find the turbo EXE, use the Mozilla turbo */
 
712
            if (statrv == 0) {
 
713
              RESULTCODES rcodes;
 
714
              CHAR pszArgString[CCHMAXPATH];
 
715
 
 
716
              strcpy(pszArgString, pszTurboPath);
 
717
              strcat(pszArgString, " -u");
 
718
              pszArgString[strlen(pszTurboPath)] = '\0';
 
719
             
 
720
              DosExecPgm(NULL,0,EXEC_BACKGROUND,
 
721
                         pszArgString,
 
722
                         0, &rcodes,
 
723
                         pszTurboPath);
 
724
              return PR_FALSE; /* Don't start the app */
 
725
            } else {
 
726
              gAbortServer = PR_TRUE;
 
727
            }
 
728
            break;
 
729
        }
 
730
    }
 
731
 
 
732
    return PR_TRUE; /* Start the app */
 
733
}
 
734
 
 
735
 
 
736
// Create and return an instance of class nsNativeAppSupportOS2.
 
737
nsresult
 
738
NS_CreateNativeAppSupport( nsINativeAppSupport **aResult ) {
 
739
    if ( aResult ) {
 
740
        nsNativeAppSupportOS2 *pNative = new nsNativeAppSupportOS2;
 
741
        if ( pNative ) {                                           
 
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) {
 
746
               delete pNative;
 
747
               return NS_ERROR_FAILURE;
 
748
            }
 
749
            *aResult = pNative;                                    
 
750
            NS_ADDREF( *aResult );                                 
 
751
        } else {
 
752
            return NS_ERROR_OUT_OF_MEMORY;
 
753
        }
 
754
    } else {
 
755
        return NS_ERROR_NULL_POINTER;
 
756
    }
 
757
 
 
758
    return NS_OK;
 
759
}
 
760
 
 
761
// Create instance of OS/2 splash screen object.
 
762
nsresult
 
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;
 
769
    if ( aResult ) {
 
770
        *aResult = 0;
 
771
        CHAR pBuffer[3];
 
772
        PrfQueryProfileString( HINI_USERPROFILE, "PM_ControlPanel", "LogoDisplayTime", "1", pBuffer, 3);
 
773
        if (pBuffer[0] == '0') {
 
774
          doSplashScreen = FALSE;
 
775
        } /* endif */
 
776
        for ( int i = 1; i < __argc; i++ ) {
 
777
            if ( strcmp( "-quiet", __argv[i] ) == 0
 
778
                 ||
 
779
                 strcmp( "/quiet", __argv[i] ) == 0 ) {
 
780
                 doSplashScreen = FALSE;
 
781
            }
 
782
            if ( strcmp( "-splash", __argv[i] ) == 0
 
783
                 ||
 
784
                 strcmp( "/splash", __argv[i] ) == 0 ) {
 
785
                 doSplashScreen = TRUE;
 
786
            }
 
787
        }
 
788
        if (!doSplashScreen) {
 
789
          return NS_OK;
 
790
        }
 
791
        *aResult = new nsSplashScreenOS2;
 
792
        if ( *aResult ) {
 
793
            NS_ADDREF( *aResult );
 
794
        } else {
 
795
            return NS_ERROR_OUT_OF_MEMORY;
 
796
        }
 
797
    } else {
 
798
        return NS_ERROR_NULL_POINTER;
 
799
    }
 
800
 
 
801
    return NS_OK;
 
802
}
 
803
 
 
804
// Constants
 
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
 
810
 
 
811
// The array entries must match the enum ordering!
 
812
const char * const topicNames[] = { "WWW_OpenURL",
 
813
                                    "WWW_Activate",
 
814
                                    "WWW_CancelProgress",
 
815
                                    "WWW_Version",
 
816
                                    "WWW_RegisterViewer",
 
817
                                    "WWW_UnRegisterViewer",
 
818
                                    "WWW_GetWindowInfo" };
 
819
 
 
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;
 
827
 
 
828
 
 
829
// Added this as pmddeml has no api like this
 
830
int DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
 
831
{
 
832
  char chhsz1[CCHMAXPATH], chhsz2[CCHMAXPATH];
 
833
  int rc = -1;
 
834
 
 
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.
 
839
   */
 
840
  WinDdeQueryString( hsz1, chhsz1, sizeof( chhsz1 ), 0 );
 
841
  WinDdeQueryString( hsz2, chhsz2, sizeof( chhsz2 ),0 );
 
842
 
 
843
  rc = stricmp( chhsz1, chhsz2 );
 
844
 
 
845
  return(rc);
 
846
}
 
847
 
 
848
 
 
849
char *GetCommandLine()
 
850
{
 
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.
 
856
    */
 
857
   PTIB pTIB = NULL;
 
858
   PPIB pPIB = NULL;
 
859
   APIRET rc = NO_ERROR;
 
860
   char *pchParam = NULL;
 
861
 
 
862
   rc = DosGetInfoBlocks( &pTIB, &pPIB );
 
863
   if( rc == NO_ERROR )
 
864
   {
 
865
      INT iLen = 0;
 
866
      char *pchTemp = NULL;
 
867
      pchParam = pPIB->pib_pchcmd;
 
868
      strcpy( szCommandLine, pchParam );
 
869
      iLen = strlen( pchParam );
 
870
 
 
871
      /* szCommandLine[iLen] is '\0', so see what's next.  Probably be another
 
872
       * '\0', a space or start of the arguments
 
873
       */
 
874
      pchTemp = &(pchParam[iLen+1]);
 
875
 
 
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
 
879
       */
 
880
      if( *pchTemp )
 
881
      {
 
882
         szCommandLine[iLen] = ' ';
 
883
         iLen++;
 
884
         if( *pchTemp == ' ' )
 
885
         {
 
886
            pchTemp++;
 
887
         }
 
888
         strcpy( &(szCommandLine[iLen]), pchTemp );
 
889
      }
 
890
 
 
891
   }
 
892
 
 
893
   return( szCommandLine );
 
894
}
 
895
 
 
896
typedef struct _DDEMLFN
 
897
{
 
898
   PFN   *fn;
 
899
   ULONG ord; 
 
900
} DDEMLFN, *PDDEMLFN;
 
901
 
 
902
DDEMLFN ddemlfnTable[] = 
 
903
{
 
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 },
 
929
   { (PFN *)NULL                           ,  0 }
 
930
};
 
931
 
 
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
 
935
 */
 
936
BOOL SetupOS2ddeml()
 
937
{
 
938
    BOOL bRC = FALSE;
 
939
    HMODULE hmodDDEML = NULLHANDLE;
 
940
    APIRET rc = NO_ERROR;
 
941
    ULONG ulVersion = 0;
 
942
 
 
943
    rc = DosLoadModule( NULL, 0, "PMDDEML", &hmodDDEML );
 
944
    if( rc == NO_ERROR )
 
945
    {
 
946
       int i=0;
 
947
       /* all of this had better work.  Get ready to be a success! */
 
948
       bRC = TRUE;
 
949
       for( i; ddemlfnTable[i].ord != 0; i++ )
 
950
       {
 
951
          rc = DosQueryProcAddr( hmodDDEML, ddemlfnTable[i].ord, NULL,
 
952
                                 ddemlfnTable[i].fn );
 
953
          if( rc != NO_ERROR )
 
954
          {
 
955
             /* we're horked.  Return rc = horked */
 
956
             bRC = FALSE;
 
957
             break;
 
958
          }
 
959
       }
 
960
    } /* load PMDDEML */
 
961
 
 
962
    return( bRC );
 
963
}
 
964
 
 
965
char nsNativeAppSupportOS2::mMutexName[ 128 ] = { 0 };
 
966
 
 
967
 
 
968
// Message window encapsulation.
 
969
struct MessageWindow {
 
970
    // ctor/dtor are simplistic
 
971
    MessageWindow() {
 
972
        // Try to find window.
 
973
        HATOMTBL  hatomtbl;
 
974
        HENUM     henum;
 
975
        HWND      hwndNext;
 
976
        char      classname[CCHMAXPATH];
 
977
 
 
978
        mHandle = NULLHANDLE;
 
979
 
 
980
        hatomtbl = WinQuerySystemAtomTable();
 
981
        mMsgWindowAtom = WinFindAtom(hatomtbl, className());
 
982
        if (mMsgWindowAtom == 0)
 
983
        {
 
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());
 
987
        } else {
 
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 
 
990
          // exists
 
991
          henum = WinBeginEnumWindows(HWND_OBJECT);
 
992
          while ((hwndNext = WinGetNextWindow(henum)) != NULLHANDLE)
 
993
          {
 
994
            if (WinQueryWindowUShort(hwndNext, QWS_ID) == (USHORT)mMsgWindowAtom)
 
995
            {
 
996
              WinQueryClassName(hwndNext, CCHMAXPATH, classname);
 
997
              if (strcmp(classname, className()) == 0)
 
998
              {
 
999
                mHandle = hwndNext;
 
1000
                break;
 
1001
              }
 
1002
            }
 
1003
          }
 
1004
        }
 
1005
    }
 
1006
 
 
1007
    HWND getHWND() {
 
1008
        return mHandle;
 
1009
    }
 
1010
 
 
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,
 
1017
                         "%s%s",
 
1018
                         nsNativeAppSupportOS2::mAppName,
 
1019
                         "MessageWindow" );
 
1020
            mClassName = classNameBuffer;
 
1021
        }
 
1022
        return mClassName;
 
1023
    }
 
1024
 
 
1025
    // Create: Register class and create window.
 
1026
    NS_IMETHOD Create() {
 
1027
 
 
1028
        // Register the window class.
 
1029
        NS_ENSURE_TRUE( WinRegisterClass( 0, className(), 
 
1030
                                          (PFNWP)&MessageWindow::WindowProc, 
 
1031
                                          0L, 0 ), 
 
1032
                        NS_ERROR_FAILURE );
 
1033
 
 
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
 
1036
         * tools
 
1037
         */
 
1038
        const char * pszClassName = className();
 
1039
        mHandle = WinCreateWindow( HWND_OBJECT,
 
1040
                                   pszClassName,
 
1041
                                   NULL,        // name
 
1042
                                   WS_DISABLED, // style
 
1043
                                   0,0,     // x, y
 
1044
                                   0,0,       // cx,cy
 
1045
                                   HWND_DESKTOP,// owner
 
1046
                                   HWND_BOTTOM,  // hwndbehind
 
1047
                                   (USHORT)mMsgWindowAtom, // id
 
1048
                                   NULL,        // pCtlData
 
1049
                                   NULL );      // pres params
 
1050
 
 
1051
#if MOZ_DEBUG_DDE
 
1052
        printf( "Message window = 0x%08X\n", (int)mHandle );
 
1053
#endif
 
1054
 
 
1055
        return NS_OK;
 
1056
    }
 
1057
 
 
1058
    // Destory:  Get rid of window and reset mHandle.
 
1059
    NS_IMETHOD Destroy() {
 
1060
        nsresult retval = NS_OK;
 
1061
 
 
1062
        if ( mHandle ) {
 
1063
           HATOMTBL hatomtbl = WinQuerySystemAtomTable();
 
1064
           WinDeleteAtom(hatomtbl, mMsgWindowAtom);
 
1065
           
 
1066
            // DestroyWindow can only destroy windows created from
 
1067
            //  the same thread.
 
1068
            BOOL desRes = WinDestroyWindow( mHandle );
 
1069
            if ( FALSE != desRes ) {
 
1070
                mHandle = NULL;
 
1071
            }
 
1072
            else {
 
1073
                retval = NS_ERROR_FAILURE;
 
1074
            }
 
1075
        }
 
1076
 
 
1077
        return retval;
 
1078
    }
 
1079
 
 
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
 
1087
         */
 
1088
 
 
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) );
 
1095
 
 
1096
        if( rc != NO_ERROR )
 
1097
        {
 
1098
           /* don't even try doing anything else.  Windows doesn't worry about
 
1099
            * errors so I guess that we shouldn't either
 
1100
            */
 
1101
           return NS_OK;
 
1102
        }
 
1103
 
 
1104
        memset( pvData, '\0', ulSize );
 
1105
        pcds = (COPYDATASTRUCT *)(pvData);
 
1106
        pcds->dwData = 0;
 
1107
        pcds->cbData = strlen(cmd)+1;
 
1108
        /* put the data in the buffer space immediately after the 
 
1109
         * COPYDATASTRUCT
 
1110
         */
 
1111
        pcds->lpData = &(pcds->chBuff);
 
1112
        if( cmd )
 
1113
        {
 
1114
           strcpy( (char *)pcds->lpData, cmd );
 
1115
        }
 
1116
        WinSendMsg( mHandle, WM_COPYDATA, 0, (MPARAM)pcds );
 
1117
        DosFreeMem( pvData );
 
1118
 
 
1119
        return NS_OK;
 
1120
    }
 
1121
 
 
1122
    // Window proc.
 
1123
    static MRESULT EXPENTRY WindowProc( HWND msgWindow, ULONG msg, MPARAM wp, 
 
1124
                                        MPARAM lp )
 
1125
    {
 
1126
        MRESULT rc = (MRESULT)TRUE;
 
1127
 
 
1128
        if ( msg == WM_COPYDATA ) {
 
1129
            // This is an incoming request.
 
1130
            COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lp;
 
1131
            DosGetSharedMem( (PVOID)cds, PAG_READ|PAG_WRITE );
 
1132
#if MOZ_DEBUG_DDE
 
1133
            printf( "Incoming request: %s\n", (const char*)cds->lpData );
 
1134
#endif
 
1135
            (void)nsNativeAppSupportOS2::HandleRequest( (LPBYTE)cds->lpData );
 
1136
 }
 
1137
 
 
1138
    /* We have to return a FALSE from WM_CREATE or this window will never
 
1139
     * get off of the ground
 
1140
     */
 
1141
    else if ( msg == WM_CREATE ) {
 
1142
        rc = (MRESULT)FALSE;
 
1143
    }
 
1144
 
 
1145
    return rc;
 
1146
}
 
1147
 
 
1148
private:
 
1149
    HWND     mHandle;
 
1150
    USHORT   mMsgWindowAtom;
 
1151
}; // struct MessageWindow
 
1152
 
 
1153
static char nameBuffer[128] = { 0 };
 
1154
char *nsNativeAppSupportOS2::mAppName = nameBuffer;
 
1155
PRBool nsNativeAppSupportOS2::mUseDDE = PR_FALSE;
 
1156
 
 
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
 
1161
 *        options.
 
1162
 *        
 
1163
 *        If not, then this is the first instance of Mozilla.  In
 
1164
 *        that case, we create and set up the message window.
 
1165
 *
 
1166
 *        The checking for existance of the message window must
 
1167
 *        be protected by use of a mutex semaphore.
 
1168
 */
 
1169
NS_IMETHODIMP
 
1170
nsNativeAppSupportOS2::Start( PRBool *aResult ) {
 
1171
    NS_ENSURE_ARG( aResult );
 
1172
    NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED );
 
1173
 
 
1174
    if (getenv("MOZ_NO_REMOTE"))
 
1175
    {
 
1176
        *aResult = PR_TRUE;
 
1177
        return NS_OK;
 
1178
    }
 
1179
 
 
1180
    nsresult rv = NS_ERROR_FAILURE;
 
1181
    *aResult = PR_FALSE;
 
1182
 
 
1183
    for ( int i = 1; i < __argc; i++ ) {
 
1184
        if ( strcmp( "-dde", __argv[i] ) == 0 ||
 
1185
             strcmp( "/dde", __argv[i] ) == 0 ) {
 
1186
            mUseDDE = PR_TRUE;
 
1187
        }
 
1188
    }
 
1189
 
 
1190
    // Grab mutex first.
 
1191
    int retval;
 
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.
 
1196
        *aResult = PR_TRUE;
 
1197
        return NS_OK;
 
1198
    }
 
1199
 
 
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 );
 
1203
 
 
1204
    NS_ENSURE_TRUE( startupLock.Lock( MOZ_DDE_START_TIMEOUT ), NS_ERROR_FAILURE );
 
1205
 
 
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.
 
1210
     */
 
1211
    MQINFO mqinfo;
 
1212
    HAB hab;
 
1213
    HMQ hmqCurrent = WinQueryQueueInfo( HMQ_CURRENT, &mqinfo, 
 
1214
                                        sizeof( MQINFO ) );
 
1215
    if( !hmqCurrent )
 
1216
    {
 
1217
        hab = WinInitialize( 0 );
 
1218
        hmqCurrent = WinCreateMsgQueue( hab, 0 );
 
1219
    }
 
1220
 
 
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 );
 
1227
    } else {
 
1228
        // We will be server.
 
1229
        if (!gAbortServer) {
 
1230
            rv = msgWindow.Create();
 
1231
            if ( NS_SUCCEEDED( rv ) ) {
 
1232
                if (mUseDDE) {
 
1233
                    // Start up DDE server.
 
1234
                    this->StartDDE();
 
1235
                }
 
1236
                // Tell caller to spin message loop.
 
1237
                *aResult = PR_TRUE;
 
1238
            }
 
1239
        }
 
1240
    }
 
1241
 
 
1242
    startupLock.Unlock();
 
1243
 
 
1244
    if( *aResult == PR_FALSE )
 
1245
    {
 
1246
        /* This process isn't going to continue much longer.  Make sure that we
 
1247
         * clean up the message queue
 
1248
         */
 
1249
        if (hmqCurrent)
 
1250
           WinDestroyMsgQueue(hmqCurrent);
 
1251
        if (hab)
 
1252
           WinTerminate(hab);
 
1253
    }
 
1254
 
 
1255
    return rv;
 
1256
}
 
1257
 
 
1258
PRBool
 
1259
nsNativeAppSupportOS2::InitTopicStrings() {
 
1260
    for ( int i = 0; i < topicCount; i++ ) {
 
1261
        if ( !( mTopics[ i ] = WinDdeCreateStringHandle( (PSZ)topicNames[ i ], CP_WINANSI ) ) ) {
 
1262
            return PR_FALSE;
 
1263
        }
 
1264
    }
 
1265
    return PR_TRUE;
 
1266
}
 
1267
 
 
1268
int
 
1269
nsNativeAppSupportOS2::FindTopic( HSZ topic ) {
 
1270
    for ( int i = 0; i < topicCount; i++ ) {
 
1271
        if ( DdeCmpStringHandles( topic, mTopics[i] ) == 0 ) {
 
1272
            return i;
 
1273
        }
 
1274
    }
 
1275
    return -1;
 
1276
}
 
1277
 
 
1278
// Start DDE server.
 
1279
//
 
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.
 
1283
//
 
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(),
 
1287
// above.
 
1288
NS_IMETHODIMP
 
1289
nsNativeAppSupportOS2::StartDDE() {
 
1290
    NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED );
 
1291
 
 
1292
    /* Get entrypoints for PMDDEML */
 
1293
    BOOL bDDEML = SetupOS2ddeml();
 
1294
 
 
1295
    /* If we couldn't initialize DDEML, set mUSEDDE to PR_FALSE */
 
1296
    /* so we don't do anything else DDE related */
 
1297
    if (!bDDEML) {
 
1298
       mUseDDE = PR_FALSE;
 
1299
       return NS_OK;
 
1300
    }
 
1301
 
 
1302
    // Initialize DDE.
 
1303
    NS_ENSURE_TRUE( DDEERR_NO_ERROR == WinDdeInitialize( &mInstance,
 
1304
                                                         nsNativeAppSupportOS2::HandleDDENotification,
 
1305
                                                         APPCLASS_STANDARD,
 
1306
                                                         0 ),
 
1307
                    NS_ERROR_FAILURE );
 
1308
 
 
1309
    // Allocate DDE strings.
 
1310
    NS_ENSURE_TRUE( ( mApplication = WinDdeCreateStringHandle( mAppName, CP_WINANSI ) ) && InitTopicStrings(),
 
1311
                    NS_ERROR_FAILURE );
 
1312
 
 
1313
    // Next step is to register a DDE service.
 
1314
    NS_ENSURE_TRUE( WinDdeNameService( mInstance, mApplication, 0, DNS_REGISTER ), NS_ERROR_FAILURE );
 
1315
 
 
1316
#if MOZ_DEBUG_DDE
 
1317
    printf( "DDE server started\n" );
 
1318
#endif
 
1319
 
 
1320
    return NS_OK;
 
1321
}
 
1322
 
 
1323
// If no DDE conversations are pending, terminate DDE.
 
1324
NS_IMETHODIMP
 
1325
nsNativeAppSupportOS2::Stop( PRBool *aResult ) {
 
1326
    NS_ENSURE_ARG( aResult );
 
1327
    NS_ENSURE_TRUE( mInstance, NS_ERROR_NOT_INITIALIZED );
 
1328
 
 
1329
    nsresult rv = NS_OK;
 
1330
    *aResult = PR_TRUE;
 
1331
 
 
1332
    if (!mUseDDE) {
 
1333
       return rv;
 
1334
    }
 
1335
 
 
1336
    Mutex ddeLock( mMutexName );
 
1337
 
 
1338
    if ( ddeLock.Lock( MOZ_DDE_STOP_TIMEOUT ) ) {
 
1339
        if ( mConversations == 0 ) {
 
1340
            this->Quit();
 
1341
        } else {
 
1342
            *aResult = PR_FALSE;
 
1343
        }
 
1344
 
 
1345
        ddeLock.Unlock();
 
1346
    }
 
1347
    else {
 
1348
        // No DDE application name specified, but that's OK.  Just
 
1349
        // forge ahead.
 
1350
        *aResult = PR_TRUE;
 
1351
    }
 
1352
 
 
1353
    return rv;
 
1354
}
 
1355
 
 
1356
// Terminate DDE regardless.
 
1357
NS_IMETHODIMP
 
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 );
 
1365
 
 
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.
 
1370
    MessageWindow mw;
 
1371
    mw.Destroy();
 
1372
 
 
1373
    if ( mInstance ) {
 
1374
        // Unregister application name.
 
1375
        WinDdeNameService( mInstance, mApplication, 0, DNS_UNREGISTER );
 
1376
        // Clean up strings.
 
1377
        if ( mApplication ) {
 
1378
            WinDdeFreeStringHandle( mApplication );
 
1379
            mApplication = 0;
 
1380
        }
 
1381
        for ( int i = 0; i < topicCount; i++ ) {
 
1382
            if ( mTopics[i] ) {
 
1383
                WinDdeFreeStringHandle( mTopics[i] );
 
1384
                mTopics[i] = 0;
 
1385
            }
 
1386
        }
 
1387
        WinDdeUninitialize( mInstance );
 
1388
        mInstance = 0;
 
1389
    }
 
1390
 
 
1391
    return NS_OK;
 
1392
}
 
1393
 
 
1394
PRBool NS_CanRun()
 
1395
{
 
1396
      return PR_FALSE; /*  We do this so that we can bail if we are using custom turbo mode */
 
1397
}
 
1398
 
 
1399
#if MOZ_DEBUG_DDE
 
1400
// Macro to generate case statement for a given XTYP value.
 
1401
#define XTYP_CASE(t) \
 
1402
    case t: result = #t; break
 
1403
 
 
1404
static nsCString uTypeDesc( UINT uType ) {
 
1405
    nsCString result;
 
1406
    switch ( 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_?????";
 
1424
    }
 
1425
    return result;
 
1426
}
 
1427
 
 
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 );
 
1432
    if ( len ) {
 
1433
        char buffer[ 256 ];
 
1434
        WinDdeQueryString( hsz, buffer, sizeof buffer, CP_WINANSI );
 
1435
        result += buffer;
 
1436
    }
 
1437
    result += "]";
 
1438
    return result;
 
1439
}
 
1440
#else
 
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( "?" );
 
1445
}
 
1446
static nsCString hszValue( DWORD, HSZ ) {
 
1447
    return nsCString( "?" );
 
1448
}
 
1449
#endif
 
1450
 
 
1451
 
 
1452
// Utility function to escape double-quotes within a string.
 
1453
static void escapeQuotes( nsAString &aString ) {
 
1454
    PRInt32 offset = -1;
 
1455
    while( 1 ) {
 
1456
       // Find next '"'.
 
1457
       offset = aString.FindChar( '"', ++offset );
 
1458
       if ( offset == kNotFound ) {
 
1459
           // No more quotes, exit.
 
1460
           break;
 
1461
       } else {
 
1462
           // Insert back-slash ahead of the '"'.
 
1463
           aString.Insert( PRUnichar('\\'), offset );
 
1464
           // Increment offset because we just inserted a slash
 
1465
           offset++;
 
1466
       }
 
1467
    }
 
1468
    return;
 
1469
}
 
1470
 
 
1471
HDDEDATA APIENTRY
 
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
 
1481
 
 
1482
#if MOZ_DEBUG_DDE
 
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 );
 
1491
#endif
 
1492
 
 
1493
    HDDEDATA result = 0;
 
1494
    if ( uType & XCLASS_BOOL ) {
 
1495
        switch ( uType ) {
 
1496
            case XTYP_CONNECT:
 
1497
                // Make sure its for our service/topic.
 
1498
                if ( FindTopic( hsz1 ) != -1 ) {
 
1499
                    // We support this connection.
 
1500
                    result = (HDDEDATA)1;
 
1501
                }
 
1502
                break;
 
1503
            case XTYP_CONNECT_CONFIRM:
 
1504
                // We don't care about the conversation handle, at this point.
 
1505
                result = (HDDEDATA)1;
 
1506
                break;
 
1507
        }
 
1508
    } else if ( uType & XCLASS_DATA ) {
 
1509
        if ( uType == XTYP_REQUEST ) {
 
1510
            switch ( FindTopic( hsz1 ) ) {
 
1511
                case topicOpenURL: {
 
1512
                    // Open a given URL...
 
1513
 
 
1514
                    // Default is to open in current window.
 
1515
                    PRBool new_window = PR_FALSE;
 
1516
 
 
1517
                    // Get the URL from the first argument in the command.
 
1518
                    nsCAutoString url( ParseDDEArg( hsz2, 0 ) );
 
1519
 
 
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 ) );
 
1523
 
 
1524
                    // "0" means to open the URL in a new window.
 
1525
                    if ( windowID.Equals( "0" ) ) {
 
1526
                        new_window = PR_TRUE;
 
1527
                    }
 
1528
 
 
1529
                    // Make it look like command line args.
 
1530
                    url.Insert( "mozilla -url ", 0 );
 
1531
#if MOZ_DEBUG_DDE
 
1532
                    printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() );
 
1533
#endif
 
1534
                    // Now handle it.
 
1535
                    HandleRequest( LPBYTE( url.get() ), new_window );
 
1536
                    // Return pseudo window ID.
 
1537
                    result = CreateDDEData( 1 );
 
1538
                    break;
 
1539
                }
 
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
 
1546
 
 
1547
                    // This isn't really a loop.  We just use "break"
 
1548
                    // statements to bypass the remaining steps when
 
1549
                    // something goes wrong.
 
1550
                    do {
 
1551
                        // Get most recently used Nav window.
 
1552
                        nsCOMPtr<nsIDOMWindowInternal> navWin;
 
1553
                        GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(),
 
1554
                                             getter_AddRefs( navWin ) );
 
1555
                        if ( !navWin ) {
 
1556
                            // There is not a window open
 
1557
                            break;
 
1558
                        }
 
1559
                        // Get content window.
 
1560
                        nsCOMPtr<nsIDOMWindow> content;
 
1561
                        navWin->GetContent( getter_AddRefs( content ) );
 
1562
                        if ( !content ) {
 
1563
                            break;
 
1564
                        }
 
1565
                        // Convert that to internal interface.
 
1566
                        nsCOMPtr<nsIDOMWindowInternal> internalContent( do_QueryInterface( content ) );
 
1567
                        if ( !internalContent ) {
 
1568
                            break;
 
1569
                        }
 
1570
                        // Get location.
 
1571
                        nsCOMPtr<nsIDOMLocation> location;
 
1572
                        internalContent->GetLocation( getter_AddRefs( location ) );
 
1573
                        if ( !location ) {
 
1574
                            break;
 
1575
                        }
 
1576
                        // Get href for URL.
 
1577
                        nsAutoString url;
 
1578
                        if ( NS_FAILED( location->GetHref( url ) ) ) {
 
1579
                            break;
 
1580
                        }
 
1581
                        // Escape any double-quotes.
 
1582
                        escapeQuotes( url );
 
1583
 
 
1584
                        // Now for the title; first, get the "window" script global object.
 
1585
                        nsCOMPtr<nsIScriptGlobalObject> scrGlobalObj( do_QueryInterface( internalContent ) );
 
1586
                        if ( !scrGlobalObj ) {
 
1587
                            break;
 
1588
                        }
 
1589
                        // Then from its doc shell get the base window...
 
1590
                        nsCOMPtr<nsIBaseWindow> baseWindow =
 
1591
                          do_QueryInterface( scrGlobalObj->GetDocShell() );
 
1592
                        if ( !baseWindow ) {
 
1593
                            break;
 
1594
                        }
 
1595
                        // And from the base window we can get the title.
 
1596
                        nsXPIDLString title;
 
1597
                        if(!baseWindow) {
 
1598
                            break;
 
1599
                        }
 
1600
                        baseWindow->GetTitle(getter_Copies(title));
 
1601
                        // Escape any double-quotes in the title.
 
1602
                        escapeQuotes( title );
 
1603
 
 
1604
                        // Use a string buffer for the output data, first
 
1605
                        // save a quote.
 
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
 
1611
                        // title
 
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( "\",\"\"" ));
 
1617
 
 
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 );
 
1624
#if MOZ_DEBUG_DDE
 
1625
                        printf( "WWW_GetWindowInfo->%s\n", outpt.get() );
 
1626
#endif
 
1627
                    } while ( PR_FALSE );
 
1628
                    break;
 
1629
                }
 
1630
                case topicActivate: {
 
1631
                    // Activate a Nav window...
 
1632
                    nsCString windowID = ParseDDEArg( hsz2, 0 );
 
1633
 
 
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 );
 
1642
                    }
 
1643
                    break;
 
1644
                }
 
1645
                case topicVersion: {
 
1646
                    // Return version.  We're restarting at 1.0!
 
1647
                    DWORD version = 1 << 16; // "1.0"
 
1648
                    result = CreateDDEData( version );
 
1649
                    break;
 
1650
                }
 
1651
                case topicRegisterViewer: {
 
1652
                    // Register new viewer (not implemented).
 
1653
                    result = CreateDDEData( PR_FALSE );
 
1654
                    break;
 
1655
                }
 
1656
                case topicUnRegisterViewer: {
 
1657
                    // Unregister new viewer (not implemented).
 
1658
                    result = CreateDDEData( PR_FALSE );
 
1659
                    break;
 
1660
                }
 
1661
                default:
 
1662
                    break;
 
1663
            }
 
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;
 
1669
                    break;
 
1670
                }
 
1671
                default:
 
1672
                    break;
 
1673
            }
 
1674
        }
 
1675
    } else if ( uType & XCLASS_FLAGS ) {
 
1676
        if ( uType == XTYP_EXECUTE ) {
 
1677
            // Prove that we received the request.
 
1678
            DWORD bytes;
 
1679
            LPBYTE request = (LPBYTE)WinDdeAccessData( hdata, &bytes );
 
1680
#if MOZ_DEBUG_DDE
 
1681
            printf( "Handling dde request: [%s]...\n", (char*)request );
 
1682
#endif
 
1683
            // Default is to open in current window.
 
1684
            PRBool new_window = PR_FALSE;
 
1685
 
 
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 ) );
 
1689
 
 
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 ) );
 
1693
 
 
1694
            // "0" means to open the URL in a new window.
 
1695
            if ( windowID.Equals( "0" ) ) {
 
1696
                new_window = PR_TRUE;
 
1697
            }
 
1698
 
 
1699
            // Make it look like command line args.
 
1700
            url.Insert( "mozilla -url ", 0 );
 
1701
#if MOZ_DEBUG_DDE
 
1702
            printf( "Handling dde XTYP_REQUEST request: [%s]...\n", url.get() );
 
1703
#endif
 
1704
            // Now handle it.
 
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;
 
1711
        } else {
 
1712
            result = (HDDEDATA)DDE_NOTPROCESSED;
 
1713
        }
 
1714
    } else if ( uType & XCLASS_NOTIFICATION ) {
 
1715
    }
 
1716
#if MOZ_DEBUG_DDE
 
1717
    printf( "DDE result=%d (0x%08X)\n", (int)result, (int)result );
 
1718
#endif
 
1719
    return result;
 
1720
}
 
1721
 
 
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
 
1727
// of the arg.
 
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] == '\\' ) {
 
1736
                offset++;
 
1737
            }
 
1738
        }
 
1739
    }
 
1740
    return offset;
 
1741
}
 
1742
 
 
1743
// Utility to parse out argument from a DDE item string.
 
1744
nsCString nsNativeAppSupportOS2::ParseDDEArg( HSZ args, int index ) {
 
1745
    nsCString result;
 
1746
    DWORD argLen = WinDdeQueryString( args, NULL, NULL, CP_WINANSI );
 
1747
    if ( argLen ) {
 
1748
        nsCString temp;
 
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.
 
1758
        while( index-- ) {
 
1759
            // If this arg is quoted, then go to closing quote.
 
1760
            offset = advanceToEndOfQuotedArg( p, offset, argLen );
 
1761
            // Find next comma.
 
1762
            offset = temp.FindChar( ',', offset );
 
1763
            if ( offset == kNotFound ) {
 
1764
                // No more commas, give up.
 
1765
                return result;
 
1766
            }
 
1767
        }
 
1768
 
 
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).
 
1772
        //
 
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.
 
1782
            end = argLen;
 
1783
        }
 
1784
        // Extract result.
 
1785
        result.Assign( p + offset, end - offset );
 
1786
    }
 
1787
    return result;
 
1788
}
 
1789
 
 
1790
void nsNativeAppSupportOS2::ActivateLastWindow() {
 
1791
    nsCOMPtr<nsIDOMWindowInternal> navWin;
 
1792
    GetMostRecentWindow( NS_LITERAL_STRING("navigator:browser").get(), getter_AddRefs( navWin ) );
 
1793
    if ( navWin ) {
 
1794
        // Activate that window.
 
1795
        activateWindow( navWin );
 
1796
    } else {
 
1797
        // Need to create a Navigator window, then.
 
1798
        OpenBrowserWindow( "about:blank" );
 
1799
    }
 
1800
}
 
1801
 
 
1802
HDDEDATA nsNativeAppSupportOS2::CreateDDEData( DWORD value ) {
 
1803
    return CreateDDEData( (LPBYTE)&value, sizeof value );
 
1804
}
 
1805
 
 
1806
HDDEDATA nsNativeAppSupportOS2::CreateDDEData( LPBYTE value, DWORD len ) {
 
1807
    HDDEDATA result = WinDdeCreateDataHandle( value,
 
1808
                                              len,
 
1809
                                              0,
 
1810
                                              mApplication,
 
1811
                                              CF_TEXT,
 
1812
                                              0 );
 
1813
    return result;
 
1814
}
 
1815
 
 
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).
 
1821
void
 
1822
nsNativeAppSupportOS2::HandleRequest( LPBYTE request, PRBool newWindow ) {
 
1823
 
 
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
 
1826
 
 
1827
    if (mInitialWindowActive) {
 
1828
      return;
 
1829
    }
 
1830
 
 
1831
    // Parse command line.
 
1832
 
 
1833
    nsCOMPtr<nsICmdLineService> args;
 
1834
    nsresult rv;
 
1835
 
 
1836
    rv = GetCmdLineArgs( request, getter_AddRefs( args ) );
 
1837
    if (NS_FAILED(rv)) return;
 
1838
 
 
1839
    nsCOMPtr<nsIAppShellService> appShell(do_GetService("@mozilla.org/appshell/appShellService;1", &rv));
 
1840
    if (NS_FAILED(rv)) return;
 
1841
 
 
1842
    nsCOMPtr<nsINativeAppSupport> nativeApp;
 
1843
    rv = appShell->GetNativeAppSupport(getter_AddRefs( nativeApp ));
 
1844
    if (NS_FAILED(rv)) return;
 
1845
 
 
1846
    // first see if there is a url
 
1847
    nsXPIDLCString arg;
 
1848
    rv = args->GetURLToLoad(getter_Copies(arg));
 
1849
    if (NS_SUCCEEDED(rv) && (const char*)arg ) {
 
1850
      // Launch browser.
 
1851
#if MOZ_DEBUG_DDE
 
1852
      printf( "Launching browser on url [%s]...\n", (const char*)arg );
 
1853
#endif
 
1854
      if (NS_SUCCEEDED(nativeApp->EnsureProfile(args)))
 
1855
        (void)OpenBrowserWindow( arg, newWindow );
 
1856
      return;
 
1857
    }
 
1858
 
 
1859
 
 
1860
    // ok, let's try the -chrome argument
 
1861
    rv = args->GetCmdLineValue("-chrome", getter_Copies(arg));
 
1862
    if (NS_SUCCEEDED(rv) && (const char*)arg ) {
 
1863
      // Launch chrome.
 
1864
#if MOZ_DEBUG_DDE
 
1865
      printf( "Launching chrome url [%s]...\n", (const char*)arg );
 
1866
#endif
 
1867
      if (NS_SUCCEEDED(nativeApp->EnsureProfile(args)))
 
1868
        (void)OpenWindow( arg, "" );
 
1869
      return;
 
1870
    }
 
1871
 
 
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
 
1874
 
 
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;
 
1881
      }
 
1882
    }
 
1883
 
 
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;
 
1891
      
 
1892
      nsCOMPtr<nsINativeAppSupport> native;
 
1893
      rv = appShell->GetNativeAppSupport( getter_AddRefs( native ));
 
1894
      if (NS_SUCCEEDED(rv)) {
 
1895
        native->SetIsServerMode( PR_FALSE );
 
1896
 
 
1897
        // close app if there are no more top-level windows.
 
1898
        appShell->Quit(nsIAppShellService::eConsiderQuit);
 
1899
      }
 
1900
 
 
1901
      return;
 
1902
    }
 
1903
 
 
1904
    // Try standard startup's command-line handling logic from nsAppRunner.cpp...
 
1905
 
 
1906
    // Need profile before opening windows.
 
1907
    rv = nativeApp->EnsureProfile(args);
 
1908
    if (NS_FAILED(rv)) return;
 
1909
 
 
1910
    // This will tell us whether the command line processing opened a window.
 
1911
    PRBool windowOpened = PR_FALSE;
 
1912
 
 
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;
 
1926
    PRInt32 argc = 0;
 
1927
    args->GetArgc( &argc );
 
1928
    if ( argc <= 1 ) {
 
1929
        // Use startup prefs iff there are no windows currently open.
 
1930
        nsCOMPtr<nsIDOMWindowInternal> win;
 
1931
        GetMostRecentWindow( 0, getter_AddRefs( win ) );
 
1932
        if ( !win ) {
 
1933
            heedStartupPrefs = PR_TRUE;
 
1934
        }
 
1935
    }
 
1936
 
 
1937
    // Process command line options.
 
1938
    rv = DoCommandLines( args, heedStartupPrefs, &windowOpened );
 
1939
 
 
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) {
 
1943
      return;
 
1944
    }
 
1945
 
 
1946
    // ok, no idea what the param is.
 
1947
#if MOZ_DEBUG_DDE
 
1948
    printf( "Unknown request [%s]\n", (char*) request );
 
1949
#endif
 
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;
 
1955
 
 
1956
    nsXPIDLString defaultArgs;
 
1957
    rv = handler->GetDefaultArgs(getter_Copies(defaultArgs));
 
1958
    if (NS_FAILED(rv) || !defaultArgs) return;
 
1959
 
 
1960
    if (defaultArgs) {
 
1961
      nsCAutoString url;
 
1962
      url.AssignWithConversion( defaultArgs );
 
1963
      OpenBrowserWindow(url.get());
 
1964
    } else {
 
1965
      OpenBrowserWindow("about:blank");
 
1966
    }
 
1967
}
 
1968
 
 
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).
 
1972
nsresult
 
1973
nsNativeAppSupportOS2::GetCmdLineArgs( LPBYTE request, nsICmdLineService **aResult ) {
 
1974
    nsresult rv = NS_OK;
 
1975
 
 
1976
    int justCounting = 1;
 
1977
    char **argv = 0;
 
1978
    // Flags, etc.
 
1979
    int init = 1;
 
1980
    int between, quoted, bSlashCount;
 
1981
    int argc;
 
1982
    char *p;
 
1983
    nsCAutoString arg;
 
1984
    // We loop if we've not finished the second pass through.
 
1985
    while ( 1 ) {
 
1986
        // Initialize if required.
 
1987
        if ( init ) {
 
1988
            p = (char*)request;
 
1989
            between = 1;
 
1990
            argc = quoted = bSlashCount = 0;
 
1991
 
 
1992
            init = 0;
 
1993
        }
 
1994
        if ( between ) {
 
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.
 
1999
                between = 0;
 
2000
                arg = "";
 
2001
                switch ( *p ) {
 
2002
                    case '\\':
 
2003
                        // Count the backslash.
 
2004
                        bSlashCount = 1;
 
2005
                        break;
 
2006
                    case '"':
 
2007
                        // Remember we're inside quotes.
 
2008
                        quoted = 1;
 
2009
                        break;
 
2010
                    default:
 
2011
                        // Add character to arg.
 
2012
                        arg += *p;
 
2013
                        break;
 
2014
                }
 
2015
            } else {
 
2016
                // Another space between args, ignore it.
 
2017
            }
 
2018
        } else {
 
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 ) {
 
2025
                    arg += '\\';
 
2026
                    bSlashCount--;
 
2027
                }
 
2028
                // End current arg.
 
2029
                if ( !justCounting ) {
 
2030
                    argv[argc] = new char[ arg.Length() + 1 ];
 
2031
                    strcpy( argv[argc], arg.get() ); 
 
2032
                }
 
2033
                argc++;
 
2034
                // We're now between args.
 
2035
                between = 1;
 
2036
            } else {
 
2037
                // Still inside argument, process the character.
 
2038
                switch ( *p ) {
 
2039
                    case '"':
 
2040
                        // First, digest preceding backslashes (if any).
 
2041
                        while ( bSlashCount > 1 ) {
 
2042
                            // Put one backsplash in arg for each pair.
 
2043
                            arg += '\\';
 
2044
                            bSlashCount -= 2;
 
2045
                        }
 
2046
                        if ( bSlashCount ) {
 
2047
                            // Quote is literal.
 
2048
                            arg += '"';
 
2049
                            bSlashCount = 0;
 
2050
                        } else {
 
2051
                            // Quote starts or ends a quoted section.
 
2052
                            if ( quoted ) {
 
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.
 
2059
                                    bSlashCount = 1;
 
2060
                                } else {
 
2061
                                    quoted = 0;
 
2062
                                }
 
2063
                            } else {
 
2064
                                quoted = 1;
 
2065
                            }
 
2066
                        }
 
2067
                        break;
 
2068
                    case '\\':
 
2069
                        // Add to count.
 
2070
                        bSlashCount++;
 
2071
                        break;
 
2072
                    default:
 
2073
                        // Accept any preceding backslashes literally.
 
2074
                        while ( bSlashCount ) {
 
2075
                            arg += '\\';
 
2076
                            bSlashCount--;
 
2077
                        }
 
2078
                        // Just add next char to the current arg.
 
2079
                        arg += *p;
 
2080
                        break;
 
2081
                }
 
2082
            }
 
2083
        }
 
2084
        // Check for end of input.
 
2085
        if ( *p ) {
 
2086
            // Go to next character.
 
2087
            p++;
 
2088
        } else {
 
2089
            // If on first pass, go on to second.
 
2090
            if ( justCounting ) {
 
2091
                // Allocate argv array.
 
2092
                argv = new char*[ argc ];
 
2093
    
 
2094
                // Start second pass
 
2095
                justCounting = 0;
 
2096
                init = 1;
 
2097
            } else {
 
2098
                // Quit.
 
2099
                break;
 
2100
            }
 
2101
        }
 
2102
    }
 
2103
 
 
2104
    // OK, now create nsICmdLineService object from argc/argv.
 
2105
    static NS_DEFINE_CID( kCmdLineServiceCID,    NS_COMMANDLINE_SERVICE_CID );
 
2106
 
 
2107
    nsCOMPtr<nsIComponentManager> compMgr;
 
2108
    NS_GetComponentManager(getter_AddRefs(compMgr));
 
2109
    rv = compMgr->CreateInstance( kCmdLineServiceCID,
 
2110
                                  0,
 
2111
                                  NS_GET_IID( nsICmdLineService ),
 
2112
                                  (void**)aResult );
 
2113
 
 
2114
    if ( NS_FAILED( rv ) || NS_FAILED( ( rv = (*aResult)->Initialize( argc, argv ) ) ) ) {
 
2115
#if MOZ_DEBUG_DDE
 
2116
        printf( "Error creating command line service = 0x%08X (argc=%d, argv=0x%08X)\n", (int)rv, (int)argc, (void*)argv );
 
2117
#endif
 
2118
    }
 
2119
 
 
2120
    // Cleanup.
 
2121
    while ( argc ) {
 
2122
        delete [] argv[ --argc ];
 
2123
    }
 
2124
    delete [] argv;
 
2125
 
 
2126
    return rv;
 
2127
}
 
2128
 
 
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().
 
2133
nsresult
 
2134
nsNativeAppSupportOS2::EnsureProfile(nsICmdLineService* args)
 
2135
{
 
2136
  nsresult rv;  
 
2137
 
 
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;
 
2142
 
 
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.
 
2148
  PRBool haveProfile;
 
2149
  rv = profileMgr->IsCurrentProfileAvailable(&haveProfile);
 
2150
  if (!mForceProfileStartup && NS_SUCCEEDED(rv) && haveProfile)
 
2151
      return NS_OK;
 
2152
 
 
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;
 
2157
 
 
2158
  // See if profile manager is being suppressed via -silent flag.
 
2159
  PRBool canInteract = PR_TRUE;
 
2160
  nsXPIDLCString arg;
 
2161
  if (NS_SUCCEEDED(args->GetCmdLineValue("-silent", getter_Copies(arg)))) {
 
2162
    if ((const char*)arg) {
 
2163
      canInteract = PR_FALSE;
 
2164
    }
 
2165
  }
 
2166
  rv = appShell->DoProfileStartup(args, canInteract);
 
2167
 
 
2168
  mForceProfileStartup = PR_FALSE;
 
2169
 
 
2170
  return rv;
 
2171
}
 
2172
 
 
2173
nsresult
 
2174
nsNativeAppSupportOS2::OpenWindow( const char*urlstr, const char *args ) {
 
2175
 
 
2176
  nsresult rv = NS_ERROR_FAILURE;
 
2177
 
 
2178
  nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
 
2179
  nsCOMPtr<nsISupportsCString> sarg(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
 
2180
  if (sarg)
 
2181
    sarg->SetData(nsDependentCString(args));
 
2182
 
 
2183
  if (wwatch && sarg) {
 
2184
    nsCOMPtr<nsIDOMWindow> newWindow;
 
2185
    rv = wwatch->OpenWindow(0, urlstr, "_blank", "chrome,dialog=no,all",
 
2186
                   sarg, getter_AddRefs(newWindow));
 
2187
#if MOZ_DEBUG_DDE
 
2188
  } else {
 
2189
      printf("Get WindowWatcher (or create string) failed\n");
 
2190
#endif
 
2191
  }
 
2192
  return rv;
 
2193
}
 
2194
 
 
2195
HWND hwndForDOMWindow( nsISupports *window ) {
 
2196
    nsCOMPtr<nsIScriptGlobalObject> ppScriptGlobalObj( do_QueryInterface(window) );
 
2197
    if ( !ppScriptGlobalObj ) {
 
2198
        return 0;
 
2199
    }
 
2200
 
 
2201
    nsCOMPtr<nsIBaseWindow> ppBaseWindow =
 
2202
      do_QueryInterface( ppScriptGlobalObj->GetDocShell() );
 
2203
    if ( !ppBaseWindow ) {
 
2204
        return 0;
 
2205
    }
 
2206
 
 
2207
    nsCOMPtr<nsIWidget> ppWidget;
 
2208
    ppBaseWindow->GetMainWidget( getter_AddRefs( ppWidget ) );
 
2209
 
 
2210
    return (HWND)( ppWidget->GetNativeData( NS_NATIVE_WIDGET ) );
 
2211
}
 
2212
 
 
2213
nsresult
 
2214
nsNativeAppSupportOS2::ReParent( nsISupports *window, HWND newParent ) {
 
2215
    HWND hMainClient = hwndForDOMWindow( window );
 
2216
    if ( !hMainClient ) {
 
2217
        return NS_ERROR_FAILURE;
 
2218
    }
 
2219
    HWND hMainFrame = WinQueryWindow(hMainClient, QW_PARENT);
 
2220
 
 
2221
    // Reset the parent.
 
2222
    WinSetParent( hMainFrame, newParent, FALSE );
 
2223
 
 
2224
    return NS_OK;
 
2225
}
 
2226
 
 
2227
static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 
2228
 
 
2229
class SafeJSContext {
 
2230
public:
 
2231
  SafeJSContext();
 
2232
  ~SafeJSContext();
 
2233
 
 
2234
  nsresult   Push();
 
2235
  JSContext *get() { return mContext; }
 
2236
 
 
2237
protected:
 
2238
  nsCOMPtr<nsIThreadJSContextStack>  mService;
 
2239
  JSContext                         *mContext;
 
2240
};
 
2241
 
 
2242
SafeJSContext::SafeJSContext() : mContext(nsnull) {
 
2243
}
 
2244
 
 
2245
SafeJSContext::~SafeJSContext() {
 
2246
  JSContext *cx;
 
2247
  nsresult   rv;
 
2248
 
 
2249
  if(mContext) {
 
2250
    rv = mService->Pop(&cx);
 
2251
    NS_ASSERTION(NS_SUCCEEDED(rv) && cx == mContext, "JSContext push/pop mismatch");
 
2252
  }
 
2253
}
 
2254
 
 
2255
nsresult SafeJSContext::Push() {
 
2256
  nsresult rv;
 
2257
 
 
2258
  if (mContext) // only once
 
2259
    return NS_ERROR_FAILURE;
 
2260
 
 
2261
  mService = do_GetService(sJSStackContractID);
 
2262
  if(mService) {
 
2263
    rv = mService->GetSafeJSContext(&mContext);
 
2264
    if (NS_SUCCEEDED(rv) && mContext) {
 
2265
      rv = mService->Push(mContext);
 
2266
      if (NS_FAILED(rv))
 
2267
        mContext = 0;
 
2268
    }
 
2269
  }
 
2270
  return mContext ? NS_OK : NS_ERROR_FAILURE; 
 
2271
}
 
2272
 
 
2273
 
 
2274
nsresult
 
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.
 
2279
    
 
2280
    // Get most recently used Nav window.
 
2281
    nsCOMPtr<nsIDOMWindowInternal> navWin;
 
2282
    GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(), getter_AddRefs( navWin ) );
 
2283
 
 
2284
    // This isn't really a loop.  We just use "break" statements to fall
 
2285
    // out to the OpenWindow call when things go awry.
 
2286
    do {
 
2287
        // If caller requires a new window, then don't use an existing one.
 
2288
        if ( newWindow ) {
 
2289
            break;
 
2290
        }
 
2291
        if ( !navWin ) {
 
2292
            // Have to open a new one.
 
2293
            break;
 
2294
        }
 
2295
        // Get content window.
 
2296
        nsCOMPtr<nsIDOMWindow> content;
 
2297
        navWin->GetContent( getter_AddRefs( content ) );
 
2298
        if ( !content ) {
 
2299
            break;
 
2300
        }
 
2301
        // Convert that to internal interface.
 
2302
        nsCOMPtr<nsIDOMWindowInternal> internalContent( do_QueryInterface( content ) );
 
2303
        if ( !internalContent ) {
 
2304
            break;
 
2305
        }
 
2306
        // Get location.
 
2307
        nsCOMPtr<nsIDOMLocation> location;
 
2308
        internalContent->GetLocation( getter_AddRefs( location ) );
 
2309
        if ( !location ) {
 
2310
            break;
 
2311
        }
 
2312
        // Set up environment.
 
2313
        SafeJSContext context;
 
2314
        if ( NS_FAILED( context.Push() ) ) {
 
2315
            break;
 
2316
        }
 
2317
        // Set href.
 
2318
        nsAutoString url; url.AssignWithConversion( args );
 
2319
        if ( NS_FAILED( location->SetHref( url ) ) ) {
 
2320
            break;
 
2321
        }
 
2322
        // Finally, if we get here, we're done.
 
2323
        return NS_OK;
 
2324
    } while ( PR_FALSE );
 
2325
 
 
2326
    nsCOMPtr<nsICmdLineHandler> handler(do_GetService("@mozilla.org/commandlinehandler/general-startup;1?type=browser", &rv));
 
2327
    if (NS_FAILED(rv)) return rv;
 
2328
 
 
2329
    nsXPIDLCString chromeUrlForTask;
 
2330
    rv = handler->GetChromeUrlForTask(getter_Copies(chromeUrlForTask));
 
2331
    if (NS_FAILED(rv)) return rv;
 
2332
 
 
2333
    // Last resort is to open a brand new window.
 
2334
    return OpenWindow( chromeUrlForTask, args );
 
2335
}
 
2336
 
 
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.
 
2343
NS_IMETHODIMP
 
2344
nsNativeAppSupportOS2::StartServerMode() {
 
2345
 
 
2346
    if (mShouldShowUI) {
 
2347
        // We dont have to anything anymore. The native UI
 
2348
        // will create the window
 
2349
        return NS_OK;
 
2350
    } else {
 
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 ) );
 
2356
        if ( win ) {
 
2357
            // Window already opened, don't need this special Nav window.
 
2358
            return NS_OK;
 
2359
        }
 
2360
    }
 
2361
 
 
2362
    // Since native UI wont create any window, we create a hidden window
 
2363
    // so thing work alright.
 
2364
 
 
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 ) {
 
2370
        return NS_OK;
 
2371
    }
 
2372
 
 
2373
    // Create the array for the arguments.
 
2374
    nsCOMPtr<nsISupportsArray> argArray = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
 
2375
    if ( !argArray ) {
 
2376
        return NS_OK;
 
2377
    }
 
2378
 
 
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" ) );
 
2383
 
 
2384
    // Put args into array.
 
2385
    if ( NS_FAILED( argArray->AppendElement( arg1 ) ) ||
 
2386
        NS_FAILED( argArray->AppendElement( arg2 ) ) ) {
 
2387
        return NS_OK;
 
2388
    }
 
2389
 
 
2390
    // Now open the window.
 
2391
    nsCOMPtr<nsIDOMWindow> newWindow;
 
2392
    ww->OpenWindow( 0,
 
2393
        "chrome://navigator/content",
 
2394
        "_blank",
 
2395
        "chrome,dialog=no,toolbar=no",
 
2396
        argArray,
 
2397
        getter_AddRefs( newWindow ) );
 
2398
 
 
2399
    if ( !newWindow ) {
 
2400
        return NS_OK;
 
2401
    }
 
2402
    mInitialWindowActive = PR_TRUE;
 
2403
 
 
2404
    // Hide this window by re-parenting it (to ensure it doesn't appear).
 
2405
    ReParent( newWindow, MessageWindow().getHWND() );
 
2406
 
 
2407
    return NS_OK;
 
2408
}
 
2409
 
 
2410
NS_IMETHODIMP
 
2411
nsNativeAppSupportOS2::SetIsServerMode( PRBool isServerMode ) {
 
2412
    return nsNativeAppSupportBase::SetIsServerMode( isServerMode );
 
2413
}
 
2414
 
 
2415
NS_IMETHODIMP
 
2416
nsNativeAppSupportOS2::OnLastWindowClosing() {
 
2417
 
 
2418
    if ( !mServerMode )
 
2419
        return NS_OK;
 
2420
 
 
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;
 
2425
        return NS_OK;
 
2426
    }
 
2427
 
 
2428
    nsresult rv;
 
2429
 
 
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 );
 
2437
    }
 
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);
 
2450
                }
 
2451
                return NS_OK;
 
2452
            }
 
2453
        }
 
2454
    }
 
2455
 
 
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);
 
2459
 
 
2460
    mForceProfileStartup = PR_TRUE;
 
2461
 
 
2462
    return NS_OK;
 
2463
}