Back to index

lightning-sunbird  0.9+nobinonly
MfcEmbed.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: Mozilla-sample-code 1.0
00004  *
00005  * Copyright (c) 2002 Netscape Communications Corporation and
00006  * other contributors
00007  *
00008  * Permission is hereby granted, free of charge, to any person obtaining a
00009  * copy of this Mozilla sample software and associated documentation files
00010  * (the "Software"), to deal in the Software without restriction, including
00011  * without limitation the rights to use, copy, modify, merge, publish,
00012  * distribute, sublicense, and/or sell copies of the Software, and to permit
00013  * persons to whom the Software is furnished to do so, subject to the
00014  * following conditions:
00015  *
00016  * The above copyright notice and this permission notice shall be included
00017  * in all copies or substantial portions of the Software.
00018  *
00019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00020  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00022  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00024  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00025  * DEALINGS IN THE SOFTWARE.
00026  *
00027  * Contributor(s):
00028  *   Chak Nanga <chak@netscape.com>
00029  *   Conrad Carlen <ccarlen@netscape.com>
00030  *
00031  * ***** END LICENSE BLOCK ***** */
00032 
00033 // File Overview....
00034 //
00035 // The typical MFC app, frame creation code + AboutDlg handling
00036 //
00037 // NS_InitEmbedding() is called in InitInstance()
00038 // 
00039 // NS_TermEmbedding() is called in ExitInstance()
00040 // ExitInstance() also takes care of cleaning up of
00041 // multiple browser frame windows on app exit
00042 //
00043 // Code to handle the creation of a new browser window
00044 
00045 // Next suggested file to look at : BrowserFrm.cpp
00046 
00047 // Local Includes
00048 #include "stdafx.h"
00049 #include "MfcEmbed.h"
00050 #include "nsXPCOM.h"
00051 #include "nsXPCOMGlue.h"
00052 #include "nsMemory.h"
00053 #include "nsIComponentRegistrar.h"
00054 #include "nsIFactory.h"
00055 #include "nsServiceManagerUtils.h"
00056 #include "BrowserFrm.h"
00057 #include "EditorFrm.h"
00058 #include "winEmbedFileLocProvider.h"
00059 #include "BrowserImpl.h"
00060 #include "nsIWindowWatcher.h"
00061 #include "plstr.h"
00062 #include "Preferences.h"
00063 #include <io.h>
00064 #include <fcntl.h>
00065 
00066 #ifdef USE_PROFILES
00067 #include "ProfileMgr.h"
00068 #else
00069 #include "nsProfileDirServiceProvider.h"
00070 #endif
00071 
00072 #ifdef MOZ_PROFILESHARING
00073 #include "nsIProfileSharingSetup.h"
00074 #endif
00075 
00076 #ifdef _BUILD_STATIC_BIN
00077 #include "nsStaticComponent.h"
00078 nsresult PR_CALLBACK
00079 app_getModuleInfo(nsStaticModuleInfo **info, PRUint32 *count);
00080 #endif
00081 
00082 
00083 #ifdef NS_TRACE_MALLOC
00084 #include "nsTraceMalloc.h"
00085 #endif
00086 
00087 #ifdef _DEBUG
00088 #define new DEBUG_NEW
00089 #undef THIS_FILE
00090 static char THIS_FILE[] = __FILE__;
00091 #endif
00092 
00093 // this is for overriding the Mozilla default PromptService component
00094 #include "PromptService.h"
00095 #define kComponentsLibname _T("mfcEmbedComponents.dll")
00096 #define NS_PROMPTSERVICE_CID \
00097  {0xa2112d6a, 0x0e28, 0x421f, {0xb4, 0x6a, 0x25, 0xc0, 0xb3, 0x8, 0xcb, 0xd0}}
00098 static NS_DEFINE_CID(kPromptServiceCID, NS_PROMPTSERVICE_CID);
00099 
00100 // this is for overriding the Mozilla default PrintingPromptService component
00101 #include "PrintingPromptService.h"
00102 #define NS_PRINTINGPROMPTSERVICE_CID \
00103  {0xe042570c, 0x62de, 0x4bb6, { 0xa6, 0xe0, 0x79, 0x8e, 0x3c, 0x7, 0xb4, 0xdf}}
00104 static NS_DEFINE_CID(kPrintingPromptServiceCID, NS_PRINTINGPROMPTSERVICE_CID);
00105 
00106 // this is for overriding the Mozilla default HelperAppLauncherDialog
00107 #include "HelperAppService.h"
00108 #define NS_HELPERAPPLAUNCHERDIALOG_CID \
00109     {0xf68578eb, 0x6ec2, 0x4169, {0xae, 0x19, 0x8c, 0x62, 0x43, 0xf0, 0xab, 0xe1}}
00110 static NS_DEFINE_CID(kHelperAppLauncherDialogCID, NS_HELPERAPPLAUNCHERDIALOG_CID);
00111 
00112 class CMfcEmbedCommandLine : public CCommandLineInfo
00113 {
00114 public:
00115 
00116     CMfcEmbedCommandLine(CMfcEmbedApp& app) : CCommandLineInfo(),
00117                                               mApp(app)
00118     {
00119     }
00120 
00121     // generic parser which bundles up flags and their parameters, to
00122     // pass to HandleFlag() or HandleNakedParameter()
00123     // if you're adding new parameters, please don't touch this
00124     // function and instead add your own handler below
00125     virtual void ParseParam(LPCTSTR szParam, BOOL bFlag, BOOL bLast)
00126     {
00127         CCommandLineInfo::ParseParam(szParam, bFlag, bLast);
00128         if (bFlag) {
00129             // advance past extra stuff like --foo
00130             while (*szParam && *szParam == '-')
00131                 szParam++;
00132 
00133             // previous argument was a flag too, so process that first
00134             if (mLastFlag.Length() != 0)
00135                 HandleFlag(mLastFlag);
00136             
00137             mLastFlag = szParam;
00138 
00139             // oops, no more arguments coming, so handle this now
00140             if (bLast)
00141                 HandleFlag(mLastFlag);
00142             
00143         } else {
00144             if (mLastFlag.Length() != 0)
00145                 HandleFlag(mLastFlag, szParam);
00146                 
00147             mLastFlag.Cut(0, PR_UINT32_MAX);
00148         }
00149     }
00150 
00151     // handle flag-based parameters
00152 #ifdef _UNICODE
00153     void HandleFlag(const nsAString& flag, const TCHAR * param = nsnull)
00154 #else
00155     void HandleFlag(const nsACString& flag, const TCHAR * param = nsnull)
00156 #endif
00157     {
00158         if (_tcscmp(flag.BeginReading(), _T("console")) == 0)
00159             DoConsole();
00160         else if (_tcscmp(flag.BeginReading(), _T("chrome")) == 0)
00161             DoChrome();
00162 #ifdef NS_TRACE_MALLOC
00163         else if (_tcscmp(flag.BeginReading(), _T("trace-malloc")) == 0)
00164         {
00165             USES_CONVERSION;
00166             DoTraceMalloc(flag, T2CA(param));
00167         }
00168 #endif
00169         // add new flag handlers here (please add a DoFoo() method below!)
00170     }
00171 
00172     void HandleNakedParameter(const char* flag) {
00173         // handle non-flag arguments here
00174     }
00175 
00176     // add your specific handlers here
00177     void DoConsole() {
00178         mApp.ShowDebugConsole();
00179     }
00180 
00181     void DoChrome() {
00182         mApp.m_bChrome = TRUE;
00183     }
00184 
00185 #ifdef NS_TRACE_MALLOC
00186     void DoTraceMalloc(const nsACString& flag, const char* param)
00187     {
00188         if (!param) {
00189             NS_WARNING("--trace-malloc needs a filename as a parameter");
00190             return;
00191         }
00192 
00193         // build up fake argv/argc arguments for tracemalloc stuff
00194         char* argv[] = { "mfcembed", "--trace-malloc",
00195                          NS_CONST_CAST(char*, param) };
00196         
00197         NS_TraceMallocStartupArgs(3, argv);
00198     }
00199 #endif
00200     
00201 private:
00202     // autostring is fine, this is a stack based object anyway
00203 #ifdef _UNICODE
00204     nsEmbedString mLastFlag;
00205 #else
00206     nsEmbedCString mLastFlag;
00207 #endif
00208 
00209     CMfcEmbedApp& mApp;
00210 };
00211 
00212 
00213 BEGIN_MESSAGE_MAP(CMfcEmbedApp, CWinApp)
00214     //{{AFX_MSG_MAP(CMfcEmbedApp)
00215     ON_COMMAND(ID_NEW_BROWSER, OnNewBrowser)
00216     ON_COMMAND(ID_NEW_EDITORWINDOW, OnNewEditor)
00217 #ifdef USE_PROFILES
00218     ON_COMMAND(ID_MANAGE_PROFILES, OnManageProfiles)
00219 #endif
00220     ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
00221     ON_COMMAND(ID_EDIT_PREFERENCES, OnEditPreferences)
00222     // NOTE - the ClassWizard will add and remove mapping macros here.
00223     //    DO NOT EDIT what you see in these blocks of generated code!
00224     //}}AFX_MSG_MAP
00225 END_MESSAGE_MAP()
00226 
00227 CMfcEmbedApp::CMfcEmbedApp()
00228 {
00229     mRefCnt = 1; // Start at one - nothing is going to addref this object
00230 
00231 #ifdef USE_PROFILES
00232     m_ProfileMgr = NULL;
00233 #endif
00234 
00235     m_strHomePage = "";
00236 
00237     m_iStartupPage = 0; 
00238 
00239     m_bChrome = FALSE;
00240 }
00241 
00242 CMfcEmbedApp theApp;
00243 
00244 /* Some Gecko interfaces are implemented as components, automatically
00245    registered at application initialization. nsIPrompt is an example:
00246    the default implementation uses XUL, not native windows. Embedding
00247    apps can override the default implementation by implementing the
00248    nsIPromptService interface and registering a factory for it with
00249    the same CID and Contract ID as the default's.
00250 
00251    Note that this example implements the service in a separate DLL,
00252    replacing the default if the override DLL is present. This could
00253    also have been done in the same module, without a separate DLL.
00254    See the PowerPlant example for, well, an example.
00255 */
00256 nsresult CMfcEmbedApp::OverrideComponents()
00257 {
00258     nsCOMPtr<nsIComponentRegistrar> compReg;
00259     nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(compReg));
00260     NS_ENSURE_SUCCESS(rv, rv);
00261     
00262     // replace Mozilla's default PromptService with our own, if the
00263     // expected override DLL is present
00264     HMODULE overlib = ::LoadLibrary(kComponentsLibname);
00265     if (overlib) {
00266         InitPromptServiceType InitLib;
00267         MakeFactoryType MakeFactory;
00268         InitLib = reinterpret_cast<InitPromptServiceType>(::GetProcAddress(overlib, kPromptServiceInitFuncName));
00269         MakeFactory = reinterpret_cast<MakeFactoryType>(::GetProcAddress(overlib, kPromptServiceFactoryFuncName));
00270 
00271         if (InitLib && MakeFactory) {
00272             InitLib(overlib);
00273 
00274             nsCOMPtr<nsIFactory> promptFactory;
00275             rv = MakeFactory(getter_AddRefs(promptFactory));
00276             if (NS_SUCCEEDED(rv)) {
00277                 compReg->RegisterFactory(kPromptServiceCID,
00278                                          "Prompt Service",
00279                                          "@mozilla.org/embedcomp/prompt-service;1",
00280                                          promptFactory);
00281             }
00282         } else
00283           ::FreeLibrary(overlib);
00284     }
00285 
00286     // Replace Mozilla's helper app launcher dialog with our own
00287     overlib = ::LoadLibrary(kComponentsLibname);
00288     if (overlib) {
00289         InitHelperAppDlgType InitLib;
00290         MakeFactoryType MakeFactory;
00291         InitLib = reinterpret_cast<InitHelperAppDlgType>(::GetProcAddress(overlib, kHelperAppDlgInitFuncName));
00292         MakeFactory = reinterpret_cast<MakeFactoryType>(::GetProcAddress(overlib, kHelperAppDlgFactoryFuncName));
00293 
00294         if (InitLib && MakeFactory) {
00295             InitLib(overlib);
00296 
00297             nsCOMPtr<nsIFactory> helperAppDlgFactory;
00298             rv = MakeFactory(getter_AddRefs(helperAppDlgFactory));
00299             if (NS_SUCCEEDED(rv))
00300                 compReg->RegisterFactory(kHelperAppLauncherDialogCID,
00301                                          "Helper App Launcher Dialog",
00302                                          "@mozilla.org/helperapplauncherdialog;1",
00303                                          helperAppDlgFactory);
00304         } else
00305           ::FreeLibrary(overlib);
00306     }
00307 
00308     // replace Mozilla's default PrintingPromptService with our own, if the
00309     // expected override DLL is present
00310     overlib = ::LoadLibrary(kComponentsLibname);
00311     if (overlib) {
00312         InitPrintingPromptServiceType InitLib;
00313         MakeFactoryType MakeFactory;
00314         InitLib = reinterpret_cast<InitPrintingPromptServiceType>(::GetProcAddress(overlib, kPrintingPromptServiceInitFuncName));
00315         MakeFactory = reinterpret_cast<MakeFactoryType>(::GetProcAddress(overlib, kPrintingPromptServiceFactoryFuncName));
00316 
00317         if (InitLib && MakeFactory) {
00318             InitLib(overlib);
00319 
00320             nsCOMPtr<nsIFactory> printingPromptFactory;
00321             rv = MakeFactory(getter_AddRefs(printingPromptFactory));
00322             if (NS_SUCCEEDED(rv))
00323                 compReg->RegisterFactory(kPrintingPromptServiceCID,
00324                                          "Printing Prompt Service",
00325                                          "@mozilla.org/embedcomp/printingprompt-service;1",
00326                                          printingPromptFactory);
00327         } else
00328           ::FreeLibrary(overlib);
00329     }
00330     return rv;
00331 }
00332 
00333 void CMfcEmbedApp::ShowDebugConsole()
00334 {
00335 #ifdef _DEBUG
00336     // Show console only in debug mode
00337 
00338     if(! AllocConsole())
00339         return;
00340 
00341     // Redirect stdout to the console
00342     int hCrtOut = _open_osfhandle(
00343                 (long) GetStdHandle(STD_OUTPUT_HANDLE),
00344                 _O_TEXT);
00345     if(hCrtOut == -1)
00346         return;
00347 
00348     FILE *hfOut = _fdopen(hCrtOut, "w");
00349     if(hfOut != NULL)
00350     {
00351         // Setup for unbuffered I/O so the console 
00352         // output shows up right away
00353         *stdout = *hfOut;
00354         setvbuf(stdout, NULL, _IONBF, 0); 
00355     }
00356 
00357     // Redirect stderr to the console
00358     int hCrtErr = _open_osfhandle(
00359                 (long) GetStdHandle(STD_ERROR_HANDLE),
00360                 _O_TEXT);
00361     if(hCrtErr == -1)
00362         return;
00363 
00364     FILE *hfErr = _fdopen(hCrtErr, "w");
00365     if(hfErr != NULL)
00366     {
00367         // Setup for unbuffered I/O so the console 
00368         // output shows up right away
00369         *stderr = *hfErr;
00370         setvbuf(stderr, NULL, _IONBF, 0); 
00371     }
00372 #endif
00373 }
00374 
00375 
00376 // Initialize our MFC application and also init
00377 // the Gecko embedding APIs
00378 // Note that we're also init'ng the profile switching
00379 // code here
00380 // Then, create a new BrowserFrame and load our
00381 // default homepage
00382 //
00383 BOOL CMfcEmbedApp::InitInstance()
00384 {
00385 #ifdef _BUILD_STATIC_BIN
00386     // Initialize XPCOM's module info table
00387     NSGetStaticModuleInfo = app_getModuleInfo;
00388 #endif
00389 
00390 #ifdef XPCOM_GLUE
00391     if (NS_FAILED(XPCOMGlueStartup(GRE_GetXPCOMPath()))) {
00392         MessageBox(NULL, "Could not initialize XPCOM. Perhaps the GRE\nis not installed or could not be found?", "MFCEmbed", MB_OK | MB_ICONERROR);
00393         return FALSE;
00394     }
00395 #endif
00396 
00397     CMfcEmbedCommandLine cmdLine(*this);
00398     ParseCommandLine(cmdLine);
00399     
00400     Enable3dControls();
00401 
00402     //
00403     // 1. Determine the name of the dir from which the GRE based app is being run
00404     // from [It's OK to do this even if you're not running in an GRE env]
00405     //
00406     // 2. Create an nsILocalFile out of it which will passed in to NS_InitEmbedding()
00407     //
00408     // Please see http://www.mozilla.org/projects/embedding/GRE.html
00409     // for more info. on GRE
00410 
00411     TCHAR path[_MAX_PATH+1];
00412     ::GetModuleFileName(0, path, _MAX_PATH);
00413     TCHAR* lastSlash = _tcsrchr(path, _T('\\'));
00414     if (!lastSlash) {
00415         NS_ERROR("No slash in module file name... something is wrong.");
00416         return FALSE;
00417     }
00418     *lastSlash = _T('\0');
00419 
00420     USES_CONVERSION;
00421     nsresult rv;
00422     nsCOMPtr<nsILocalFile> mreAppDir;
00423     rv = NS_NewNativeLocalFile(nsEmbedCString(T2A(path)), TRUE, getter_AddRefs(mreAppDir));
00424     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create mreAppDir localfile");
00425 
00426     // Take a look at 
00427     // http://www.mozilla.org/projects/xpcom/file_locations.html
00428     // for more info on File Locations
00429 
00430     CString strRes;
00431     strRes.LoadString(IDS_PROFILES_FOLDER_NAME);
00432     winEmbedFileLocProvider *provider = new winEmbedFileLocProvider(nsEmbedCString(strRes));
00433     if(!provider)
00434     {
00435         ASSERT(FALSE);
00436         return FALSE;
00437     }
00438 
00439     rv = NS_InitEmbedding(mreAppDir, provider);
00440     if(NS_FAILED(rv))
00441     {
00442         ASSERT(FALSE);
00443         return FALSE;
00444     }
00445 
00446     rv = OverrideComponents();
00447     if(NS_FAILED(rv))
00448     {
00449         ASSERT(FALSE);
00450         return FALSE;
00451     }
00452 
00453 
00454     rv = InitializeWindowCreator();
00455     if (NS_FAILED(rv))
00456     {
00457         ASSERT(FALSE);
00458         return FALSE;
00459     }
00460 
00461     if(!InitializeProfiles())
00462     {
00463         ASSERT(FALSE);
00464         NS_TermEmbedding();
00465         return FALSE;
00466     }
00467 
00468 
00469     if(!CreateHiddenWindow())
00470     {
00471         ASSERT(FALSE);
00472         NS_TermEmbedding();
00473         return FALSE;
00474     }
00475 
00476     // Create the first browser frame window
00477     OnNewBrowser();
00478 
00479     return TRUE;
00480 }
00481 
00482 CBrowserFrame* CMfcEmbedApp::CreateNewBrowserFrame(PRUint32 chromeMask,
00483                                                    PRInt32 x, PRInt32 y,
00484                                                    PRInt32 cx, PRInt32 cy,
00485                                                    PRBool bShowWindow,
00486                                                    PRBool bIsEditor
00487                                                    )
00488 {
00489     UINT resId = bIsEditor ? IDR_EDITOR : IDR_MAINFRAME;
00490 
00491     // Setup a CRect with the requested window dimensions
00492     CRect winSize(x, y, cx, cy);
00493 
00494     // Use the Windows default if all are specified as -1
00495     if(x == -1 && y == -1 && cx == -1 && cy == -1)
00496         winSize = CFrameWnd::rectDefault;
00497 
00498     // Load the window title from the string resource table
00499     CString strTitle;
00500     strTitle.LoadString(IDR_MAINFRAME);
00501 
00502     // Now, create the browser frame
00503     CBrowserFrame* pFrame = bIsEditor ? ( new  CEditorFrame(chromeMask) ) :
00504                         ( new  CBrowserFrame(chromeMask) );
00505     pFrame->SetEditable(bIsEditor);
00506 
00507     if (!pFrame->Create(NULL, strTitle, WS_OVERLAPPEDWINDOW, 
00508                     winSize, NULL, MAKEINTRESOURCE(resId), 0L, NULL))
00509     {
00510         return NULL;
00511     }
00512 
00513     // load accelerator resource
00514     pFrame->LoadAccelTable(MAKEINTRESOURCE(IDR_MAINFRAME));
00515 
00516     // Show the window...
00517     if(bShowWindow)
00518     {
00519         pFrame->ShowWindow(SW_SHOW);
00520         pFrame->UpdateWindow();
00521     }
00522 
00523     // Add to the list of BrowserFrame windows
00524     m_FrameWndLst.AddHead(pFrame);
00525 
00526     return pFrame;
00527 }
00528 
00529 void CMfcEmbedApp::OnNewBrowser()
00530 {
00531     CBrowserFrame *pBrowserFrame = CreateNewBrowserFrame();
00532 
00533     //Load the HomePage into the browser view
00534     if(pBrowserFrame && (GetStartupPageMode() == 1))
00535         pBrowserFrame->m_wndBrowserView.LoadHomePage();
00536 }
00537 
00538 void CMfcEmbedApp::OnNewEditor() 
00539 {
00540     CEditorFrame *pEditorFrame = (CEditorFrame *)CreateNewBrowserFrame(nsIWebBrowserChrome::CHROME_ALL, 
00541                                     -1, -1, -1, -1,
00542                                     PR_TRUE,PR_TRUE);
00543     if (pEditorFrame)
00544     {
00545         pEditorFrame->InitEditor();
00546         pEditorFrame->m_wndBrowserView.OpenURL("about:blank");
00547     }
00548 }
00549 
00550 // This gets called anytime a BrowserFrameWindow is
00551 // closed i.e. by choosing the "close" menu item from
00552 // a window's system menu or by dbl clicking on the
00553 // system menu box
00554 // 
00555 // Sends a WM_QUIT to the hidden window which results
00556 // in ExitInstance() being called and the app is
00557 // properly cleaned up and shutdown
00558 //
00559 void CMfcEmbedApp::RemoveFrameFromList(CBrowserFrame* pFrm, BOOL bCloseAppOnLastFrame/*= TRUE*/)
00560 {
00561     POSITION pos = m_FrameWndLst.Find(pFrm);
00562     m_FrameWndLst.RemoveAt(pos);
00563 
00564     // Send a WM_QUIT msg. to the hidden window if we've
00565     // just closed the last browserframe window and
00566     // if the bCloseAppOnLastFrame is TRUE. This be FALSE
00567     // only in the case we're switching profiles
00568     // Without this the hidden window will stick around
00569     // i.e. the app will never die even after all the 
00570     // visible windows are gone.
00571     if(m_FrameWndLst.GetCount() == 0 && bCloseAppOnLastFrame)
00572         m_pMainWnd->PostMessage(WM_QUIT);
00573 }
00574 
00575 int CMfcEmbedApp::ExitInstance()
00576 {
00577     // When File/Exit is chosen and if the user
00578     // has opened multiple browser windows shut all
00579     // of them down properly before exiting the app
00580 
00581     CBrowserFrame* pBrowserFrame = NULL;
00582 
00583     POSITION pos = m_FrameWndLst.GetHeadPosition();
00584     while( pos != NULL )
00585     {
00586         pBrowserFrame = (CBrowserFrame *) m_FrameWndLst.GetNext(pos);
00587         if(pBrowserFrame)
00588         {
00589             pBrowserFrame->ShowWindow(false);
00590             pBrowserFrame->DestroyWindow();
00591         }
00592     }
00593     m_FrameWndLst.RemoveAll();
00594 
00595     if (m_pMainWnd)
00596         m_pMainWnd->DestroyWindow();
00597 
00598 #ifdef USE_PROFILES
00599     delete m_ProfileMgr;
00600 #else
00601     if (m_ProfileDirServiceProvider)
00602     {
00603         m_ProfileDirServiceProvider->Shutdown();
00604         NS_RELEASE(m_ProfileDirServiceProvider);
00605     }
00606 #endif
00607 
00608     NS_TermEmbedding();
00609 
00610 #ifdef XPCOM_GLUE
00611     XPCOMGlueShutdown();
00612 #endif
00613 
00614     return 1;
00615 }
00616 
00617 BOOL CMfcEmbedApp::OnIdle(LONG lCount)
00618 {
00619     CWinApp::OnIdle(lCount);
00620 
00621     return FALSE;
00622 }
00623 
00624 void CMfcEmbedApp::OnManageProfiles()
00625 {
00626 #ifdef USE_PROFILES
00627     m_ProfileMgr->DoManageProfilesDialog(PR_FALSE);
00628 #endif
00629 }
00630 
00631 void CMfcEmbedApp::OnEditPreferences()
00632 {
00633     CPreferences prefs(_T("Preferences"));
00634     
00635     prefs.m_startupPage.m_iStartupPage = m_iStartupPage;
00636     prefs.m_startupPage.m_strHomePage = m_strHomePage;   
00637 
00638     if(prefs.DoModal() == IDOK)
00639     {
00640         // Update our member vars with these new pref values
00641         m_iStartupPage = prefs.m_startupPage.m_iStartupPage;
00642         m_strHomePage = prefs.m_startupPage.m_strHomePage;
00643 
00644         // Save these changes to disk now
00645         nsresult rv;
00646         nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID, &rv));
00647         if (NS_SUCCEEDED(rv)) 
00648         {
00649             USES_CONVERSION;
00650             prefs->SetIntPref("browser.startup.page", m_iStartupPage);
00651             rv = prefs->SetCharPref("browser.startup.homepage", T2CA(m_strHomePage));
00652             if (NS_SUCCEEDED(rv))
00653                 rv = prefs->SavePrefFile(nsnull);
00654         }
00655         else
00656             NS_ASSERTION(PR_FALSE, "Could not get preferences service");
00657     }
00658 }
00659 
00660 BOOL CMfcEmbedApp::InitializeProfiles()
00661 {
00662 
00663 #ifdef MOZ_PROFILESHARING
00664     // If we are using profile sharing, get the sharing setup service
00665     nsCOMPtr<nsIProfileSharingSetup> sharingSetup =
00666         do_GetService("@mozilla.org/embedcomp/profile-sharing-setup;1");
00667     if (sharingSetup)
00668     {
00669         USES_CONVERSION;
00670         CString strRes;
00671         strRes.LoadString(IDS_PROFILES_NONSHARED_NAME);
00672         nsEmbedString nonSharedName(T2W(strRes));
00673         sharingSetup->EnableSharing(nonSharedName);
00674     }
00675 #endif
00676 
00677     nsCOMPtr<nsIObserverService> observerService = 
00678              do_GetService("@mozilla.org/observer-service;1");
00679     if (!observerService)
00680         return FALSE;
00681 
00682     // Both the profile mgr and standalone nsProfileDirServiceProvider
00683     // send this notification.
00684     observerService->AddObserver(this, "profile-after-change", PR_TRUE);
00685 
00686 #ifdef USE_PROFILES
00687     m_ProfileMgr = new CProfileMgr;
00688     if (!m_ProfileMgr)
00689         return FALSE;
00690 
00691     observerService->AddObserver(this, "profile-approve-change", PR_TRUE);
00692     observerService->AddObserver(this, "profile-change-teardown", PR_TRUE);
00693 
00694     m_ProfileMgr->StartUp();
00695 #else
00696     nsresult rv;
00697     nsCOMPtr<nsIFile> appDataDir;
00698     NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
00699                                 getter_AddRefs(appDataDir));
00700     if (!appDataDir)
00701         return FALSE;
00702     nsCOMPtr<nsProfileDirServiceProvider> profProvider;
00703     NS_NewProfileDirServiceProvider(PR_TRUE, getter_AddRefs(profProvider));
00704     if (!profProvider)
00705         return FALSE;
00706     profProvider->Register();    
00707     nsCOMPtr<nsILocalFile> localAppDataDir(do_QueryInterface(appDataDir));
00708     rv = profProvider->SetProfileDir(localAppDataDir);
00709     if (NS_FAILED(rv))
00710         return FALSE;
00711     NS_ADDREF(m_ProfileDirServiceProvider = profProvider);
00712 #endif
00713 
00714     return TRUE;
00715 }
00716 
00717 // When the profile switch happens, all open browser windows need to be 
00718 // closed. 
00719 // In order for that not to kill off the app, we just make the MFC app's 
00720 // mainframe be an invisible window which doesn't get closed on profile 
00721 // switches
00722 BOOL CMfcEmbedApp::CreateHiddenWindow()
00723 {
00724     CFrameWnd *hiddenWnd = new CFrameWnd;
00725     if(!hiddenWnd)
00726         return FALSE;
00727 
00728     RECT bounds = { -10010, -10010, -10000, -10000 };
00729     hiddenWnd->Create(NULL, _T("main"), WS_DISABLED, bounds, NULL, NULL, 0, NULL);
00730     m_pMainWnd = hiddenWnd;
00731 
00732     return TRUE;
00733 }
00734 
00735 nsresult CMfcEmbedApp::InitializePrefs()
00736 {
00737    nsresult rv;
00738    nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID, &rv));
00739    if (NS_SUCCEEDED(rv)) {      
00740 
00741         // We are using the default prefs from mozilla. If you were
00742         // disributing your own, this would be done simply by editing
00743         // the default pref files.
00744         
00745         PRBool inited;
00746         rv = prefs->GetBoolPref("mfcbrowser.prefs_inited", &inited);
00747         if (NS_FAILED(rv) || !inited)
00748         {
00749             USES_CONVERSION;
00750             m_iStartupPage = 1;
00751             m_strHomePage = "http://www.mozilla.org/projects/embedding";
00752 
00753             prefs->SetIntPref("browser.startup.page", m_iStartupPage);
00754             prefs->SetCharPref("browser.startup.homepage", T2CA(m_strHomePage));
00755             prefs->SetIntPref("font.size.variable.x-western", 16);
00756             prefs->SetIntPref("font.size.fixed.x-western", 13);
00757             rv = prefs->SetBoolPref("mfcbrowser.prefs_inited", PR_TRUE);
00758             if (NS_SUCCEEDED(rv))
00759                 rv = prefs->SavePrefFile(nsnull);
00760         }
00761         else
00762         {
00763             // The prefs are present, read them in
00764 
00765             prefs->GetIntPref("browser.startup.page", &m_iStartupPage);
00766 
00767             char* str = nsnull;
00768             prefs->GetCharPref("browser.startup.homepage", &str);
00769             if (str)
00770             {
00771                 USES_CONVERSION;
00772                 m_strHomePage = A2CT(str);
00773             }
00774             else
00775             {
00776                 m_strHomePage.Empty();
00777             }
00778             nsMemory::Free(str);
00779         }       
00780     }
00781     else
00782         NS_ASSERTION(PR_FALSE, "Could not get preferences service");
00783         
00784     return rv;
00785 }
00786 
00787 
00788 /* InitializeWindowCreator creates and hands off an object with a callback
00789    to a window creation function. This will be used by Gecko C++ code
00790    (never JS) to create new windows when no previous window is handy
00791    to begin with. This is done in a few exceptional cases, like PSM code.
00792    Failure to set this callback will only disable the ability to create
00793    new windows under these circumstances. */
00794 nsresult CMfcEmbedApp::InitializeWindowCreator()
00795 {
00796   // give an nsIWindowCreator to the WindowWatcher service
00797   nsCOMPtr<nsIWindowCreator> windowCreator(NS_STATIC_CAST(nsIWindowCreator *, this));
00798   if (windowCreator) {
00799     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00800     if (wwatch) {
00801       wwatch->SetWindowCreator(windowCreator);
00802       return NS_OK;
00803     }
00804   }
00805   return NS_ERROR_FAILURE;
00806 }
00807 
00808 // ---------------------------------------------------------------------------
00809 //  CMfcEmbedApp : nsISupports
00810 // ---------------------------------------------------------------------------
00811 
00812 NS_IMPL_ISUPPORTS3(CMfcEmbedApp, nsIObserver, nsIWindowCreator, nsISupportsWeakReference)
00813 
00814 // ---------------------------------------------------------------------------
00815 //  CMfcEmbedApp : nsIObserver
00816 // ---------------------------------------------------------------------------
00817 
00818 // Mainly needed to support "on the fly" profile switching
00819 
00820 NS_IMETHODIMP CMfcEmbedApp::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00821 {
00822     nsresult rv = NS_OK;
00823     
00824     if (strcmp(aTopic, "profile-approve-change") == 0)
00825     {
00826         // Ask the user if they want to
00827         int result = MessageBox(NULL,
00828             _T("Do you want to close all windows in order to switch the profile?"),
00829             _T("Confirm"), MB_YESNO | MB_ICONQUESTION);
00830         if (result != IDYES)
00831         {
00832             nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
00833             NS_ENSURE_TRUE(status, NS_ERROR_FAILURE);
00834             status->VetoChange();
00835         }
00836     }
00837     else if (strcmp(aTopic, "profile-change-teardown") == 0)
00838     {
00839         // Close all open windows. Alternatively, we could just call CBrowserWindow::Stop()
00840         // on each. Either way, we have to stop all network activity on this phase.
00841         
00842         POSITION pos = m_FrameWndLst.GetHeadPosition();
00843         while( pos != NULL )
00844         {
00845             CBrowserFrame *pBrowserFrame = (CBrowserFrame *) m_FrameWndLst.GetNext(pos);
00846             if(pBrowserFrame)
00847             {
00848                 pBrowserFrame->ShowWindow(false);
00849 
00850                 // Passing in FALSE below so that we do not
00851                 // kill the main app during a profile switch
00852                 RemoveFrameFromList(pBrowserFrame, FALSE);
00853 
00854                 pBrowserFrame->DestroyWindow();
00855             }
00856         }
00857     }
00858     else if (strcmp(aTopic, "profile-after-change") == 0)
00859     {
00860         InitializePrefs(); // In case we have just switched to a newly created profile.
00861         
00862         // Only make a new browser window on a switch. This also gets
00863         // called at start up and we already make a window then.
00864         if (!wcscmp(someData, L"switch"))      
00865             OnNewBrowser();
00866     }
00867     return rv;
00868 }
00869 
00870 // ---------------------------------------------------------------------------
00871 //  CMfcEmbedApp : nsIWindowCreator
00872 // ---------------------------------------------------------------------------
00873 NS_IMETHODIMP CMfcEmbedApp::CreateChromeWindow(nsIWebBrowserChrome *parent,
00874                                                PRUint32 chromeFlags,
00875                                                nsIWebBrowserChrome **_retval)
00876 {
00877   // XXX we're ignoring the "parent" parameter
00878   NS_ENSURE_ARG_POINTER(_retval);
00879   *_retval = 0;
00880 
00881   CBrowserFrame *pBrowserFrame = CreateNewBrowserFrame(chromeFlags);
00882   if(pBrowserFrame) {
00883     *_retval = NS_STATIC_CAST(nsIWebBrowserChrome *, pBrowserFrame->GetBrowserImpl());
00884     NS_ADDREF(*_retval);
00885   }
00886   return NS_OK;
00887 }
00888 
00889 // AboutDlg Stuff
00890 
00891 class CAboutDlg : public CDialog
00892 {
00893 public:
00894     CAboutDlg();
00895 
00896     enum { IDD = IDD_ABOUTBOX };
00897 
00898 protected:
00899     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
00900 
00901 protected:
00902     DECLARE_MESSAGE_MAP()
00903 };
00904 
00905 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
00906 {
00907 }
00908 
00909 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
00910 {
00911     CDialog::DoDataExchange(pDX);
00912 }
00913 
00914 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
00915 END_MESSAGE_MAP()
00916 
00917 // Show the AboutDlg
00918 void CMfcEmbedApp::OnAppAbout()
00919 {
00920     CAboutDlg aboutDlg;
00921     aboutDlg.DoModal();
00922 }