Back to index

lightning-sunbird  0.9+nobinonly
nsBrowserInstance.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *   Travis Bogard <travis@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 // Local Includes
00041 #include "nsBrowserInstance.h"
00042 
00043 // Helper Includes
00044 #include "nsIGenericFactory.h"
00045 
00046 // Interfaces Needed
00047 #include "nsIBaseWindow.h"
00048 #include "nsIWebNavigationInfo.h"
00049 #include "nsDocShellCID.h"
00050 #include "nsIDocShell.h"
00051 #include "nsIDocShellTreeItem.h"
00052 #include "nsIHttpProtocolHandler.h"
00053 #include "nsISHistory.h"
00054 #include "nsIWebNavigation.h"
00055 
00057 
00058 #include "nsIObserver.h"
00059 #include "pratom.h"
00060 #include "prprf.h"
00061 #include "nsIComponentManager.h"
00062 #include "nsCRT.h"
00063 
00064 #include "nsIScriptContext.h"
00065 #include "nsIScriptGlobalObject.h"
00066 #include "nsIDOMDocument.h"
00067 #include "nsIDOMWindowInternal.h"
00068 
00069 #include "nsIContentViewer.h"
00070 #include "nsIContentViewerEdit.h"
00071 #include "nsIWebBrowserChrome.h"
00072 #include "nsIWindowWatcher.h"
00073 #include "nsCOMPtr.h"
00074 #include "nsXPIDLString.h"
00075 #include "nsReadableUtils.h"
00076 
00077 #include "nsIPref.h"
00078 #include "nsIServiceManager.h"
00079 #include "nsIURL.h"
00080 #include "nsIIOService.h"
00081 #include "nsIWidget.h"
00082 #include "plevent.h"
00083 #include "plstr.h"
00084 
00085 #include "nsIAppStartup.h"
00086 
00087 #include "nsIBrowserHistory.h"
00088 #include "nsDocShellCID.h"
00089 
00090 #include "nsIObserverService.h"
00091 
00092 #include "nsILocalFile.h"
00093 #include "nsDirectoryServiceDefs.h"
00094 
00095 #include "nsNetUtil.h"
00096 #ifndef MOZ_XUL_APP
00097 #include "nsICmdLineService.h"
00098 #endif
00099 
00100 // Stuff to implement file download dialog.
00101 #include "nsIProxyObjectManager.h" 
00102 
00103 #include "nsXPFEComponentsCID.h"
00104 
00105 // If DEBUG, NS_BUILD_REFCNT_LOGGING, MOZ_PERF_METRICS, or MOZ_JPROF is
00106 // defined, enable the PageCycler.
00107 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(MOZ_PERF_METRICS) || defined(MOZ_JPROF)
00108 #define ENABLE_PAGE_CYCLER
00109 #endif
00110 
00111 /* Define Class IDs */
00112 static NS_DEFINE_CID(kPrefServiceCID,           NS_PREF_CID);
00113 static NS_DEFINE_CID(kProxyObjectManagerCID,    NS_PROXYEVENT_MANAGER_CID);
00114 
00115 #ifdef DEBUG                                                           
00116 static int APP_DEBUG = 0; // Set to 1 in debugger to turn on debugging.
00117 #else                                                                  
00118 #define APP_DEBUG 0                                                    
00119 #endif                                                                 
00120 
00121 
00122 #define PREF_HOMEPAGE_OVERRIDE_URL "startup.homepage_override_url"
00123 #define PREF_HOMEPAGE_OVERRIDE_MSTONE "browser.startup.homepage_override.mstone"
00124 #define PREF_BROWSER_STARTUP_PAGE "browser.startup.page"
00125 #define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
00126 
00127 const char *kIgnoreOverrideMilestone = "ignore";
00128 
00129 //*****************************************************************************
00130 //***    PageCycler: Object Management
00131 //*****************************************************************************
00132 
00133 #ifdef ENABLE_PAGE_CYCLER
00134 #include "nsIProxyObjectManager.h"
00135 #include "nsITimer.h"
00136 
00137 static void TimesUp(nsITimer *aTimer, void *aClosure);
00138   // Timer callback: called when the timer fires
00139 
00140 class PageCycler : public nsIObserver {
00141 public:
00142   NS_DECL_ISUPPORTS
00143 
00144   PLEvent mEvent;
00145 
00146   PageCycler(nsBrowserInstance* appCore, const char *aTimeoutValue = nsnull, const char *aWaitValue = nsnull)
00147     : mAppCore(appCore), mBuffer(nsnull), mCursor(nsnull), mTimeoutValue(0), mWaitValue(1 /*sec*/) { 
00148     NS_ADDREF(mAppCore);
00149     if (aTimeoutValue){
00150       mTimeoutValue = atol(aTimeoutValue);
00151     }
00152     if (aWaitValue) {
00153       mWaitValue = atol(aWaitValue);
00154     }
00155   }
00156 
00157   virtual ~PageCycler() { 
00158     if (mBuffer) delete[] mBuffer;
00159     NS_RELEASE(mAppCore);
00160   }
00161 
00162   nsresult Init(const char* nativePath) {
00163     nsresult rv;
00164     if (!mFile) {
00165       nsCOMPtr<nsIFile> aFile;
00166       rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
00167                                   getter_AddRefs(aFile));
00168       if (NS_FAILED(rv)) return rv;
00169 
00170       mFile = do_QueryInterface(aFile);
00171       NS_ASSERTION(mFile, "QI to nsILocalFile should not fail");
00172       rv = mFile->AppendRelativeNativePath(nsDependentCString(nativePath));
00173       if (NS_FAILED(rv)) return rv;
00174     }
00175 
00176     nsCOMPtr<nsIInputStream> inStr;
00177     rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), mFile);
00178     if (NS_FAILED(rv)) return rv;
00179 
00180     PRUint32 avail;
00181     rv = inStr->Available(&avail);
00182     if (NS_FAILED(rv)) return rv;
00183 
00184     mBuffer = new char[avail + 1];
00185     if (mBuffer == nsnull)
00186       return NS_ERROR_OUT_OF_MEMORY;
00187     PRUint32 amt;
00188     rv = inStr->Read(mBuffer, avail, &amt);
00189     if (NS_FAILED(rv)) return rv;
00190     NS_ASSERTION(amt == avail, "Didn't get the whole file.");
00191     mBuffer[avail] = '\0';
00192     mCursor = mBuffer;
00193 
00194     nsCOMPtr<nsIObserverService> obsServ = 
00195              do_GetService("@mozilla.org/observer-service;1", &rv);
00196     if (NS_FAILED(rv)) return rv;
00197     rv = obsServ->AddObserver(this, "EndDocumentLoad", PR_FALSE );
00198     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add self to observer service");
00199     return rv; 
00200   }
00201 
00202   nsresult GetNextURL(nsString& result) {
00203     result.AssignWithConversion(mCursor);
00204     PRInt32 pos = result.Find(NS_LINEBREAK);
00205     if (pos > 0) {
00206       result.Truncate(pos);
00207       mLastRequest.Assign(result);
00208       mCursor += pos + NS_LINEBREAK_LEN;
00209       return NS_OK;
00210     }
00211     else if ( !result.IsEmpty() ) {
00212       // no more URLs after this one
00213       mCursor += result.Length(); // Advance cursor to terminating '\0'
00214       mLastRequest.Assign(result);
00215       return NS_OK;
00216     }
00217     else {
00218       // no more URLs, so quit the browser
00219       nsresult rv;
00220       // make sure our timer is stopped first
00221       StopTimer();
00222 
00223       // XXX This needs to do a whole bunch of other stuff that
00224       // globalOverlay.js's goQuitApplication does.
00225       nsCOMPtr<nsIAppStartup> appStartup = 
00226                do_GetService(NS_APPSTARTUP_CONTRACTID, &rv);
00227       if(NS_FAILED(rv)) return rv;
00228       nsCOMPtr<nsIProxyObjectManager> pIProxyObjectManager = 
00229                do_GetService(kProxyObjectManagerCID, &rv);
00230       if(NS_FAILED(rv)) return rv;
00231       nsCOMPtr<nsIAppStartup> appStartupProxy;
00232       rv = pIProxyObjectManager->GetProxyForObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIAppStartup),
00233                                                    appStartup, PROXY_ASYNC | PROXY_ALWAYS,
00234                                                    getter_AddRefs(appStartupProxy));
00235 
00236       (void)appStartupProxy->Quit(nsIAppStartup::eAttemptQuit);
00237       return NS_ERROR_FAILURE;
00238     }
00239   }
00240 
00241   NS_IMETHOD Observe(nsISupports* aSubject, 
00242                      const char* aTopic,
00243                      const PRUnichar* someData) {
00244     nsresult rv = NS_OK;
00245     nsString data(someData);
00246     if (data.Find(mLastRequest) == 0) {
00247       char* dataStr = ToNewCString(data);
00248       printf("########## PageCycler loaded (%d ms): %s\n", 
00249              PR_IntervalToMilliseconds(PR_IntervalNow() - mIntervalTime), 
00250              dataStr);
00251       NS_Free(dataStr);
00252 
00253       nsAutoString url;
00254       rv = GetNextURL(url);
00255       if (NS_SUCCEEDED(rv)) {
00256         // stop previous timer
00257         StopTimer();
00258         if (aSubject == this){
00259           // if the aSubject arg is 'this' then we were called by the Timer
00260           // Stop the current load and move on to the next
00261           nsCOMPtr<nsIDocShell> docShell;
00262           mAppCore->GetContentAreaDocShell(getter_AddRefs(docShell));
00263 
00264           nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
00265           if(webNav)
00266             webNav->Stop(nsIWebNavigation::STOP_ALL);
00267         }
00268 
00269         // We need to enqueue an event to load the next page,
00270         // otherwise we'll run the risk of confusing the docshell
00271         // (which notifies observers before propagating the
00272         // DocumentEndLoad up to parent docshells).
00273         nsCOMPtr<nsIEventQueueService> eqs
00274           = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID);
00275 
00276         rv = NS_ERROR_FAILURE;
00277 
00278         if (eqs) {
00279           nsCOMPtr<nsIEventQueue> eq;
00280           eqs->ResolveEventQueue(NS_UI_THREAD_EVENTQ, getter_AddRefs(eq));
00281           if (eq) {
00282             rv = eq->InitEvent(&mEvent, this, HandleAsyncLoadEvent,
00283                                DestroyAsyncLoadEvent);
00284 
00285             if (NS_SUCCEEDED(rv)) {
00286               rv = eq->PostEvent(&mEvent);
00287             }
00288           }
00289         }
00290 
00291         if (NS_FAILED(rv)) {
00292           printf("######### PageCycler couldn't asynchronously load: %s\n", NS_ConvertUCS2toUTF8(mLastRequest).get());
00293         }
00294       }
00295     }
00296     else {
00297       char* dataStr = ToNewCString(data);
00298       printf("########## PageCycler possible failure for: %s\n", dataStr);
00299       NS_Free(dataStr);
00300     }
00301     return rv;
00302   }
00303 
00304   static void* PR_CALLBACK
00305   HandleAsyncLoadEvent(PLEvent* aEvent)
00306   {
00307     // This is the callback that actually loads the page
00308     PageCycler* self = NS_STATIC_CAST(PageCycler*, PL_GetEventOwner(aEvent));
00309 
00310     // load the URL
00311     const PRUnichar* url = self->mLastRequest.get();
00312     printf("########## PageCycler starting: %s\n", NS_ConvertUCS2toUTF8(url).get());
00313 
00314     self->mIntervalTime = PR_IntervalNow();
00315     self->mAppCore->LoadUrl(url);
00316 
00317     // start new timer
00318     self->StartTimer();
00319     return nsnull;
00320   }
00321 
00322   static void PR_CALLBACK
00323   DestroyAsyncLoadEvent(PLEvent* aEvent) { /*no-op*/ }
00324 
00325   const nsAutoString &GetLastRequest( void )
00326   { 
00327     return mLastRequest; 
00328   }
00329 
00330   // StartTimer: if mTimeoutValue is positive, then create a new timer
00331   //             that will call the callback fcn 'TimesUp' to keep us cycling
00332   //             through the URLs
00333   nsresult StartTimer(void)
00334   {
00335     nsresult rv=NS_OK;
00336     if (mTimeoutValue > 0){
00337       mShutdownTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
00338       NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create timer for PageCycler...");
00339       if (NS_SUCCEEDED(rv) && mShutdownTimer){
00340         mShutdownTimer->InitWithFuncCallback(TimesUp, (void *)this, mTimeoutValue*1000,
00341                                              nsITimer::TYPE_ONE_SHOT);
00342       }
00343     }
00344     return rv;
00345   }
00346 
00347   // StopTimer: if there is a timer, cancel it
00348   nsresult StopTimer(void)
00349   {
00350     if (mShutdownTimer){
00351       mShutdownTimer->Cancel();
00352     }
00353     return NS_OK;
00354   }
00355 
00356 protected:
00357   nsBrowserInstance*    mAppCore;
00358   nsCOMPtr<nsILocalFile> mFile;
00359   char*                 mBuffer;
00360   char*                 mCursor;
00361   nsAutoString          mLastRequest;
00362   nsCOMPtr<nsITimer>    mShutdownTimer;
00363   PRUint32              mTimeoutValue;
00364   PRUint32              mWaitValue;
00365   PRIntervalTime        mIntervalTime;
00366 };
00367 
00368 NS_IMPL_ISUPPORTS1(PageCycler, nsIObserver)
00369 
00370 // TimesUp: callback for the PageCycler timer: called when we have
00371 // waited too long for the page to finish loading.
00372 // 
00373 // The aClosure argument is actually the PageCycler, so use it to stop
00374 // the timer and call the Observe fcn to move on to the next URL.  Note
00375 // that we pass the PageCycler instance as the aSubject argument to the
00376 // Observe function. This is our indication that the Observe method is
00377 // being called after a timeout, allowing the PageCycler to do any
00378 // necessary processing before moving on.
00379 
00380 void TimesUp(nsITimer *aTimer, void *aClosure)
00381 {
00382   if(aClosure){
00383     char urlBuf[64];
00384     PageCycler *pCycler = (PageCycler *)aClosure;
00385     pCycler->StopTimer();
00386     pCycler->GetLastRequest().ToCString( urlBuf, sizeof(urlBuf), 0 );
00387     fprintf(stderr,"########## PageCycler Timeout on URL: %s\n", urlBuf);
00388     pCycler->Observe( pCycler, nsnull, (pCycler->GetLastRequest()).get() );
00389   }
00390 }
00391 
00392 #endif //ENABLE_PAGE_CYCLER
00393 
00394 PRBool nsBrowserInstance::sCmdLineURLUsed = PR_FALSE;
00395 
00396 //*****************************************************************************
00397 //***    nsBrowserInstance: Object Management
00398 //*****************************************************************************
00399 
00400 nsBrowserInstance::nsBrowserInstance() : mIsClosed(PR_FALSE)
00401 {
00402   mDOMWindow            = nsnull;
00403   mContentAreaDocShellWeak  = nsnull;
00404 }
00405 
00406 nsBrowserInstance::~nsBrowserInstance()
00407 {
00408   Close();
00409 }
00410 
00411 void
00412 nsBrowserInstance::ReinitializeContentVariables()
00413 {
00414   NS_ASSERTION(mDOMWindow,"Reinitializing Content Variables without a window will cause a crash. see Bugzilla Bug 46454");
00415   if (!mDOMWindow)
00416     return;
00417 
00418   nsCOMPtr<nsIDOMWindow> contentWindow;
00419   mDOMWindow->GetContent(getter_AddRefs(contentWindow));
00420 
00421   nsCOMPtr<nsIScriptGlobalObject> globalObj(do_QueryInterface(contentWindow));
00422 
00423   if (globalObj) {
00424     nsIDocShell *docShell = globalObj->GetDocShell();
00425 
00426     mContentAreaDocShellWeak = do_GetWeakReference(docShell); // Weak reference
00427 
00428     if (APP_DEBUG) {
00429       nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
00430       if (docShellAsItem) {
00431         nsXPIDLString name;
00432         docShellAsItem->GetName(getter_Copies(name));
00433         printf("Attaching to Content WebShell [%s]\n", NS_LossyConvertUCS2toASCII(name).get());
00434       }
00435     }
00436   }
00437 }
00438 
00439 nsresult nsBrowserInstance::GetContentAreaDocShell(nsIDocShell** outDocShell)
00440 {
00441   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContentAreaDocShellWeak));
00442   if (!mIsClosed && docShell) {
00443     // we're still alive and the docshell still exists. but has it been destroyed?
00444     nsCOMPtr<nsIBaseWindow> hack = do_QueryInterface(docShell);
00445     if (hack) {
00446       nsCOMPtr<nsIWidget> parent;
00447       hack->GetParentWidget(getter_AddRefs(parent));
00448       if (!parent)
00449         // it's a zombie. a new one is in place. set up to use it.
00450         docShell = 0;
00451     }
00452   }
00453   if (!mIsClosed && !docShell)
00454     ReinitializeContentVariables();
00455 
00456   docShell = do_QueryReferent(mContentAreaDocShellWeak);
00457   *outDocShell = docShell;
00458   NS_IF_ADDREF(*outDocShell);
00459   return NS_OK;
00460 }
00461     
00462 //*****************************************************************************
00463 //    nsBrowserInstance: nsISupports
00464 //*****************************************************************************
00465 
00466 NS_IMPL_ADDREF(nsBrowserInstance)
00467 NS_IMPL_RELEASE(nsBrowserInstance)
00468 
00469 NS_INTERFACE_MAP_BEGIN(nsBrowserInstance)
00470    NS_INTERFACE_MAP_ENTRY(nsIBrowserInstance)
00471    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00472    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIBrowserInstance)
00473 NS_INTERFACE_MAP_END
00474 
00475 //*****************************************************************************
00476 //    nsBrowserInstance: nsIBrowserInstance
00477 //*****************************************************************************
00478 
00479 nsresult
00480 nsBrowserInstance::LoadUrl(const PRUnichar * urlToLoad)
00481 {
00482   nsresult rv = NS_OK;
00483 
00484   nsCOMPtr<nsIDocShell> docShell;
00485   GetContentAreaDocShell(getter_AddRefs(docShell));
00486 
00487   /* Ask nsWebShell to load the URl */
00488   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
00489     
00490   // Normal browser.
00491   rv = webNav->LoadURI( urlToLoad,                          // URI string
00492                         nsIWebNavigation::LOAD_FLAGS_NONE,  // Load flags
00493                         nsnull,                             // Referring URI
00494                         nsnull,                             // Post data
00495                         nsnull );                           // Extra headers
00496 
00497   return rv;
00498 }
00499 
00500 NS_IMETHODIMP    
00501 nsBrowserInstance::SetCmdLineURLUsed(PRBool aCmdLineURLUsed)
00502 {
00503   sCmdLineURLUsed = aCmdLineURLUsed;
00504   return NS_OK;
00505 }
00506 
00507 NS_IMETHODIMP    
00508 nsBrowserInstance::GetCmdLineURLUsed(PRBool* aCmdLineURLUsed)
00509 {
00510   NS_ASSERTION(aCmdLineURLUsed, "aCmdLineURLUsed can't be null");
00511   if (!aCmdLineURLUsed)
00512     return NS_ERROR_NULL_POINTER;
00513 
00514   *aCmdLineURLUsed = sCmdLineURLUsed;
00515   return NS_OK;
00516 }
00517 
00518 NS_IMETHODIMP    
00519 nsBrowserInstance::StartPageCycler(PRBool* aIsPageCycling)
00520 {
00521   *aIsPageCycling = PR_FALSE;
00522 
00523 #ifndef MOZ_XUL_APP
00524   nsresult rv;
00525 
00526   if (!sCmdLineURLUsed) {
00527     nsCOMPtr<nsICmdLineService> cmdLineArgs = 
00528              do_GetService(NS_COMMANDLINESERVICE_CONTRACTID, &rv);
00529     if (NS_FAILED(rv)) {
00530       if (APP_DEBUG) fprintf(stderr, "Could not obtain CmdLine processing service\n");
00531       return NS_ERROR_FAILURE;
00532     }
00533 
00534 #ifdef ENABLE_PAGE_CYCLER
00535     // First, check if there's a URL file to load (for testing), and if there 
00536     // is, process it instead of anything else.
00537     nsAutoString urlstr;
00538     nsXPIDLCString file;
00539     rv = cmdLineArgs->GetCmdLineValue("-f", getter_Copies(file));
00540     if (NS_SUCCEEDED(rv) && (const char*)file) {
00541 
00542       // see if we have a timeout value corresponding to the url-file
00543       nsXPIDLCString timeoutVal;
00544       rv = cmdLineArgs->GetCmdLineValue("-ftimeout", getter_Copies(timeoutVal));
00545       // see if we have a wait value corresponding to the url-file
00546       nsXPIDLCString waitVal;
00547       rv = cmdLineArgs->GetCmdLineValue("-fwait", getter_Copies(waitVal));
00548       // cereate the cool PageCycler instance
00549       PageCycler* bb = new PageCycler(this, timeoutVal, waitVal);
00550       if (bb == nsnull)
00551         return NS_ERROR_OUT_OF_MEMORY;
00552 
00553       NS_ADDREF(bb);
00554       rv = bb->Init(file);
00555       if (NS_FAILED(rv)) return rv;
00556 
00557       rv = bb->GetNextURL(urlstr);
00558       NS_RELEASE(bb);
00559 
00560       *aIsPageCycling = PR_TRUE;
00561     }
00562 
00563     if (!urlstr.IsEmpty()) {
00564       // A url was provided. Load it
00565       if (APP_DEBUG) printf("Got Command line URL to load %s\n", NS_ConvertUCS2toUTF8(urlstr).get());
00566       rv = LoadUrl( urlstr.get() );
00567       sCmdLineURLUsed = PR_TRUE;
00568       return rv;
00569     }
00570 #endif //ENABLE_PAGE_CYCLER
00571   }
00572 #endif // MOZ_XUL_APP
00573   return NS_OK;
00574 }
00575 
00576 
00577 NS_IMETHODIMP    
00578 nsBrowserInstance::SetWebShellWindow(nsIDOMWindowInternal* aWin)
00579 {
00580   NS_ENSURE_ARG(aWin);
00581   mDOMWindow = aWin;
00582 
00583   nsCOMPtr<nsIScriptGlobalObject> globalObj( do_QueryInterface(aWin) );
00584   if (!globalObj) {
00585     return NS_ERROR_FAILURE;
00586   }
00587 
00588   if (APP_DEBUG) {
00589     nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
00590       do_QueryInterface(globalObj->GetDocShell());
00591 
00592     if (docShellAsItem) {
00593       // inform our top level webshell that we are its parent URI content listener...
00594       nsXPIDLString name;
00595       docShellAsItem->GetName(getter_Copies(name));
00596       printf("Attaching to WebShellWindow[%s]\n", NS_LossyConvertUCS2toASCII(name).get());
00597     }
00598   }
00599 
00600   ReinitializeContentVariables();
00601 
00602   return NS_OK;
00603 }
00604 
00605 NS_IMETHODIMP    
00606 nsBrowserInstance::Close()
00607 { 
00608   // if we have already been closed....then just return
00609   if (mIsClosed) 
00610     return NS_OK;
00611   else
00612     mIsClosed = PR_TRUE;
00613 
00614   return NS_OK;
00615 }
00616 
00617 #ifndef MOZ_XUL_APP
00618 //*****************************************************************************
00619 // nsBrowserInstance: Helpers
00620 //*****************************************************************************
00621 
00623 // browserCntHandler is a content handler component that registers
00624 // the browse as the preferred content handler for various content
00625 // types like text/html, image/jpeg, etc. When the uri loader
00626 // has a content type that no currently open window wants to handle, 
00627 // it will ask the registry for a registered content handler for this
00628 // type. If the browser is registered to handle that type, we'll end
00629 // up in here where we create a new browser window for the url.
00630 //
00631 // I had intially written this as a JS component and would like to do
00632 // so again. However, JS components can't access xpconnect objects that
00633 // return DOM objects. And we need a dom window to bootstrap the browser
00635 
00636 NS_IMPL_ISUPPORTS1(nsChromeStartupHandler, nsICmdLineHandler)
00637 CMDLINEHANDLER_IMPL(nsChromeStartupHandler, "-chrome", "", "",
00638                     "Load the specified chrome.",
00639                     NS_CHROMESTARTUPHANDLER_CONTRACTID,
00640                     "Chrome Startup Handler", PR_TRUE, "", PR_FALSE)
00641 
00642 NS_IMPL_ISUPPORTS2(nsBrowserContentHandler, nsIContentHandler, nsICmdLineHandler)
00643 CMDLINEHANDLER_OTHERS_IMPL(nsBrowserContentHandler, "-browser",
00644                            "general.startup.browser", "Load the browser.",
00645                            PR_TRUE, PR_TRUE)
00646 CMDLINEHANDLER_REGISTERPROC_IMPL(nsBrowserContentHandler,
00647                                  "Browser Startup Handler",
00648                                  NS_BROWSERSTARTUPHANDLER_CONTRACTID)
00649 NS_IMETHODIMP nsBrowserContentHandler::GetChromeUrlForTask(char **aChromeUrlForTask) {
00650 
00651   if (!aChromeUrlForTask)
00652     return NS_ERROR_NULL_POINTER;
00653 
00654   nsresult rv = NS_ERROR_FAILURE;
00655   nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID));
00656   if (prefs) {
00657     rv = prefs->CopyCharPref("browser.chromeURL", aChromeUrlForTask);
00658     if (NS_SUCCEEDED(rv) && (*aChromeUrlForTask)[0] == '\0') {
00659       PL_strfree(*aChromeUrlForTask);
00660       rv = NS_ERROR_FAILURE;
00661     }
00662   }
00663   if (NS_FAILED(rv))
00664     *aChromeUrlForTask = PL_strdup("chrome://navigator/content/navigator.xul");
00665 
00666   return NS_OK;
00667 }
00668 
00669 PRBool nsBrowserContentHandler::NeedHomepageOverride(nsIPref *aPrefService)
00670 {
00671   NS_ASSERTION(aPrefService, "Null pointer to prefs service!");
00672 
00673   // get saved milestone from user's prefs
00674   nsXPIDLCString savedMilestone;
00675   aPrefService->GetCharPref(PREF_HOMEPAGE_OVERRIDE_MSTONE, 
00676                             getter_Copies(savedMilestone));
00677   // Mozilla never saves this value, but a fed-up advanced user might
00678   if (savedMilestone.Equals(kIgnoreOverrideMilestone))
00679     return PR_FALSE;
00680 
00681   // get browser's current milestone
00682   nsCOMPtr<nsIHttpProtocolHandler> httpHandler(
00683       do_GetService("@mozilla.org/network/protocol;1?name=http"));
00684   if (!httpHandler)
00685     return PR_TRUE;
00686 
00687   nsCAutoString currMilestone;
00688   httpHandler->GetMisc(currMilestone);
00689 
00690   // failed to get pref -or- saved milestone older than current milestone, 
00691   // write out known current milestone and show URL this time
00692   if (!(currMilestone.Equals(savedMilestone))) {
00693     // update milestone in "homepage override" pref
00694     aPrefService->SetCharPref(PREF_HOMEPAGE_OVERRIDE_MSTONE, 
00695                               currMilestone.get());
00696     return PR_TRUE;
00697   }
00698   
00699   // don't override if saved and current are same
00700   return PR_FALSE;
00701 }
00702 
00703 nsresult GetHomePageGroup(nsIPref* aPref, PRUnichar** aResult)
00704 {
00705   nsresult rv;
00706 
00707   nsXPIDLString uri;
00708   rv = aPref->GetLocalizedUnicharPref(PREF_BROWSER_STARTUP_HOMEPAGE, getter_Copies(uri));
00709   if (NS_FAILED(rv))
00710     return rv;
00711 
00712   PRInt32 count = 0;
00713   rv = aPref->GetIntPref("browser.startup.homepage.count", &count);
00714 
00715   // if we couldn't get the pref (unlikely) or only have one homepage
00716   if (NS_FAILED(rv) || count <= 1) {
00717     *aResult = ToNewUnicode(uri);
00718     return NS_OK;
00719   }
00720 
00721   // The "homepage" is a group of pages, put them in uriList separated by '\n'
00722   nsAutoString uriList(uri);
00723 
00724   for (PRInt32 i = 1; i < count; ++i) {
00725     nsCAutoString pref(NS_LITERAL_CSTRING("browser.startup.homepage."));
00726     pref.AppendInt(i);
00727 
00728     rv = aPref->GetLocalizedUnicharPref(pref.get(), getter_Copies(uri));
00729     if (NS_FAILED(rv))
00730       return rv;
00731 
00732     uriList.Append(PRUnichar('\n'));
00733     uriList.Append(uri);
00734   }
00735 
00736   *aResult = ToNewUnicode(uriList);
00737   return NS_OK;
00738 }
00739 
00740 NS_IMETHODIMP nsBrowserContentHandler::GetDefaultArgs(PRUnichar **aDefaultArgs)
00741 {
00742   if (!aDefaultArgs)
00743     return NS_ERROR_NULL_POINTER;
00744 
00745   nsresult rv;
00746 
00747   nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID));
00748   if (prefs) {
00749     if (NeedHomepageOverride(prefs)) {
00750       rv = prefs->GetLocalizedUnicharPref(PREF_HOMEPAGE_OVERRIDE_URL, aDefaultArgs);
00751       if (NS_SUCCEEDED(rv) && *aDefaultArgs)
00752         return NS_OK;
00753     }
00754 
00755     PRInt32 choice = 0;
00756     rv = prefs->GetIntPref(PREF_BROWSER_STARTUP_PAGE, &choice);
00757     if (NS_SUCCEEDED(rv)) {
00758       switch (choice) {
00759         case 1: {
00760           // skip the code below
00761           rv = GetHomePageGroup(prefs, aDefaultArgs);
00762           if (NS_SUCCEEDED(rv) && *aDefaultArgs)
00763             return NS_OK;
00764         }
00765         case 2: {
00766           nsCOMPtr<nsIBrowserHistory> history(do_GetService(NS_GLOBALHISTORY2_CONTRACTID));
00767           if (history) {
00768             nsCAutoString curl;
00769             rv = history->GetLastPageVisited(curl);
00770             if (NS_SUCCEEDED(rv)) {
00771               *aDefaultArgs = UTF8ToNewUnicode(curl);
00772               if (*aDefaultArgs) return NS_OK;
00773             }
00774           }
00775         }
00776       }
00777     }
00778   }
00779     
00780   // the default, in case we fail somewhere
00781   *aDefaultArgs = ToNewUnicode(NS_LITERAL_STRING("about:blank"));
00782   if (!*aDefaultArgs) return NS_ERROR_OUT_OF_MEMORY;
00783 
00784   return NS_OK;
00785 }
00786 
00787 NS_IMETHODIMP nsBrowserContentHandler::HandleContent(const char * aContentType,
00788                                                      nsIInterfaceRequestor * aWindowContext,
00789                                                      nsIRequest * aRequest)
00790 {
00791   NS_PRECONDITION(aContentType, "Must have a content type");
00792 
00793   // Verify that we can handle this content, to avoid infinite window opening
00794   // loops
00795   nsresult rv;
00796   nsCOMPtr<nsIWebNavigationInfo> webNavInfo =
00797     do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID, &rv);
00798   NS_ENSURE_SUCCESS(rv, rv);
00799 
00800   PRUint32 typeSupported;
00801   rv = webNavInfo->IsTypeSupported(nsDependentCString(aContentType), nsnull,
00802                                    &typeSupported);
00803   NS_ENSURE_SUCCESS(rv, rv);
00804 
00805   if (!typeSupported)
00806       return NS_ERROR_WONT_HANDLE_CONTENT;
00807 
00808   // create a new browser window to handle the content
00809   NS_ENSURE_ARG(aRequest);
00810   nsCOMPtr<nsIDOMWindow> parentWindow;
00811 
00812   if (aWindowContext)
00813     parentWindow = do_GetInterface(aWindowContext);
00814 
00815   nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(aRequest);
00816   if (!aChannel) return NS_ERROR_FAILURE;
00817 
00818   nsCOMPtr<nsIURI> uri;
00819   aChannel->GetURI(getter_AddRefs(uri));
00820   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
00821   nsCAutoString spec;
00822   uri->GetSpec(spec);
00823 
00824   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00825   if (wwatch) {
00826     nsCOMPtr<nsIDOMWindow> newWindow;
00827     wwatch->OpenWindow(parentWindow, spec.get(), "", 0, 0,
00828               getter_AddRefs(newWindow));
00829   }
00830 
00831   // now abort the current channel load...
00832   aRequest->Cancel(NS_BINDING_ABORTED);
00833 
00834   return NS_OK;
00835 }
00836 
00837 #endif // MOZ_XUL_APP