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
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.
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"
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.
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
,
78 CFStringRef inExtension
,
79 LSRolesMask inRoleMask
,
80 const FSRef
* inBindingRef
);
83 NS_IMPL_ISUPPORTS3(nsMacShellService
, nsIMacShellService
, nsIShellService
, nsIWebProgressListener
)
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());
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"),
111 nsresult rv
= NS_ERROR_FAILURE
;
113 // Get a reference to the bundle (based on its URL)
114 CFBundleRef defaultBrowserBundle
= ::CFBundleCreate(NULL
,
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
);
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
);
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).
145 mCheckedThisSession
= PR_TRUE
;
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
);
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
);
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
) {
187 nsCOMPtr
<nsIPrefBranch
> prefs
;
188 nsCOMPtr
<nsIPrefService
> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID
));
190 pserve
->GetBranch("", getter_AddRefs(prefs
));
192 prefs
->GetBoolPref(PREF_CHECKDEFAULTBROWSER
, aResult
);
198 nsMacShellService::SetShouldCheckDefaultBrowser(PRBool aShouldCheck
)
200 nsCOMPtr
<nsIPrefBranch
> prefs
;
201 nsCOMPtr
<nsIPrefService
> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID
));
203 pserve
->GetBranch("", getter_AddRefs(prefs
));
205 prefs
->SetBoolPref(PREF_CHECKDEFAULTBROWSER
, aShouldCheck
);
211 nsMacShellService::SetDesktopBackground(nsIDOMElement
* aElement
,
214 // Note: We don't support aPosition on OS X.
216 // Get the image URI:
218 nsCOMPtr
<nsIImageLoadingContent
> imageContent
= do_QueryInterface(aElement
,
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();
231 return NS_ERROR_FAILURE
;
233 nsIURI
*docURI
= doc
->GetDocumentURI();
235 return NS_ERROR_FAILURE
;
237 // Get the desired image file name
238 nsCOMPtr
<nsIURL
> imageURL(do_QueryInterface(imageURI
));
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
,
280 nsMacShellService::OnProgressChange(nsIWebProgress
* aWebProgress
,
281 nsIRequest
* aRequest
,
282 PRInt32 aCurSelfProgress
,
283 PRInt32 aMaxSelfProgress
,
284 PRInt32 aCurTotalProgress
,
285 PRInt32 aMaxTotalProgress
)
291 nsMacShellService::OnLocationChange(nsIWebProgress
* aWebProgress
,
292 nsIRequest
* aRequest
,
299 nsMacShellService::OnStatusChange(nsIWebProgress
* aWebProgress
,
300 nsIRequest
* aRequest
,
302 const PRUnichar
* aMessage
)
308 nsMacShellService::OnSecurityChange(nsIWebProgress
* aWebProgress
,
309 nsIRequest
* aRequest
,
316 nsMacShellService::OnStateChange(nsIWebProgress
* aWebProgress
,
317 nsIRequest
* aRequest
,
318 PRUint32 aStateFlags
,
321 if (aStateFlags
& STATE_STOP
) {
322 nsCOMPtr
<nsIObserverService
> os(do_GetService("@mozilla.org/observer-service;1"));
324 os
->NotifyObservers(nsnull
, "shell:desktop-background-changed", nsnull
);
326 PRBool exists
= PR_FALSE
;
327 mBackgroundFile
->Exists(&exists
);
331 nsCAutoString nativePath
;
332 mBackgroundFile
->GetNativePath(nativePath
);
334 AEDesc tAEDesc
= { typeNull
, nil
};
336 AliasHandle aliasHandle
= nil
;
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
)
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
);
359 AppleEvent tAppleEvent
;
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:(@)",
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
);
384 nsMacShellService::OpenApplication(PRInt32 aApplication
)
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
);
399 case nsIShellService::APPLICATION_NEWS
:
401 CFURLRef tempURL
= ::CFURLCreateWithString(kCFAllocatorDefault
,
402 CFSTR("news:"), NULL
);
403 err
= ::LSGetApplicationForURL(tempURL
, kLSRolesAll
, NULL
, &appURL
);
404 ::CFRelease(tempURL
);
407 case nsIMacShellService::APPLICATION_KEYCHAIN_ACCESS
:
408 err
= ::LSGetApplicationForInfo('APPL', 'kcmr', NULL
, kLSRolesAll
, NULL
,
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
);
419 return NS_ERROR_FILE_NOT_FOUND
;
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
);
431 return NS_ERROR_FILE_NOT_FOUND
;
437 if (appURL
&& err
== noErr
) {
438 err
= ::LSOpenCFURLRef(appURL
, NULL
);
439 rv
= err
!= noErr
? NS_ERROR_FAILURE
: NS_OK
;
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
453 return NS_ERROR_NOT_IMPLEMENTED
;
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
462 return NS_ERROR_NOT_IMPLEMENTED
;
466 nsMacShellService::OpenApplicationWithURI(nsILocalFile
* aApplication
, const nsACString
& aURI
)
468 nsCOMPtr
<nsILocalFileMac
> lfm(do_QueryInterface(aApplication
));
470 nsresult rv
= lfm
->GetCFURL(&appURL
);
474 const nsCString
spec(aURI
);
475 const UInt8
* uriString
= (const UInt8
*)spec
.get();
476 CFURLRef uri
= ::CFURLCreateWithBytes(NULL
, uriString
, aURI
.Length(),
477 kCFStringEncodingUTF8
, NULL
);
479 return NS_ERROR_OUT_OF_MEMORY
;
481 CFArrayRef uris
= ::CFArrayCreate(NULL
, (const void**)&uri
, 1, NULL
);
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
);
499 return err
!= noErr
? NS_ERROR_FAILURE
: NS_OK
;
503 nsMacShellService::GetDefaultFeedReader(nsILocalFile
** _retval
)
505 nsresult rv
= NS_ERROR_FAILURE
;
508 CFURLRef defaultHandlerURL
;
509 OSStatus err
= ::_LSCopyDefaultSchemeHandlerURL(CFSTR("feed"),
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
);
530 ::CFRelease(defaultHandlerURL
);