Back to index

lightning-sunbird  0.9+nobinonly
CHBrowserService.mm
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.org 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  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #import "NSString+Utils.h"
00039 
00040 #import "CHBrowserService.h"
00041 #import "CHDownloadFactories.h"
00042 #import "CHBrowserView.h"
00043 
00044 #include "nsIWindowWatcher.h"
00045 #include "nsIWebBrowserChrome.h"
00046 #include "nsCRT.h"
00047 #include "nsString.h"
00048 #include "nsIGenericFactory.h"
00049 #include "nsIComponentRegistrar.h"
00050 #include "nsEmbedAPI.h"
00051 #include "nsIDownload.h"
00052 #include "nsIExternalHelperAppService.h"
00053 
00054 NSString* TermEmbeddingNotificationName = @"TermEmbedding";
00055 NSString* XPCOMShutDownNotificationName = @"XPCOMShutDown";
00056 
00057 nsAlertController* CHBrowserService::sController = nsnull;
00058 CHBrowserService* CHBrowserService::sSingleton = nsnull;
00059 PRUint32 CHBrowserService::sNumBrowsers = 0;
00060 PRBool CHBrowserService::sCanTerminate = PR_FALSE;
00061 
00062 
00063 // CHBrowserService implementation
00064 CHBrowserService::CHBrowserService()
00065 {
00066 }
00067 
00068 CHBrowserService::~CHBrowserService()
00069 {
00070 }
00071 
00072 NS_IMPL_ISUPPORTS3(CHBrowserService,
00073                    nsIWindowCreator,
00074                    nsIFactory, 
00075                    nsIHelperAppLauncherDialog)
00076 
00077 /* static */
00078 nsresult
00079 CHBrowserService::InitEmbedding()
00080 {
00081   sNumBrowsers++;
00082   
00083   if (sSingleton)
00084     return NS_OK;
00085 
00086   sSingleton = new CHBrowserService();
00087   if (!sSingleton)
00088     return NS_ERROR_OUT_OF_MEMORY;
00089   NS_ADDREF(sSingleton);
00090   
00091   // Register as the window creator
00092   nsCOMPtr<nsIWindowWatcher> watcher(do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
00093   if (!watcher) 
00094     return NS_ERROR_FAILURE;
00095   watcher->SetWindowCreator(sSingleton);
00096 
00097   nsCOMPtr<nsIComponentRegistrar> cr;
00098   NS_GetComponentRegistrar(getter_AddRefs(cr));
00099   if ( !cr )
00100     return NS_ERROR_FAILURE;
00101 
00102   // replace the external helper app dialog with our own
00103   #define NS_HELPERAPPLAUNCHERDIALOG_CID \
00104           {0xf68578eb, 0x6ec2, 0x4169, {0xae, 0x19, 0x8c, 0x62, 0x43, 0xf0, 0xab, 0xe1}}
00105   static NS_DEFINE_CID(kHelperDlgCID, NS_HELPERAPPLAUNCHERDIALOG_CID);
00106   nsresult rv = cr->RegisterFactory(kHelperDlgCID, NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
00107                             sSingleton);
00108   
00109   // replace the downloader with our own which does not rely on the xpfe downlaod manager
00110   nsCOMPtr<nsIFactory> downloadFactory;
00111   rv = NewDownloadListenerFactory(getter_AddRefs(downloadFactory));
00112   if (NS_FAILED(rv)) return rv;
00113   
00114   static NS_DEFINE_CID(kDownloadCID, NS_DOWNLOAD_CID);
00115   rv = cr->RegisterFactory(kDownloadCID, "Download", NS_TRANSFER_CONTRACTID, downloadFactory);
00116 
00117   return rv;
00118 }
00119 
00120 /* static */
00121 void
00122 CHBrowserService::BrowserClosed()
00123 {
00124   sNumBrowsers--;
00125   if (sCanTerminate && sNumBrowsers == 0) {
00126     // The app is terminating *and* our count dropped to 0.
00127     ShutDown();
00128   }
00129 }
00130 
00131 /* static */
00132 void
00133 CHBrowserService::TermEmbedding()
00134 {
00135   // phase 1 notification (we're trying to terminate)
00136   [[NSNotificationCenter defaultCenter] postNotificationName:TermEmbeddingNotificationName object:nil];
00137 
00138   sCanTerminate = PR_TRUE;
00139   if (sNumBrowsers == 0) {
00140     ShutDown();
00141   }
00142   else {
00143 #if DEBUG
00144        NSLog(@"Cannot yet shut down embedding.");
00145 #endif
00146     // Otherwise we cannot yet terminate.  We have to let the death of the browser views
00147     // induce termination.
00148   }
00149 }
00150 
00151 /* static */
00152 void CHBrowserService::ShutDown()
00153 {
00154   // phase 2 notifcation (we really are about to terminate)
00155   [[NSNotificationCenter defaultCenter] postNotificationName:XPCOMShutDownNotificationName object:nil];
00156 
00157   NS_IF_RELEASE(sSingleton);
00158   NS_TermEmbedding();
00159 #if DEBUG
00160   NSLog(@"Shutting down embedding.");
00161 #endif
00162 }
00163 
00164 #define NS_ALERT_NIB_NAME "alert"
00165 
00166 nsAlertController* 
00167 CHBrowserService::GetAlertController()
00168 {
00169   if (!sController) {
00170     NSBundle* bundle = [NSBundle bundleForClass:[CHBrowserView class]];
00171     [bundle loadNibFile:@NS_ALERT_NIB_NAME externalNameTable:nsnull withZone:[NSApp zone]];
00172   }
00173   return sController;
00174 }
00175 
00176 void
00177 CHBrowserService::SetAlertController(nsAlertController* aController)
00178 {
00179   // XXX When should the controller be released?
00180   sController = aController;
00181   [sController retain];
00182 }
00183 
00184 // nsIFactory implementation
00185 NS_IMETHODIMP 
00186 CHBrowserService::CreateInstance(nsISupports *aOuter, 
00187                                       const nsIID & aIID, 
00188                                       void **aResult)
00189 {
00190 
00191   NS_ENSURE_ARG_POINTER(aResult);
00192 
00193   /*
00194   if (aIID.Equals(NS_GET_IID(nsIHelperAppLauncherDialog)))
00195   {
00196   }
00197   */
00198 
00199   return sSingleton->QueryInterface(aIID, aResult);
00200 }
00201 
00202 NS_IMETHODIMP 
00203 CHBrowserService::LockFactory(PRBool lock)
00204 {
00205   return NS_OK;
00206 }
00207 
00208 
00209 // Implementation of nsIWindowCreator
00210 /* nsIWebBrowserChrome createChromeWindow (in nsIWebBrowserChrome parent, in PRUint32 chromeFlags); */
00211 NS_IMETHODIMP 
00212 CHBrowserService::CreateChromeWindow(nsIWebBrowserChrome *parent, 
00213                                           PRUint32 chromeFlags, 
00214                                           nsIWebBrowserChrome **_retval)
00215 {
00216   if (!parent) {
00217 #if DEBUG
00218     NSLog(@"Attempt to create a new browser window with a null parent.  Should not happen in Chimera.");
00219 #endif
00220     return NS_ERROR_FAILURE;
00221   }
00222     
00223   nsCOMPtr<nsIWindowCreator> browserChrome(do_QueryInterface(parent));
00224   return browserChrome->CreateChromeWindow(parent, chromeFlags, _retval);
00225 }
00226 
00227 
00228 //    void show( in nsIHelperAppLauncher aLauncher, in nsISupports aContext, in unsigned long aReason );
00229 NS_IMETHODIMP
00230 CHBrowserService::Show(nsIHelperAppLauncher* inLauncher, nsISupports* inContext, PRUint32 aReason)
00231 {
00232   // Old way - always prompt to save file to disk
00233   return inLauncher->SaveToDisk(nsnull, PR_FALSE);
00234   // New way - just save the file to disk in download folder and invoke the default helper app
00235   // XXX fix me. We need to update the downlaod dialog UI to account for this,
00236   // and warn if the user is launching an executable.
00237   //return inLauncher->LaunchWithApplication(nsnull, PR_FALSE);
00238 }
00239 
00240 NS_IMETHODIMP
00241 CHBrowserService::PromptForSaveToFile(nsIHelperAppLauncher* aLauncher, 
00242                                       nsISupports *aWindowContext, 
00243                                       const PRUnichar *aDefaultFile, 
00244                                       const PRUnichar *aSuggestedFileExtension, 
00245                                       nsILocalFile **_retval)
00246 {
00247   NSString* filename = [NSString stringWithPRUnichars:aDefaultFile];
00248   NSSavePanel *thePanel = [NSSavePanel savePanel];
00249   
00250   // Note: although the docs for NSSavePanel specifically state "path and filename can be empty strings, but
00251   // cannot be nil" if you want the last used directory to persist between calls to display the save panel
00252   // use nil for the path given to runModalForDirectory
00253   int runResult = [thePanel runModalForDirectory: nil file:filename];
00254   if (runResult == NSOKButton) {
00255     // NSLog(@"Saving to %@", [thePanel filename]);
00256     NSString *theName = [thePanel filename];
00257     return NS_NewNativeLocalFile(nsDependentCString([theName fileSystemRepresentation]), PR_FALSE, _retval);
00258   }
00259 
00260   return NS_ERROR_FAILURE;
00261 }
00262 
00263 //
00264 // RegisterAppComponents
00265 //
00266 // Register application-provided Gecko components.
00267 //
00268 void
00269 CHBrowserService::RegisterAppComponents(const nsModuleComponentInfo* inComponents, const int inNumComponents)
00270 {
00271   nsCOMPtr<nsIComponentRegistrar> cr;
00272   NS_GetComponentRegistrar(getter_AddRefs(cr));
00273   if ( !cr )
00274     return;
00275 
00276   for (int i = 0; i < inNumComponents; ++i) {
00277     nsCOMPtr<nsIGenericFactory> componentFactory;
00278     nsresult rv = NS_NewGenericFactory(getter_AddRefs(componentFactory), &(inComponents[i]));
00279     if (NS_FAILED(rv)) {
00280       NS_ASSERTION(PR_FALSE, "Unable to create factory for component");
00281       continue;
00282     }
00283 
00284     rv = cr->RegisterFactory(inComponents[i].mCID,
00285                              inComponents[i].mDescription,
00286                              inComponents[i].mContractID,
00287                              componentFactory);
00288     NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to register factory for component");
00289   }
00290 }
00291