Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / browser / components / shell / src / nsMacShellService.cpp
blob633c1b5e10146b72b6c1e3823aff5c7bdcaa5e57
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Shell Service.
17 * The Initial Developer of the Original Code is Ben Goodger.
18 * Portions created by the Initial Developer are Copyright (C) 2004
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Ben Goodger <ben@mozilla.org> (Original Author)
23 * Asaf Romano <mozilla.mano@sent.com>
24 * Benjamin Smedberg <benjamin@smedbergs.us>
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 #include "nsDirectoryServiceDefs.h"
41 #include "nsIDOMElement.h"
42 #include "nsIDOMHTMLImageElement.h"
43 #include "nsIImageLoadingContent.h"
44 #include "nsIDocument.h"
45 #include "nsIContent.h"
46 #include "nsILocalFileMac.h"
47 #include "nsIObserverService.h"
48 #include "nsIPrefService.h"
49 #include "nsIServiceManager.h"
50 #include "nsIStringBundle.h"
51 #include "nsIURL.h"
52 #include "nsIWebBrowserPersist.h"
53 #include "nsMacShellService.h"
54 #include "nsNetUtil.h"
55 #include "nsShellService.h"
56 #include "nsStringAPI.h"
58 #include <CoreFoundation/CoreFoundation.h>
59 #include <Carbon/Carbon.h>
61 #define NETWORK_PREFPANE NS_LITERAL_CSTRING("/System/Library/PreferencePanes/Network.prefPane")
62 #define DESKTOP_PREFPANE NS_LITERAL_CSTRING("/System/Library/PreferencePanes/DesktopScreenEffectsPref.prefPane")
64 #define SAFARI_BUNDLE_IDENTIFIER NS_LITERAL_CSTRING("com.apple.Safari")
66 // These Launch Services functions are undocumented. We're using them since they're
67 // the only way to set the default opener for URLs / file extensions.
68 extern "C" {
69 // Returns the CFURL for application currently set as the default opener for the
70 // given URL scheme. appURL must be released by the caller.
71 extern OSStatus _LSCopyDefaultSchemeHandlerURL(CFStringRef scheme, CFURLRef *appURL);
72 extern OSStatus _LSSetDefaultSchemeHandlerURL(CFStringRef scheme, CFURLRef appURL);
73 extern OSStatus _LSSaveAndRefresh(void);
74 // Callers should pass 0 as both inType and inCreator in order to set the default opener
75 // without modifing those.
76 extern OSStatus _LSSetWeakBindingForType(OSType inType,
77 OSType inCreator,
78 CFStringRef inExtension,
79 LSRolesMask inRoleMask,
80 const FSRef* inBindingRef);
83 NS_IMPL_ISUPPORTS3(nsMacShellService, nsIMacShellService, nsIShellService, nsIWebProgressListener)
85 NS_IMETHODIMP
86 nsMacShellService::IsDefaultBrowser(PRBool aStartupCheck, PRBool* aIsDefaultBrowser)
88 *aIsDefaultBrowser = PR_TRUE;
90 // Since neither Launch Services nor Internet Config actually differ between
91 // bundles which have the same bundle identifier (That is, if we set our
92 // bundle's URL as the default handler, Launch Service might return the
93 // URL of another firefox bundle as the defualt http handler), we are
94 // comparing the bundles' identifiers rather than their URLs.
96 CFStringRef firefoxID = ::CFBundleGetIdentifier(CFBundleGetMainBundle());
97 if (!firefoxID) {
98 // CFBundleGetIdentifier is expected to return NULL only if the specified
99 // bundle doesn't have a bundle identifier in its plist. In this case, that
100 // means a failure, since our bundle does have an identifier.
101 return NS_ERROR_FAILURE;
104 ::CFRetain(firefoxID);
106 // Get the default http handler URL
107 CFURLRef defaultBrowserURL;
108 OSStatus err = ::_LSCopyDefaultSchemeHandlerURL(CFSTR("http"),
109 &defaultBrowserURL);
111 nsresult rv = NS_ERROR_FAILURE;
112 if (err == noErr) {
113 // Get a reference to the bundle (based on its URL)
114 CFBundleRef defaultBrowserBundle = ::CFBundleCreate(NULL,
115 defaultBrowserURL);
116 if (defaultBrowserBundle) {
117 CFStringRef defaultBrowserID = ::CFBundleGetIdentifier(defaultBrowserBundle);
118 if (defaultBrowserID) {
119 ::CFRetain(defaultBrowserID);
120 // and compare it to our bundle identifier
121 *aIsDefaultBrowser = ::CFStringCompare(firefoxID, defaultBrowserID, 0)
122 == kCFCompareEqualTo;
123 ::CFRelease(defaultBrowserID);
125 else {
126 // If the default browser bundle doesn't have an identifier in its plist,
127 // it's not our bundle
128 *aIsDefaultBrowser = PR_FALSE;
131 ::CFRelease(defaultBrowserBundle);
132 rv = NS_OK;
135 ::CFRelease(defaultBrowserURL);
138 // release the idetifiers strings
139 ::CFRelease(firefoxID);
141 // If this is the first browser window, maintain internal state that we've
142 // checked this session (so that subsequent window opens don't show the
143 // default browser dialog).
144 if (aStartupCheck)
145 mCheckedThisSession = PR_TRUE;
147 return rv;
150 NS_IMETHODIMP
151 nsMacShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUsers)
153 // Note: We don't support aForAllUsers on Mac OS X.
155 CFURLRef firefoxURL = ::CFBundleCopyBundleURL(CFBundleGetMainBundle());
157 ::_LSSetDefaultSchemeHandlerURL(CFSTR("http"), firefoxURL);
158 ::_LSSetDefaultSchemeHandlerURL(CFSTR("https"), firefoxURL);
160 if (aClaimAllTypes) {
161 ::_LSSetDefaultSchemeHandlerURL(CFSTR("ftp"), firefoxURL);
163 FSRef firefoxFSRef;
164 // CFURLGetFSRef returns true if the conversion was successful
165 if (::CFURLGetFSRef(firefoxURL, &firefoxFSRef)) {
166 // Set the default opener for html/htm files
167 ::_LSSetWeakBindingForType(0, 0, CFSTR("html"), kLSRolesAll, &firefoxFSRef);
168 ::_LSSetWeakBindingForType(0, 0, CFSTR("htm"), kLSRolesAll, &firefoxFSRef);
171 ::_LSSaveAndRefresh();
173 ::CFRelease(firefoxURL);
174 return NS_OK;
177 NS_IMETHODIMP
178 nsMacShellService::GetShouldCheckDefaultBrowser(PRBool* aResult)
180 // If we've already checked, the browser has been started and this is a
181 // new window open, and we don't want to check again.
182 if (mCheckedThisSession) {
183 *aResult = PR_FALSE;
184 return NS_OK;
187 nsCOMPtr<nsIPrefBranch> prefs;
188 nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
189 if (pserve)
190 pserve->GetBranch("", getter_AddRefs(prefs));
192 prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult);
194 return NS_OK;
197 NS_IMETHODIMP
198 nsMacShellService::SetShouldCheckDefaultBrowser(PRBool aShouldCheck)
200 nsCOMPtr<nsIPrefBranch> prefs;
201 nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
202 if (pserve)
203 pserve->GetBranch("", getter_AddRefs(prefs));
205 prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
207 return NS_OK;
210 NS_IMETHODIMP
211 nsMacShellService::SetDesktopBackground(nsIDOMElement* aElement,
212 PRInt32 aPosition)
214 // Note: We don't support aPosition on OS X.
216 // Get the image URI:
217 nsresult rv;
218 nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement,
219 &rv);
220 NS_ENSURE_SUCCESS(rv, rv);
221 nsCOMPtr<nsIURI> imageURI;
222 rv = imageContent->GetCurrentURI(getter_AddRefs(imageURI));
223 NS_ENSURE_SUCCESS(rv, rv);
225 // We need the referer URI for nsIWebBrowserPersist::saveURI
226 nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
227 NS_ENSURE_SUCCESS(rv, rv);
228 nsCOMPtr<nsIDocument> doc;
229 doc = content->GetOwnerDoc();
230 if (!doc)
231 return NS_ERROR_FAILURE;
233 nsIURI *docURI = doc->GetDocumentURI();
234 if (!docURI)
235 return NS_ERROR_FAILURE;
237 // Get the desired image file name
238 nsCOMPtr<nsIURL> imageURL(do_QueryInterface(imageURI));
239 if (!imageURL) {
240 // XXXmano (bug 300293): Non-URL images (e.g. the data: protocol) are not
241 // yet supported. What filename should we take here?
242 return NS_ERROR_NOT_IMPLEMENTED;
245 nsCAutoString fileName;
246 imageURL->GetFileName(fileName);
247 nsCOMPtr<nsIProperties> fileLocator
248 (do_GetService("@mozilla.org/file/directory_service;1", &rv));
249 NS_ENSURE_SUCCESS(rv, rv);
251 // Get the current user's "Pictures" folder (That's ~/Pictures):
252 fileLocator->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsILocalFile),
253 getter_AddRefs(mBackgroundFile));
254 if (!mBackgroundFile)
255 return NS_ERROR_OUT_OF_MEMORY;
257 nsAutoString fileNameUnicode;
258 CopyUTF8toUTF16(fileName, fileNameUnicode);
260 // and add the imgage file name itself:
261 mBackgroundFile->Append(fileNameUnicode);
263 // Download the image; the desktop background will be set in OnStateChange()
264 nsCOMPtr<nsIWebBrowserPersist> wbp
265 (do_CreateInstance("@mozilla.org/embedding/browser/nsWebBrowserPersist;1", &rv));
266 NS_ENSURE_SUCCESS(rv, rv);
268 PRUint32 flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION |
269 nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES |
270 nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
272 wbp->SetPersistFlags(flags);
273 wbp->SetProgressListener(this);
275 return wbp->SaveURI(imageURI, nsnull, docURI, nsnull, nsnull,
276 mBackgroundFile);
279 NS_IMETHODIMP
280 nsMacShellService::OnProgressChange(nsIWebProgress* aWebProgress,
281 nsIRequest* aRequest,
282 PRInt32 aCurSelfProgress,
283 PRInt32 aMaxSelfProgress,
284 PRInt32 aCurTotalProgress,
285 PRInt32 aMaxTotalProgress)
287 return NS_OK;
290 NS_IMETHODIMP
291 nsMacShellService::OnLocationChange(nsIWebProgress* aWebProgress,
292 nsIRequest* aRequest,
293 nsIURI* aLocation)
295 return NS_OK;
298 NS_IMETHODIMP
299 nsMacShellService::OnStatusChange(nsIWebProgress* aWebProgress,
300 nsIRequest* aRequest,
301 nsresult aStatus,
302 const PRUnichar* aMessage)
304 return NS_OK;
307 NS_IMETHODIMP
308 nsMacShellService::OnSecurityChange(nsIWebProgress* aWebProgress,
309 nsIRequest* aRequest,
310 PRUint32 aState)
312 return NS_OK;
315 NS_IMETHODIMP
316 nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress,
317 nsIRequest* aRequest,
318 PRUint32 aStateFlags,
319 nsresult aStatus)
321 if (aStateFlags & STATE_STOP) {
322 nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1"));
323 if (os)
324 os->NotifyObservers(nsnull, "shell:desktop-background-changed", nsnull);
326 PRBool exists = PR_FALSE;
327 mBackgroundFile->Exists(&exists);
328 if (!exists)
329 return NS_OK;
331 nsCAutoString nativePath;
332 mBackgroundFile->GetNativePath(nativePath);
334 AEDesc tAEDesc = { typeNull, nil };
335 OSErr err = noErr;
336 AliasHandle aliasHandle = nil;
337 FSRef pictureRef;
338 OSStatus status;
340 // Convert the path into a FSRef
341 status = ::FSPathMakeRef((const UInt8*)nativePath.get(), &pictureRef, NULL);
342 if (status == noErr) {
343 err = ::FSNewAlias(nil, &pictureRef, &aliasHandle);
344 if (err == noErr && aliasHandle == nil)
345 err = paramErr;
347 if (err == noErr) {
348 // We need the descriptor (based on the picture file reference)
349 // for the 'Set Desktop Picture' apple event.
350 char handleState = ::HGetState((Handle)aliasHandle);
351 ::HLock((Handle)aliasHandle);
352 err = ::AECreateDesc(typeAlias, *aliasHandle,
353 GetHandleSize((Handle)aliasHandle), &tAEDesc);
354 // unlock the alias handler
355 ::HSetState((Handle)aliasHandle, handleState);
356 ::DisposeHandle((Handle)aliasHandle);
358 if (err == noErr) {
359 AppleEvent tAppleEvent;
360 OSType sig = 'MACS';
361 AEBuildError tAEBuildError;
362 // Create a 'Set Desktop Pictue' Apple Event
363 err = ::AEBuildAppleEvent(kAECoreSuite, kAESetData, typeApplSignature,
364 &sig, sizeof(OSType), kAutoGenerateReturnID,
365 kAnyTransactionID, &tAppleEvent, &tAEBuildError,
366 "'----':'obj '{want:type (prop),form:prop" \
367 ",seld:type('dpic'),from:'null'()},data:(@)",
368 &tAEDesc);
369 if (err == noErr) {
370 AppleEvent reply = { typeNull, nil };
371 // Sent the event we built, the reply event isn't necessary
372 err = ::AESend(&tAppleEvent, &reply, kAENoReply, kAENormalPriority,
373 kNoTimeOut, nil, nil);
374 ::AEDisposeDesc(&tAppleEvent);
380 return NS_OK;
383 NS_IMETHODIMP
384 nsMacShellService::OpenApplication(PRInt32 aApplication)
386 nsresult rv = NS_OK;
387 CFURLRef appURL = nil;
388 OSStatus err = noErr;
390 switch (aApplication) {
391 case nsIShellService::APPLICATION_MAIL:
393 CFURLRef tempURL = ::CFURLCreateWithString(kCFAllocatorDefault,
394 CFSTR("mailto:"), NULL);
395 err = ::LSGetApplicationForURL(tempURL, kLSRolesAll, NULL, &appURL);
396 ::CFRelease(tempURL);
398 break;
399 case nsIShellService::APPLICATION_NEWS:
401 CFURLRef tempURL = ::CFURLCreateWithString(kCFAllocatorDefault,
402 CFSTR("news:"), NULL);
403 err = ::LSGetApplicationForURL(tempURL, kLSRolesAll, NULL, &appURL);
404 ::CFRelease(tempURL);
406 break;
407 case nsIMacShellService::APPLICATION_KEYCHAIN_ACCESS:
408 err = ::LSGetApplicationForInfo('APPL', 'kcmr', NULL, kLSRolesAll, NULL,
409 &appURL);
410 break;
411 case nsIMacShellService::APPLICATION_NETWORK:
413 nsCOMPtr<nsILocalFile> lf;
414 rv = NS_NewNativeLocalFile(NETWORK_PREFPANE, PR_TRUE, getter_AddRefs(lf));
415 NS_ENSURE_SUCCESS(rv, rv);
416 PRBool exists;
417 lf->Exists(&exists);
418 if (!exists)
419 return NS_ERROR_FILE_NOT_FOUND;
420 return lf->Launch();
422 break;
423 case nsIMacShellService::APPLICATION_DESKTOP:
425 nsCOMPtr<nsILocalFile> lf;
426 rv = NS_NewNativeLocalFile(DESKTOP_PREFPANE, PR_TRUE, getter_AddRefs(lf));
427 NS_ENSURE_SUCCESS(rv, rv);
428 PRBool exists;
429 lf->Exists(&exists);
430 if (!exists)
431 return NS_ERROR_FILE_NOT_FOUND;
432 return lf->Launch();
434 break;
437 if (appURL && err == noErr) {
438 err = ::LSOpenCFURLRef(appURL, NULL);
439 rv = err != noErr ? NS_ERROR_FAILURE : NS_OK;
441 ::CFRelease(appURL);
444 return rv;
447 NS_IMETHODIMP
448 nsMacShellService::GetDesktopBackgroundColor(PRUint32 *aColor)
450 // This method and |SetDesktopBackgroundColor| has no meaning on Mac OS X.
451 // The mac desktop preferences UI uses pictures for the few solid colors it
452 // supports.
453 return NS_ERROR_NOT_IMPLEMENTED;
456 NS_IMETHODIMP
457 nsMacShellService::SetDesktopBackgroundColor(PRUint32 aColor)
459 // This method and |GetDesktopBackgroundColor| has no meaning on Mac OS X.
460 // The mac desktop preferences UI uses pictures for the few solid colors it
461 // supports.
462 return NS_ERROR_NOT_IMPLEMENTED;
465 NS_IMETHODIMP
466 nsMacShellService::OpenApplicationWithURI(nsILocalFile* aApplication, const nsACString& aURI)
468 nsCOMPtr<nsILocalFileMac> lfm(do_QueryInterface(aApplication));
469 CFURLRef appURL;
470 nsresult rv = lfm->GetCFURL(&appURL);
471 if (NS_FAILED(rv))
472 return rv;
474 const nsCString spec(aURI);
475 const UInt8* uriString = (const UInt8*)spec.get();
476 CFURLRef uri = ::CFURLCreateWithBytes(NULL, uriString, aURI.Length(),
477 kCFStringEncodingUTF8, NULL);
478 if (!uri)
479 return NS_ERROR_OUT_OF_MEMORY;
481 CFArrayRef uris = ::CFArrayCreate(NULL, (const void**)&uri, 1, NULL);
482 if (!uris) {
483 ::CFRelease(uri);
484 return NS_ERROR_OUT_OF_MEMORY;
487 LSLaunchURLSpec launchSpec;
488 launchSpec.appURL = appURL;
489 launchSpec.itemURLs = uris;
490 launchSpec.passThruParams = NULL;
491 launchSpec.launchFlags = kLSLaunchDefaults;
492 launchSpec.asyncRefCon = NULL;
494 OSErr err = ::LSOpenFromURLSpec(&launchSpec, NULL);
496 ::CFRelease(uris);
497 ::CFRelease(uri);
499 return err != noErr ? NS_ERROR_FAILURE : NS_OK;
502 NS_IMETHODIMP
503 nsMacShellService::GetDefaultFeedReader(nsILocalFile** _retval)
505 nsresult rv = NS_ERROR_FAILURE;
506 *_retval = nsnull;
508 CFURLRef defaultHandlerURL;
509 OSStatus err = ::_LSCopyDefaultSchemeHandlerURL(CFSTR("feed"),
510 &defaultHandlerURL);
511 if (defaultHandlerURL) {
512 nsCOMPtr<nsILocalFileMac> defaultReader =
513 do_CreateInstance("@mozilla.org/file/local;1", &rv);
514 if (NS_SUCCEEDED(rv)) {
515 rv = defaultReader->InitWithCFURL(defaultHandlerURL);
516 if (NS_SUCCEEDED(rv)) {
517 // ASSERT("Safari Is Not a Feed Reader");
518 nsCAutoString bundleIdentifier;
520 // don't throw if the bundle has no identifier
521 rv = NS_ERROR_FAILURE;
522 if (NS_FAILED(defaultReader->GetBundleIdentifier(bundleIdentifier)) ||
523 !bundleIdentifier.Equals(SAFARI_BUNDLE_IDENTIFIER)) {
524 NS_ADDREF(*_retval = defaultReader);
525 rv = NS_OK;
530 ::CFRelease(defaultHandlerURL);
533 return rv;