nsMacShellService.cpp (11740B)
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 "CocoaFileUtils.h" 7 #include "nsDirectoryServiceDefs.h" 8 #include "nsIImageLoadingContent.h" 9 #include "mozilla/dom/Document.h" 10 #include "nsComponentManagerUtils.h" 11 #include "nsIContent.h" 12 #include "nsICookieJarSettings.h" 13 #include "nsIObserverService.h" 14 #include "nsIWebBrowserPersist.h" 15 #include "nsMacShellService.h" 16 #include "nsIProperties.h" 17 #include "nsServiceManagerUtils.h" 18 #include "nsShellService.h" 19 #include "nsString.h" 20 #include "nsIDocShell.h" 21 #include "nsILoadContext.h" 22 #include "nsIPrefService.h" 23 #include "mozilla/dom/Element.h" 24 #include "mozilla/dom/ReferrerInfo.h" 25 #include "DesktopBackgroundImage.h" 26 27 #include <Carbon/Carbon.h> 28 #include <CoreFoundation/CoreFoundation.h> 29 #include <ApplicationServices/ApplicationServices.h> 30 31 using mozilla::dom::Element; 32 using mozilla::widget::SetDesktopImage; 33 34 #define NETWORK_PREFPANE "/System/Library/PreferencePanes/Network.prefPane"_ns 35 #define DESKTOP_PREFPANE \ 36 nsLiteralCString( \ 37 "/System/Library/PreferencePanes/DesktopScreenEffectsPref.prefPane") 38 39 #define SAFARI_BUNDLE_IDENTIFIER "com.apple.Safari" 40 41 NS_IMPL_ISUPPORTS(nsMacShellService, nsIMacShellService, nsIShellService, 42 nsIToolkitShellService, nsIWebProgressListener) 43 44 NS_IMETHODIMP 45 nsMacShellService::IsDefaultBrowser(bool aForAllTypes, 46 bool* aIsDefaultBrowser) { 47 *aIsDefaultBrowser = false; 48 49 CFStringRef firefoxID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle()); 50 if (!firefoxID) { 51 // CFBundleGetIdentifier is expected to return nullptr only if the specified 52 // bundle doesn't have a bundle identifier in its plist. In this case, that 53 // means a failure, since our bundle does have an identifier. 54 return NS_ERROR_FAILURE; 55 } 56 57 // Get the default http handler's bundle ID (or nullptr if it has not been 58 // explicitly set) 59 CFStringRef defaultBrowserID = 60 ::LSCopyDefaultHandlerForURLScheme(CFSTR("http")); 61 if (defaultBrowserID) { 62 *aIsDefaultBrowser = 63 ::CFStringCompare(firefoxID, defaultBrowserID, 0) == kCFCompareEqualTo; 64 ::CFRelease(defaultBrowserID); 65 } 66 67 return NS_OK; 68 } 69 70 NS_IMETHODIMP 71 nsMacShellService::SetDefaultBrowser(bool aForAllUsers) { 72 // Note: We don't support aForAllUsers on Mac OS X. 73 74 CFStringRef firefoxID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle()); 75 if (!firefoxID) { 76 return NS_ERROR_FAILURE; 77 } 78 79 if (::LSSetDefaultHandlerForURLScheme(CFSTR("http"), firefoxID) != noErr) { 80 return NS_ERROR_FAILURE; 81 } 82 if (::LSSetDefaultHandlerForURLScheme(CFSTR("https"), firefoxID) != noErr) { 83 return NS_ERROR_FAILURE; 84 } 85 86 if (::LSSetDefaultRoleHandlerForContentType(kUTTypeHTML, kLSRolesAll, 87 firefoxID) != noErr) { 88 return NS_ERROR_FAILURE; 89 } 90 91 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); 92 if (prefs) { 93 (void)prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true); 94 // Reset the number of times the dialog should be shown 95 // before it is silenced. 96 (void)prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0); 97 } 98 99 return NS_OK; 100 } 101 102 NS_IMETHODIMP 103 nsMacShellService::SetDesktopBackground(Element* aElement, int32_t aPosition, 104 const nsACString& aImageName) { 105 // Note: We don't support aPosition on OS X. 106 107 // Get the image URI: 108 nsresult rv; 109 nsCOMPtr<nsIImageLoadingContent> imageContent = 110 do_QueryInterface(aElement, &rv); 111 NS_ENSURE_SUCCESS(rv, rv); 112 nsCOMPtr<nsIURI> imageURI; 113 rv = imageContent->GetCurrentURI(getter_AddRefs(imageURI)); 114 NS_ENSURE_SUCCESS(rv, rv); 115 116 nsIURI* docURI = aElement->OwnerDoc()->GetDocumentURI(); 117 if (!docURI) return NS_ERROR_FAILURE; 118 119 nsCOMPtr<nsIProperties> fileLocator( 120 do_GetService("@mozilla.org/file/directory_service;1", &rv)); 121 NS_ENSURE_SUCCESS(rv, rv); 122 123 // Get the current user's "Pictures" folder (That's ~/Pictures): 124 fileLocator->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), 125 getter_AddRefs(mBackgroundFile)); 126 if (!mBackgroundFile) return NS_ERROR_OUT_OF_MEMORY; 127 128 nsAutoString fileNameUnicode; 129 CopyUTF8toUTF16(aImageName, fileNameUnicode); 130 131 // and add the imgage file name itself: 132 mBackgroundFile->Append(fileNameUnicode); 133 134 // Download the image; the desktop background will be set in OnStateChange() 135 nsCOMPtr<nsIWebBrowserPersist> wbp(do_CreateInstance( 136 "@mozilla.org/embedding/browser/nsWebBrowserPersist;1", &rv)); 137 NS_ENSURE_SUCCESS(rv, rv); 138 139 uint32_t flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION | 140 nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES | 141 nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE; 142 143 wbp->SetPersistFlags(flags); 144 wbp->SetProgressListener(this); 145 146 nsCOMPtr<nsILoadContext> loadContext; 147 nsCOMPtr<nsISupports> container = aElement->OwnerDoc()->GetContainer(); 148 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container); 149 if (docShell) { 150 loadContext = do_QueryInterface(docShell); 151 } 152 153 auto referrerInfo = 154 mozilla::MakeRefPtr<mozilla::dom::ReferrerInfo>(*aElement); 155 156 nsCOMPtr<nsICookieJarSettings> cookieJarSettings = 157 aElement->OwnerDoc()->CookieJarSettings(); 158 return wbp->SaveURI(imageURI, aElement->NodePrincipal(), 0, referrerInfo, 159 cookieJarSettings, nullptr, nullptr, mBackgroundFile, 160 nsIContentPolicy::TYPE_IMAGE, 161 loadContext->UsePrivateBrowsing()); 162 } 163 164 NS_IMETHODIMP 165 nsMacShellService::OnProgressChange(nsIWebProgress* aWebProgress, 166 nsIRequest* aRequest, 167 int32_t aCurSelfProgress, 168 int32_t aMaxSelfProgress, 169 int32_t aCurTotalProgress, 170 int32_t aMaxTotalProgress) { 171 return NS_OK; 172 } 173 174 NS_IMETHODIMP 175 nsMacShellService::OnLocationChange(nsIWebProgress* aWebProgress, 176 nsIRequest* aRequest, nsIURI* aLocation, 177 uint32_t aFlags) { 178 return NS_OK; 179 } 180 181 NS_IMETHODIMP 182 nsMacShellService::OnStatusChange(nsIWebProgress* aWebProgress, 183 nsIRequest* aRequest, nsresult aStatus, 184 const char16_t* aMessage) { 185 return NS_OK; 186 } 187 188 NS_IMETHODIMP 189 nsMacShellService::OnSecurityChange(nsIWebProgress* aWebProgress, 190 nsIRequest* aRequest, uint32_t aState) { 191 return NS_OK; 192 } 193 194 NS_IMETHODIMP 195 nsMacShellService::OnContentBlockingEvent(nsIWebProgress* aWebProgress, 196 nsIRequest* aRequest, 197 uint32_t aEvent) { 198 return NS_OK; 199 } 200 201 NS_IMETHODIMP 202 nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress, 203 nsIRequest* aRequest, uint32_t aStateFlags, 204 nsresult aStatus) { 205 if (NS_SUCCEEDED(aStatus) && (aStateFlags & STATE_STOP) && 206 (aRequest == nullptr)) { 207 nsCOMPtr<nsIObserverService> os( 208 do_GetService("@mozilla.org/observer-service;1")); 209 if (os) 210 os->NotifyObservers(nullptr, "shell:desktop-background-changed", nullptr); 211 212 bool exists = false; 213 nsresult rv = mBackgroundFile->Exists(&exists); 214 if (NS_FAILED(rv) || !exists) { 215 return NS_OK; 216 } 217 218 SetDesktopImage(mBackgroundFile); 219 } 220 221 return NS_OK; 222 } 223 224 NS_IMETHODIMP 225 nsMacShellService::ShowDesktopPreferences() { 226 nsCOMPtr<nsIFile> lf; 227 nsresult rv = NS_NewNativeLocalFile(DESKTOP_PREFPANE, getter_AddRefs(lf)); 228 NS_ENSURE_SUCCESS(rv, rv); 229 bool exists; 230 lf->Exists(&exists); 231 if (!exists) return NS_ERROR_FILE_NOT_FOUND; 232 return lf->Launch(); 233 } 234 235 NS_IMETHODIMP 236 nsMacShellService::GetDesktopBackgroundColor(uint32_t* aColor) { 237 // This method and |SetDesktopBackgroundColor| has no meaning on Mac OS X. 238 // The mac desktop preferences UI uses pictures for the few solid colors it 239 // supports. 240 return NS_ERROR_NOT_IMPLEMENTED; 241 } 242 243 NS_IMETHODIMP 244 nsMacShellService::SetDesktopBackgroundColor(uint32_t aColor) { 245 // This method and |GetDesktopBackgroundColor| has no meaning on Mac OS X. 246 // The mac desktop preferences UI uses pictures for the few solid colors it 247 // supports. 248 return NS_ERROR_NOT_IMPLEMENTED; 249 } 250 251 NS_IMETHODIMP 252 nsMacShellService::ShowSecurityPreferences(const nsACString& aPaneID) { 253 nsresult rv = NS_ERROR_NOT_AVAILABLE; 254 255 CFStringRef paneID = ::CFStringCreateWithBytes( 256 kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aPaneID).get(), 257 aPaneID.Length(), kCFStringEncodingUTF8, false); 258 259 if (paneID) { 260 CFStringRef format = 261 CFSTR("x-apple.systempreferences:com.apple.preference.security?%@"); 262 if (format) { 263 CFStringRef urlStr = 264 CFStringCreateWithFormat(kCFAllocatorDefault, NULL, format, paneID); 265 if (urlStr) { 266 CFURLRef url = ::CFURLCreateWithString(NULL, urlStr, NULL); 267 rv = CocoaFileUtils::OpenURL(url); 268 269 ::CFRelease(urlStr); 270 } 271 272 ::CFRelease(format); 273 } 274 275 ::CFRelease(paneID); 276 } 277 return rv; 278 } 279 280 nsString ConvertCFStringToNSString(CFStringRef aSrc) { 281 nsString aDest; 282 auto len = ::CFStringGetLength(aSrc); 283 aDest.SetLength(len); 284 ::CFStringGetCharacters(aSrc, ::CFRangeMake(0, len), 285 (UniChar*)aDest.BeginWriting()); 286 return aDest; 287 } 288 289 NS_IMETHODIMP 290 nsMacShellService::GetAvailableApplicationsForProtocol( 291 const nsACString& protocol, nsTArray<nsTArray<nsString>>& aHandlerPaths) { 292 class CFTypeRefAutoDeleter { 293 public: 294 explicit CFTypeRefAutoDeleter(CFTypeRef ref) : mRef(ref) {} 295 ~CFTypeRefAutoDeleter() { 296 if (mRef != NULL) ::CFRelease(mRef); 297 } 298 299 private: 300 CFTypeRef mRef; 301 }; 302 303 aHandlerPaths.Clear(); 304 nsCString protocolSep = protocol + "://"_ns; 305 CFStringRef cfProtocol = ::CFStringCreateWithBytes( 306 kCFAllocatorDefault, (const UInt8*)protocolSep.BeginReading(), 307 protocolSep.Length(), kCFStringEncodingUTF8, false); 308 CFTypeRefAutoDeleter cfProtocolAuto((CFTypeRef)cfProtocol); 309 if (cfProtocol == NULL) { 310 return NS_ERROR_ILLEGAL_VALUE; 311 } 312 CFURLRef protocolURL = 313 ::CFURLCreateWithString(kCFAllocatorDefault, cfProtocol, NULL); 314 CFTypeRefAutoDeleter cfProtocolURLAuto((CFTypeRef)protocolURL); 315 if (protocolURL == NULL) { 316 return NS_ERROR_MALFORMED_URI; 317 } 318 CFArrayRef appURLs = ::LSCopyApplicationURLsForURL(protocolURL, kLSRolesAll); 319 CFTypeRefAutoDeleter cfAppURLsAuto((CFTypeRef)appURLs); 320 if (appURLs == NULL) { 321 return NS_ERROR_NOT_AVAILABLE; 322 } 323 for (CFIndex i = 0; i < ::CFArrayGetCount(appURLs); i++) { 324 CFURLRef appURL = (CFURLRef)::CFArrayGetValueAtIndex(appURLs, i); 325 CFBundleRef appBundle = ::CFBundleCreate(kCFAllocatorDefault, appURL); 326 CFTypeRefAutoDeleter cfAppBundleAuto((CFTypeRef)appBundle); 327 if (appBundle == NULL) { 328 continue; 329 } 330 CFDictionaryRef appInfo = ::CFBundleGetInfoDictionary(appBundle); 331 if (appInfo == NULL) { 332 continue; 333 } 334 CFStringRef displayName = 335 (CFStringRef)::CFDictionaryGetValue(appInfo, kCFBundleNameKey); 336 if (displayName == NULL) { 337 continue; 338 } 339 CFStringRef appPath = ::CFURLGetString(appURL); 340 nsTArray<nsString> handlerPath = {ConvertCFStringToNSString(displayName), 341 ConvertCFStringToNSString(appPath)}; 342 aHandlerPaths.AppendElement(handlerPath.Clone()); 343 } 344 return NS_OK; 345 }