Follow-on fix for bug 457825. Use sheet principal for agent and user sheets. r=dbaron...
[wine-gecko.git] / embedding / qa / testembed / TestEmbed.cpp
blob0829f98d4ad72a1da4a058598344eb37ee1ebef7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Chak Nanga <chak@netscape.com>
24 * Conrad Carlen <ccarlen@netscape.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 // File Overview....
42 // The typical MFC app, frame creation code + AboutDlg handling
44 // NS_InitEmbedding() is called in InitInstance()
45 //
46 // NS_TermEmbedding() is called in ExitInstance()
47 // ExitInstance() also takes care of cleaning up of
48 // multiple browser frame windows on app exit
51 // Code to handle the creation of a new browser window
53 // Next suggested file to look at : BrowserFrm.cpp
55 // Local Includes
56 #include "stdafx.h"
57 #include "BrowserImpl.h"
58 #include "TestEmbed.h"
59 #include "BrowserFrm.h"
60 #include "winEmbedFileLocProvider.h"
61 #include "ProfileMgr.h"
62 #include "BrowserView.h"
63 #include "nsIWindowWatcher.h"
64 #include "nsIComponentRegistrar.h"
65 #include "plstr.h"
66 #include "Preferences.h"
67 #include <io.h>
68 #include <fcntl.h>
70 #include "QAUtils.h"
72 #ifdef _DEBUG
73 #define new DEBUG_NEW
74 #undef THIS_FILE
75 static char THIS_FILE[] = __FILE__;
76 #endif
78 // this is for overriding the Mozilla default PromptService component
79 #include "PromptService.h"
80 #define kComponentsLibname "testEmbedComponents.dll"
81 #define NS_PROMPTSERVICE_CID \
82 {0xa2112d6a, 0x0e28, 0x421f, {0xb4, 0x6a, 0x25, 0xc0, 0xb3, 0x8, 0xcb, 0xd0}}
83 static NS_DEFINE_CID(kPromptServiceCID, NS_PROMPTSERVICE_CID);
85 BEGIN_MESSAGE_MAP(CTestEmbedApp, CWinApp)
86 //{{AFX_MSG_MAP(CTestEmbedApp)
87 ON_COMMAND(ID_NEW_BROWSER, OnNewBrowser)
88 ON_COMMAND(ID_MANAGE_PROFILES, OnManageProfiles)
89 ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
90 ON_COMMAND(ID_EDIT_PREFERENCES, OnEditPreferences)
91 // NOTE - the ClassWizard will add and remove mapping macros here.
92 // DO NOT EDIT what you see in these blocks of generated code!
93 //}}AFX_MSG_MAP
94 END_MESSAGE_MAP()
96 CTestEmbedApp::CTestEmbedApp() :
97 m_ProfileMgr(NULL)
99 mRefCnt = 1; // Start at one - nothing is going to addref this object
101 m_strHomePage = "";
103 m_iStartupPage = 0;
107 CTestEmbedApp theApp;
109 BOOL CTestEmbedApp::IsCmdLineSwitch(const char *pSwitch, BOOL bRemove)
111 // Search for the switch in the command line.
112 // Don't take it out of m_lpCmdLine by default
113 char *pFound = PL_strcasestr(m_lpCmdLine, pSwitch);
114 if(pFound == NULL ||
115 // Switch must be at beginning of command line
116 // or have a space in front of it to avoid
117 // mangling filenames
118 ( (pFound != m_lpCmdLine) &&
119 *(pFound-1) != ' ' ) )
121 return(FALSE);
124 if (bRemove)
126 // remove the flag from the command line
127 char *pTravEnd = pFound + strlen(pSwitch);
128 char *pTraverse = pFound;
130 *pTraverse = *pTravEnd;
131 while(*pTraverse != '\0')
133 pTraverse++;
134 pTravEnd++;
135 *pTraverse = *pTravEnd;
139 return(TRUE);
142 void CTestEmbedApp::ParseCmdLine()
144 // Show Debug Console?
145 if(IsCmdLineSwitch("-console"))
146 ShowDebugConsole();
149 /* Some Gecko interfaces are implemented as components, automatically
150 registered at application initialization. nsIPrompt is an example:
151 the default implementation uses XUL, not native windows. Embedding
152 apps can override the default implementation by implementing the
153 nsIPromptService interface and registering a factory for it with
154 the same CID and Contract ID as the default's.
156 Note that this example implements the service in a separate DLL,
157 replacing the default if the override DLL is present. This could
158 also have been done in the same module, without a separate DLL.
159 See the PowerPlant example for, well, an example.
161 nsresult CTestEmbedApp::OverrideComponents()
163 nsresult rv = NS_OK;
165 // replace Mozilla's default PromptService with our own, if the
166 // expected override DLL is present
167 HMODULE overlib = ::LoadLibrary(kComponentsLibname);
168 if (overlib) {
169 InitPromptServiceType InitLib;
170 MakeFactoryType MakeFactory;
171 InitLib = reinterpret_cast<InitPromptServiceType>(::GetProcAddress(overlib, kPromptServiceInitFuncName));
172 MakeFactory = reinterpret_cast<MakeFactoryType>(::GetProcAddress(overlib, kPromptServiceFactoryFuncName));
174 if (InitLib && MakeFactory) {
175 InitLib(overlib);
177 nsCOMPtr<nsIFactory> promptFactory;
178 rv = MakeFactory(getter_AddRefs(promptFactory));
179 if (NS_SUCCEEDED(rv)) {
180 nsCOMPtr<nsIComponentRegistrar> registrar;
181 NS_GetComponentRegistrar(getter_AddRefs(registrar));
182 if (registrar)
183 registrar->RegisterFactory(kPromptServiceCID,
184 "Prompt Service",
185 "@mozilla.org/embedcomp/prompt-service;1",
186 promptFactory);
188 } else
189 ::FreeLibrary(overlib);
192 return rv;
195 void CTestEmbedApp::ShowDebugConsole()
197 #ifdef _DEBUG
198 // Show console only in debug mode
200 if(! AllocConsole())
201 return;
203 // Redirect stdout to the console
204 int hCrtOut = _open_osfhandle(
205 (long) GetStdHandle(STD_OUTPUT_HANDLE),
206 _O_TEXT);
207 if(hCrtOut == -1)
208 return;
210 FILE *hfOut = _fdopen(hCrtOut, "w");
211 if(hfOut != NULL)
213 // Setup for unbuffered I/O so the console
214 // output shows up right away
215 *stdout = *hfOut;
216 setvbuf(stdout, NULL, _IONBF, 0);
219 // Redirect stderr to the console
220 int hCrtErr = _open_osfhandle(
221 (long) GetStdHandle(STD_ERROR_HANDLE),
222 _O_TEXT);
223 if(hCrtErr == -1)
224 return;
226 FILE *hfErr = _fdopen(hCrtErr, "w");
227 if(hfErr != NULL)
229 // Setup for unbuffered I/O so the console
230 // output shows up right away
231 *stderr = *hfErr;
232 setvbuf(stderr, NULL, _IONBF, 0);
234 #endif
237 // Initialize our MFC application and also init
238 // the Gecko embedding APIs
239 // Note that we're also init'ng the profile switching
240 // code here
241 // Then, create a new BrowserFrame and load our
242 // default homepage
244 BOOL CTestEmbedApp::InitInstance()
246 QAOutput("****************************************************\r\n");
248 ParseCmdLine();
250 Enable3dControls();
253 // 1. Determine the name of the dir from which the MRE based app is being run
254 // from [It's OK to do this even if you're not running in an MRE env]
256 // 2. Create an nsILocalFile out of it which will passed in to NS_InitEmbedding()
258 // Please see http://www.mozilla.org/projects/embedding/MRE.html
259 // for more info. on MRE
261 char curDir[_MAX_PATH+1];
262 ::GetCurrentDirectory(_MAX_PATH, curDir);
263 nsresult rv;
264 nsCOMPtr<nsILocalFile> mreAppDir;
265 rv = NS_NewNativeLocalFile(nsDependentCString(curDir), TRUE, getter_AddRefs(mreAppDir));
266 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create mreAppDir localfile");
268 // Take a look at
269 // http://www.mozilla.org/projects/xpcom/file_locations.html
270 // for more info on File Locations
272 winEmbedFileLocProvider *provider = new winEmbedFileLocProvider("TestEmbed");
273 if(!provider)
275 ASSERT(FALSE);
276 return FALSE;
279 rv = NS_InitEmbedding(mreAppDir, provider);
280 if(NS_FAILED(rv))
282 QAOutput("TestEmbed didn't start up.");
283 ASSERT(FALSE);
284 return FALSE;
286 else
287 QAOutput("TestEmbed started up.");
289 rv = OverrideComponents();
290 if(NS_FAILED(rv))
292 ASSERT(FALSE);
293 return FALSE;
297 rv = InitializeWindowCreator();
298 if (NS_FAILED(rv))
300 ASSERT(FALSE);
301 return FALSE;
304 if(!InitializeProfiles())
306 ASSERT(FALSE);
307 rv = NS_TermEmbedding();
308 RvTestResult(rv, "TestEmbed shutdown");
309 return FALSE;
312 rv = InitializePrefs();
313 if (NS_FAILED(rv))
315 ASSERT(FALSE);
316 NS_TermEmbedding();
317 return FALSE;
320 if(!CreateHiddenWindow())
322 ASSERT(FALSE);
323 rv = NS_TermEmbedding();
324 RvTestResult(rv, "TestEmbed shutdown");
325 return FALSE;
329 // Create the first browser frame window
330 OnNewBrowser();
332 return TRUE;
335 CBrowserFrame* CTestEmbedApp::CreateNewBrowserFrame(PRUint32 chromeMask,
336 PRInt32 x, PRInt32 y,
337 PRInt32 cx, PRInt32 cy,
338 PRBool bShowWindow)
340 // Setup a CRect with the requested window dimensions
341 CRect winSize(x, y, cx, cy);
343 // Use the Windows default if all are specified as -1
344 if(x == -1 && y == -1 && cx == -1 && cy == -1)
345 winSize = CFrameWnd::rectDefault;
347 // Load the window title from the string resource table
348 CString strTitle;
349 strTitle.LoadString(IDR_MAINFRAME);
351 // Now, create the browser frame
352 CBrowserFrame* pFrame = new CBrowserFrame(chromeMask);
353 if (!pFrame->Create(NULL, strTitle, WS_OVERLAPPEDWINDOW,
354 winSize, NULL, MAKEINTRESOURCE(IDR_MAINFRAME), 0L, NULL))
356 return NULL;
359 // load accelerator resource
360 pFrame->LoadAccelTable(MAKEINTRESOURCE(IDR_MAINFRAME));
362 // Show the window...
363 if(bShowWindow)
365 pFrame->ShowWindow(SW_SHOW);
366 pFrame->UpdateWindow();
369 // Add to the list of BrowserFrame windows
370 m_FrameWndLst.AddHead(pFrame);
372 return pFrame;
375 void CTestEmbedApp::OnNewBrowser()
377 CBrowserFrame *pBrowserFrame = CreateNewBrowserFrame();
379 //Load the HomePage into the browser view
380 if(pBrowserFrame && (GetStartupPageMode() == 1))
381 pBrowserFrame->m_wndBrowserView.LoadHomePage();
384 // This gets called anytime a BrowserFrameWindow is
385 // closed i.e. by choosing the "close" menu item from
386 // a window's system menu or by dbl clicking on the
387 // system menu box
389 // Sends a WM_QUIT to the hidden window which results
390 // in ExitInstance() being called and the app is
391 // properly cleaned up and shutdown
393 void CTestEmbedApp::RemoveFrameFromList(CBrowserFrame* pFrm, BOOL bCloseAppOnLastFrame/*= TRUE*/)
395 POSITION pos = m_FrameWndLst.Find(pFrm);
396 m_FrameWndLst.RemoveAt(pos);
398 // Send a WM_QUIT msg. to the hidden window if we've
399 // just closed the last browserframe window and
400 // if the bCloseAppOnLastFrame is TRUE. This be FALSE
401 // only in the case we're switching profiles
402 // Without this the hidden window will stick around
403 // i.e. the app will never die even after all the
404 // visible windows are gone.
405 if(m_FrameWndLst.GetCount() == 0 && bCloseAppOnLastFrame)
406 m_pMainWnd->PostMessage(WM_QUIT);
409 int CTestEmbedApp::ExitInstance()
411 // When File/Exit is chosen and if the user
412 // has opened multiple browser windows shut all
413 // of them down properly before exiting the app
415 CBrowserFrame* pBrowserFrame = NULL;
416 nsresult rv;
418 POSITION pos = m_FrameWndLst.GetHeadPosition();
419 while( pos != NULL )
421 pBrowserFrame = (CBrowserFrame *) m_FrameWndLst.GetNext(pos);
422 if(pBrowserFrame)
424 pBrowserFrame->ShowWindow(false);
425 pBrowserFrame->DestroyWindow();
428 m_FrameWndLst.RemoveAll();
430 if (m_pMainWnd)
431 m_pMainWnd->DestroyWindow();
433 delete m_ProfileMgr;
435 rv = NS_TermEmbedding();
436 if (NS_FAILED(rv))
437 QAOutput("TestEmbed didn't shut down.");
438 else
439 QAOutput("TestEmbed shut down.");
441 return 1;
444 BOOL CTestEmbedApp::OnIdle(LONG lCount)
446 CWinApp::OnIdle(lCount);
448 return FALSE;
451 void CTestEmbedApp::OnManageProfiles()
453 m_ProfileMgr->DoManageProfilesDialog(PR_FALSE);
456 void CTestEmbedApp::OnEditPreferences()
458 CPreferences prefs(_T("Preferences"));
460 prefs.m_startupPage.m_iStartupPage = m_iStartupPage;
461 prefs.m_startupPage.m_strHomePage = m_strHomePage;
463 if(prefs.DoModal() == IDOK)
465 // Update our member vars with these new pref values
466 m_iStartupPage = prefs.m_startupPage.m_iStartupPage;
467 m_strHomePage = prefs.m_startupPage.m_strHomePage;
469 // Save these changes to disk now
470 nsresult rv;
472 nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID,&rv));
474 if (NS_SUCCEEDED(rv))
476 prefs->SetIntPref("browser.startup.page", m_iStartupPage);
477 rv = prefs->SetCharPref("browser.startup.homepage", m_strHomePage);
478 if (NS_SUCCEEDED(rv))
479 rv = prefs->SavePrefFile(nsnull);
481 else
482 NS_ASSERTION(PR_FALSE, "Could not get preferences service");
486 BOOL CTestEmbedApp::InitializeProfiles()
488 m_ProfileMgr = new CProfileMgr;
489 if (!m_ProfileMgr)
490 return FALSE;
492 nsresult rv;
494 nsCOMPtr<nsIObserverService>observerService(do_GetService("@mozilla.org/observer-service;1",&rv));
495 if (NS_SUCCEEDED(rv))
497 observerService->AddObserver(this, "profile-approve-change", PR_TRUE);
498 observerService->AddObserver(this, "profile-change-teardown", PR_TRUE);
499 observerService->AddObserver(this, "profile-after-change", PR_TRUE);
502 m_ProfileMgr->StartUp();
504 return TRUE;
507 // When the profile switch happens, all open browser windows need to be
508 // closed.
509 // In order for that not to kill off the app, we just make the MFC app's
510 // mainframe be an invisible window which doesn't get closed on profile
511 // switches
512 BOOL CTestEmbedApp::CreateHiddenWindow()
514 CFrameWnd *hiddenWnd = new CFrameWnd;
515 if(!hiddenWnd)
516 return FALSE;
518 RECT bounds = { -10010, -10010, -10000, -10000 };
519 hiddenWnd->Create(NULL, "main", WS_DISABLED, bounds, NULL, NULL, 0, NULL);
520 m_pMainWnd = hiddenWnd;
522 return TRUE;
525 nsresult CTestEmbedApp::InitializePrefs()
527 nsresult rv;
529 nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID,&rv));
531 if (NS_SUCCEEDED(rv)) {
533 // We are using the default prefs from mozilla. If you were
534 // disributing your own, this would be done simply by editing
535 // the default pref files.
536 PRBool inited;
537 rv = prefs->GetBoolPref("mfcbrowser.prefs_inited", &inited);
538 if (NS_FAILED(rv) || !inited)
540 m_iStartupPage = 1;
541 m_strHomePage = "http://www.mozilla.org/projects/embedding";
543 prefs->SetIntPref("browser.startup.page", m_iStartupPage);
544 prefs->SetCharPref("browser.startup.homepage", m_strHomePage);
545 prefs->SetIntPref("font.size.variable.x-western", 16);
546 prefs->SetIntPref("font.size.fixed.x-western", 13);
547 rv = prefs->SetBoolPref("mfcbrowser.prefs_inited", PR_TRUE);
548 if (NS_SUCCEEDED(rv))
549 rv = prefs->SavePrefFile(nsnull);
551 else
553 // The prefs are present, read them in
554 prefs->GetIntPref("browser.startup.page", &m_iStartupPage);
556 CString strBuf;
557 char *pBuf = strBuf.GetBuffer(_MAX_PATH);
558 prefs->CopyCharPref("browser.startup.homepage", &pBuf);
559 strBuf.ReleaseBuffer(-1);
560 if(pBuf)
561 m_strHomePage = pBuf;
564 else
565 NS_ASSERTION(PR_FALSE, "Could not get preferences service");
567 return rv;
571 /* InitializeWindowCreator creates and hands off an object with a callback
572 to a window creation function. This will be used by Gecko C++ code
573 (never JS) to create new windows when no previous window is handy
574 to begin with. This is done in a few exceptional cases, like PSM code.
575 Failure to set this callback will only disable the ability to create
576 new windows under these circumstances. */
577 nsresult CTestEmbedApp::InitializeWindowCreator()
579 // give an nsIWindowCreator to the WindowWatcher service
580 nsCOMPtr<nsIWindowCreator> windowCreator(static_cast<nsIWindowCreator *>(this));
581 if (windowCreator) {
582 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
583 if (wwatch) {
584 wwatch->SetWindowCreator(windowCreator);
585 return NS_OK;
588 return NS_ERROR_FAILURE;
591 // ---------------------------------------------------------------------------
592 // CTestEmbedApp : nsISupports
593 // ---------------------------------------------------------------------------
595 NS_IMPL_THREADSAFE_ISUPPORTS3(CTestEmbedApp, nsIObserver, nsIWindowCreator, nsISupportsWeakReference)
597 // ---------------------------------------------------------------------------
598 // CTestEmbedApp : nsIObserver
599 // ---------------------------------------------------------------------------
601 // Mainly needed to support "on the fly" profile switching
603 NS_IMETHODIMP CTestEmbedApp::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
605 nsresult rv = NS_OK;
607 if (nsCRT::strcmp(aTopic, "profile-approve-change") == 0)
609 // Ask the user if they want to
610 int result = MessageBox(NULL, "Do you want to close all windows in order to switch the profile?", "Confirm", MB_YESNO | MB_ICONQUESTION);
611 if (result != IDYES)
613 nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
614 NS_ENSURE_TRUE(status, NS_ERROR_FAILURE);
615 status->VetoChange();
618 else if (nsCRT::strcmp(aTopic, "profile-change-teardown") == 0)
620 // Close all open windows. Alternatively, we could just call CBrowserWindow::Stop()
621 // on each. Either way, we have to stop all network activity on this phase.
623 POSITION pos = m_FrameWndLst.GetHeadPosition();
624 while( pos != NULL )
626 CBrowserFrame *pBrowserFrame = (CBrowserFrame *) m_FrameWndLst.GetNext(pos);
627 if(pBrowserFrame)
629 pBrowserFrame->ShowWindow(false);
631 // Passing in FALSE below so that we do not
632 // kill the main app during a profile switch
633 RemoveFrameFromList(pBrowserFrame, FALSE);
635 pBrowserFrame->DestroyWindow();
639 else if (nsCRT::strcmp(aTopic, "profile-after-change") == 0)
641 InitializePrefs(); // In case we have just switched to a newly created profile.
643 // Only make a new browser window on a switch. This also gets
644 // called at start up and we already make a window then.
645 if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("switch").get()))
646 OnNewBrowser();
648 return rv;
651 // ---------------------------------------------------------------------------
652 // CTestEmbedApp : nsIWindowCreator
653 // ---------------------------------------------------------------------------
654 NS_IMETHODIMP CTestEmbedApp::CreateChromeWindow(nsIWebBrowserChrome *parent,
655 PRUint32 chromeFlags,
656 nsIWebBrowserChrome **_retval)
658 // XXX we're ignoring the "parent" parameter
659 NS_ENSURE_ARG_POINTER(_retval);
660 *_retval = 0;
662 CBrowserFrame *pBrowserFrame = CreateNewBrowserFrame(chromeFlags);
663 if(pBrowserFrame) {
664 *_retval = static_cast<nsIWebBrowserChrome *>(pBrowserFrame->GetBrowserImpl());
665 NS_ADDREF(*_retval);
667 return NS_OK;
670 // AboutDlg Stuff
672 class CAboutDlg : public CDialog
674 public:
675 CAboutDlg();
677 enum { IDD = IDD_ABOUTBOX };
679 protected:
680 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
682 protected:
683 DECLARE_MESSAGE_MAP()
686 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
690 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
692 CDialog::DoDataExchange(pDX);
695 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
696 END_MESSAGE_MAP()
698 // Show the AboutDlg
699 void CTestEmbedApp::OnAppAbout()
701 CAboutDlg aboutDlg;
702 aboutDlg.DoModal();