browser/components/shell/src/nsMacShellService.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:e6bac9a7e862
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsDirectoryServiceDefs.h"
7 #include "nsIDOMElement.h"
8 #include "nsIDOMHTMLImageElement.h"
9 #include "nsIImageLoadingContent.h"
10 #include "nsIDocument.h"
11 #include "nsIContent.h"
12 #include "nsILocalFileMac.h"
13 #include "nsIObserverService.h"
14 #include "nsIPrefService.h"
15 #include "nsIServiceManager.h"
16 #include "nsIStringBundle.h"
17 #include "nsIURL.h"
18 #include "nsIWebBrowserPersist.h"
19 #include "nsMacShellService.h"
20 #include "nsNetUtil.h"
21 #include "nsShellService.h"
22 #include "nsStringAPI.h"
23 #include "nsIDocShell.h"
24 #include "nsILoadContext.h"
25
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <ApplicationServices/ApplicationServices.h>
28
29 #define NETWORK_PREFPANE NS_LITERAL_CSTRING("/System/Library/PreferencePanes/Network.prefPane")
30 #define DESKTOP_PREFPANE NS_LITERAL_CSTRING("/System/Library/PreferencePanes/DesktopScreenEffectsPref.prefPane")
31
32 #define SAFARI_BUNDLE_IDENTIFIER "com.apple.Safari"
33
34 NS_IMPL_ISUPPORTS(nsMacShellService, nsIMacShellService, nsIShellService, nsIWebProgressListener)
35
36 NS_IMETHODIMP
37 nsMacShellService::IsDefaultBrowser(bool aStartupCheck,
38 bool aForAllTypes,
39 bool* aIsDefaultBrowser)
40 {
41 *aIsDefaultBrowser = false;
42
43 CFStringRef firefoxID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
44 if (!firefoxID) {
45 // CFBundleGetIdentifier is expected to return nullptr only if the specified
46 // bundle doesn't have a bundle identifier in its plist. In this case, that
47 // means a failure, since our bundle does have an identifier.
48 return NS_ERROR_FAILURE;
49 }
50
51 // Get the default http handler's bundle ID (or nullptr if it has not been
52 // explicitly set)
53 CFStringRef defaultBrowserID = ::LSCopyDefaultHandlerForURLScheme(CFSTR("http"));
54 if (defaultBrowserID) {
55 *aIsDefaultBrowser = ::CFStringCompare(firefoxID, defaultBrowserID, 0) == kCFCompareEqualTo;
56 ::CFRelease(defaultBrowserID);
57 }
58
59 // If this is the first browser window, maintain internal state that we've
60 // checked this session (so that subsequent window opens don't show the
61 // default browser dialog).
62 if (aStartupCheck)
63 mCheckedThisSession = true;
64
65 return NS_OK;
66 }
67
68 NS_IMETHODIMP
69 nsMacShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
70 {
71 // Note: We don't support aForAllUsers on Mac OS X.
72
73 CFStringRef firefoxID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
74 if (!firefoxID) {
75 return NS_ERROR_FAILURE;
76 }
77
78 if (::LSSetDefaultHandlerForURLScheme(CFSTR("http"), firefoxID) != noErr) {
79 return NS_ERROR_FAILURE;
80 }
81 if (::LSSetDefaultHandlerForURLScheme(CFSTR("https"), firefoxID) != noErr) {
82 return NS_ERROR_FAILURE;
83 }
84
85 if (aClaimAllTypes) {
86 if (::LSSetDefaultHandlerForURLScheme(CFSTR("ftp"), firefoxID) != noErr) {
87 return NS_ERROR_FAILURE;
88 }
89 if (::LSSetDefaultRoleHandlerForContentType(kUTTypeHTML, kLSRolesAll, firefoxID) != noErr) {
90 return NS_ERROR_FAILURE;
91 }
92 }
93
94 return NS_OK;
95 }
96
97 NS_IMETHODIMP
98 nsMacShellService::GetShouldCheckDefaultBrowser(bool* aResult)
99 {
100 // If we've already checked, the browser has been started and this is a
101 // new window open, and we don't want to check again.
102 if (mCheckedThisSession) {
103 *aResult = false;
104 return NS_OK;
105 }
106
107 nsCOMPtr<nsIPrefBranch> prefs;
108 nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
109 if (pserve)
110 pserve->GetBranch("", getter_AddRefs(prefs));
111
112 prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult);
113
114 return NS_OK;
115 }
116
117 NS_IMETHODIMP
118 nsMacShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck)
119 {
120 nsCOMPtr<nsIPrefBranch> prefs;
121 nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
122 if (pserve)
123 pserve->GetBranch("", getter_AddRefs(prefs));
124
125 prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
126
127 return NS_OK;
128 }
129
130 NS_IMETHODIMP
131 nsMacShellService::GetCanSetDesktopBackground(bool* aResult)
132 {
133 *aResult = true;
134 return NS_OK;
135 }
136
137 NS_IMETHODIMP
138 nsMacShellService::SetDesktopBackground(nsIDOMElement* aElement,
139 int32_t aPosition)
140 {
141 // Note: We don't support aPosition on OS X.
142
143 // Get the image URI:
144 nsresult rv;
145 nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement,
146 &rv);
147 NS_ENSURE_SUCCESS(rv, rv);
148 nsCOMPtr<nsIURI> imageURI;
149 rv = imageContent->GetCurrentURI(getter_AddRefs(imageURI));
150 NS_ENSURE_SUCCESS(rv, rv);
151
152 // We need the referer URI for nsIWebBrowserPersist::saveURI
153 nsCOMPtr<nsIContent> content = do_QueryInterface(aElement, &rv);
154 NS_ENSURE_SUCCESS(rv, rv);
155
156 nsIURI *docURI = content->OwnerDoc()->GetDocumentURI();
157 if (!docURI)
158 return NS_ERROR_FAILURE;
159
160 // Get the desired image file name
161 nsCOMPtr<nsIURL> imageURL(do_QueryInterface(imageURI));
162 if (!imageURL) {
163 // XXXmano (bug 300293): Non-URL images (e.g. the data: protocol) are not
164 // yet supported. What filename should we take here?
165 return NS_ERROR_NOT_IMPLEMENTED;
166 }
167
168 nsAutoCString fileName;
169 imageURL->GetFileName(fileName);
170 nsCOMPtr<nsIProperties> fileLocator
171 (do_GetService("@mozilla.org/file/directory_service;1", &rv));
172 NS_ENSURE_SUCCESS(rv, rv);
173
174 // Get the current user's "Pictures" folder (That's ~/Pictures):
175 fileLocator->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile),
176 getter_AddRefs(mBackgroundFile));
177 if (!mBackgroundFile)
178 return NS_ERROR_OUT_OF_MEMORY;
179
180 nsAutoString fileNameUnicode;
181 CopyUTF8toUTF16(fileName, fileNameUnicode);
182
183 // and add the imgage file name itself:
184 mBackgroundFile->Append(fileNameUnicode);
185
186 // Download the image; the desktop background will be set in OnStateChange()
187 nsCOMPtr<nsIWebBrowserPersist> wbp
188 (do_CreateInstance("@mozilla.org/embedding/browser/nsWebBrowserPersist;1", &rv));
189 NS_ENSURE_SUCCESS(rv, rv);
190
191 uint32_t flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION |
192 nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES |
193 nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
194
195 wbp->SetPersistFlags(flags);
196 wbp->SetProgressListener(this);
197
198 nsCOMPtr<nsILoadContext> loadContext;
199 nsCOMPtr<nsISupports> container = content->OwnerDoc()->GetContainer();
200 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
201 if (docShell) {
202 loadContext = do_QueryInterface(docShell);
203 }
204
205 return wbp->SaveURI(imageURI, nullptr, docURI, nullptr, nullptr,
206 mBackgroundFile, loadContext);
207 }
208
209 NS_IMETHODIMP
210 nsMacShellService::OnProgressChange(nsIWebProgress* aWebProgress,
211 nsIRequest* aRequest,
212 int32_t aCurSelfProgress,
213 int32_t aMaxSelfProgress,
214 int32_t aCurTotalProgress,
215 int32_t aMaxTotalProgress)
216 {
217 return NS_OK;
218 }
219
220 NS_IMETHODIMP
221 nsMacShellService::OnLocationChange(nsIWebProgress* aWebProgress,
222 nsIRequest* aRequest,
223 nsIURI* aLocation,
224 uint32_t aFlags)
225 {
226 return NS_OK;
227 }
228
229 NS_IMETHODIMP
230 nsMacShellService::OnStatusChange(nsIWebProgress* aWebProgress,
231 nsIRequest* aRequest,
232 nsresult aStatus,
233 const char16_t* aMessage)
234 {
235 return NS_OK;
236 }
237
238 NS_IMETHODIMP
239 nsMacShellService::OnSecurityChange(nsIWebProgress* aWebProgress,
240 nsIRequest* aRequest,
241 uint32_t aState)
242 {
243 return NS_OK;
244 }
245
246 NS_IMETHODIMP
247 nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress,
248 nsIRequest* aRequest,
249 uint32_t aStateFlags,
250 nsresult aStatus)
251 {
252 if (aStateFlags & STATE_STOP) {
253 nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1"));
254 if (os)
255 os->NotifyObservers(nullptr, "shell:desktop-background-changed", nullptr);
256
257 bool exists = false;
258 mBackgroundFile->Exists(&exists);
259 if (!exists)
260 return NS_OK;
261
262 nsAutoCString nativePath;
263 mBackgroundFile->GetNativePath(nativePath);
264
265 AEDesc tAEDesc = { typeNull, nil };
266 OSErr err = noErr;
267 AliasHandle aliasHandle = nil;
268 FSRef pictureRef;
269 OSStatus status;
270
271 // Convert the path into a FSRef
272 status = ::FSPathMakeRef((const UInt8*)nativePath.get(), &pictureRef,
273 nullptr);
274 if (status == noErr) {
275 err = ::FSNewAlias(nil, &pictureRef, &aliasHandle);
276 if (err == noErr && aliasHandle == nil)
277 err = paramErr;
278
279 if (err == noErr) {
280 // We need the descriptor (based on the picture file reference)
281 // for the 'Set Desktop Picture' apple event.
282 char handleState = ::HGetState((Handle)aliasHandle);
283 ::HLock((Handle)aliasHandle);
284 err = ::AECreateDesc(typeAlias, *aliasHandle,
285 GetHandleSize((Handle)aliasHandle), &tAEDesc);
286 // unlock the alias handler
287 ::HSetState((Handle)aliasHandle, handleState);
288 ::DisposeHandle((Handle)aliasHandle);
289 }
290 if (err == noErr) {
291 AppleEvent tAppleEvent;
292 OSType sig = 'MACS';
293 AEBuildError tAEBuildError;
294 // Create a 'Set Desktop Pictue' Apple Event
295 err = ::AEBuildAppleEvent(kAECoreSuite, kAESetData, typeApplSignature,
296 &sig, sizeof(OSType), kAutoGenerateReturnID,
297 kAnyTransactionID, &tAppleEvent, &tAEBuildError,
298 "'----':'obj '{want:type (prop),form:prop" \
299 ",seld:type('dpic'),from:'null'()},data:(@)",
300 &tAEDesc);
301 if (err == noErr) {
302 AppleEvent reply = { typeNull, nil };
303 // Sent the event we built, the reply event isn't necessary
304 err = ::AESend(&tAppleEvent, &reply, kAENoReply, kAENormalPriority,
305 kNoTimeOut, nil, nil);
306 ::AEDisposeDesc(&tAppleEvent);
307 }
308 }
309 }
310 }
311
312 return NS_OK;
313 }
314
315 NS_IMETHODIMP
316 nsMacShellService::OpenApplication(int32_t aApplication)
317 {
318 nsresult rv = NS_OK;
319 CFURLRef appURL = nil;
320 OSStatus err = noErr;
321
322 switch (aApplication) {
323 case nsIShellService::APPLICATION_MAIL:
324 {
325 CFURLRef tempURL = ::CFURLCreateWithString(kCFAllocatorDefault,
326 CFSTR("mailto:"), nullptr);
327 err = ::LSGetApplicationForURL(tempURL, kLSRolesAll, nullptr, &appURL);
328 ::CFRelease(tempURL);
329 }
330 break;
331 case nsIShellService::APPLICATION_NEWS:
332 {
333 CFURLRef tempURL = ::CFURLCreateWithString(kCFAllocatorDefault,
334 CFSTR("news:"), nullptr);
335 err = ::LSGetApplicationForURL(tempURL, kLSRolesAll, nullptr, &appURL);
336 ::CFRelease(tempURL);
337 }
338 break;
339 case nsIMacShellService::APPLICATION_KEYCHAIN_ACCESS:
340 err = ::LSGetApplicationForInfo('APPL', 'kcmr', nullptr, kLSRolesAll,
341 nullptr, &appURL);
342 break;
343 case nsIMacShellService::APPLICATION_NETWORK:
344 {
345 nsCOMPtr<nsIFile> lf;
346 rv = NS_NewNativeLocalFile(NETWORK_PREFPANE, true, getter_AddRefs(lf));
347 NS_ENSURE_SUCCESS(rv, rv);
348 bool exists;
349 lf->Exists(&exists);
350 if (!exists)
351 return NS_ERROR_FILE_NOT_FOUND;
352 return lf->Launch();
353 }
354 break;
355 case nsIMacShellService::APPLICATION_DESKTOP:
356 {
357 nsCOMPtr<nsIFile> lf;
358 rv = NS_NewNativeLocalFile(DESKTOP_PREFPANE, true, getter_AddRefs(lf));
359 NS_ENSURE_SUCCESS(rv, rv);
360 bool exists;
361 lf->Exists(&exists);
362 if (!exists)
363 return NS_ERROR_FILE_NOT_FOUND;
364 return lf->Launch();
365 }
366 break;
367 }
368
369 if (appURL && err == noErr) {
370 err = ::LSOpenCFURLRef(appURL, nullptr);
371 rv = err != noErr ? NS_ERROR_FAILURE : NS_OK;
372
373 ::CFRelease(appURL);
374 }
375
376 return rv;
377 }
378
379 NS_IMETHODIMP
380 nsMacShellService::GetDesktopBackgroundColor(uint32_t *aColor)
381 {
382 // This method and |SetDesktopBackgroundColor| has no meaning on Mac OS X.
383 // The mac desktop preferences UI uses pictures for the few solid colors it
384 // supports.
385 return NS_ERROR_NOT_IMPLEMENTED;
386 }
387
388 NS_IMETHODIMP
389 nsMacShellService::SetDesktopBackgroundColor(uint32_t aColor)
390 {
391 // This method and |GetDesktopBackgroundColor| has no meaning on Mac OS X.
392 // The mac desktop preferences UI uses pictures for the few solid colors it
393 // supports.
394 return NS_ERROR_NOT_IMPLEMENTED;
395 }
396
397 NS_IMETHODIMP
398 nsMacShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI)
399 {
400 nsCOMPtr<nsILocalFileMac> lfm(do_QueryInterface(aApplication));
401 CFURLRef appURL;
402 nsresult rv = lfm->GetCFURL(&appURL);
403 if (NS_FAILED(rv))
404 return rv;
405
406 const nsCString spec(aURI);
407 const UInt8* uriString = (const UInt8*)spec.get();
408 CFURLRef uri = ::CFURLCreateWithBytes(nullptr, uriString, aURI.Length(),
409 kCFStringEncodingUTF8, nullptr);
410 if (!uri)
411 return NS_ERROR_OUT_OF_MEMORY;
412
413 CFArrayRef uris = ::CFArrayCreate(nullptr, (const void**)&uri, 1, nullptr);
414 if (!uris) {
415 ::CFRelease(uri);
416 return NS_ERROR_OUT_OF_MEMORY;
417 }
418
419 LSLaunchURLSpec launchSpec;
420 launchSpec.appURL = appURL;
421 launchSpec.itemURLs = uris;
422 launchSpec.passThruParams = nullptr;
423 launchSpec.launchFlags = kLSLaunchDefaults;
424 launchSpec.asyncRefCon = nullptr;
425
426 OSErr err = ::LSOpenFromURLSpec(&launchSpec, nullptr);
427
428 ::CFRelease(uris);
429 ::CFRelease(uri);
430
431 return err != noErr ? NS_ERROR_FAILURE : NS_OK;
432 }
433
434 NS_IMETHODIMP
435 nsMacShellService::GetDefaultFeedReader(nsIFile** _retval)
436 {
437 nsresult rv = NS_ERROR_FAILURE;
438 *_retval = nullptr;
439
440 CFStringRef defaultHandlerID = ::LSCopyDefaultHandlerForURLScheme(CFSTR("feed"));
441 if (!defaultHandlerID) {
442 defaultHandlerID = ::CFStringCreateWithCString(kCFAllocatorDefault,
443 SAFARI_BUNDLE_IDENTIFIER,
444 kCFStringEncodingASCII);
445 }
446
447 CFURLRef defaultHandlerURL = nullptr;
448 OSStatus status = ::LSFindApplicationForInfo(kLSUnknownCreator,
449 defaultHandlerID,
450 nullptr, // inName
451 nullptr, // outAppRef
452 &defaultHandlerURL);
453
454 if (status == noErr && defaultHandlerURL) {
455 nsCOMPtr<nsILocalFileMac> defaultReader =
456 do_CreateInstance("@mozilla.org/file/local;1", &rv);
457 if (NS_SUCCEEDED(rv)) {
458 rv = defaultReader->InitWithCFURL(defaultHandlerURL);
459 if (NS_SUCCEEDED(rv)) {
460 NS_ADDREF(*_retval = defaultReader);
461 rv = NS_OK;
462 }
463 }
464
465 ::CFRelease(defaultHandlerURL);
466 }
467
468 ::CFRelease(defaultHandlerID);
469
470 return rv;
471 }

mercurial