summaryrefslogtreecommitdiffstats
path: root/comm/suite/components/shell/nsMacShellService.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/suite/components/shell/nsMacShellService.cpp
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/suite/components/shell/nsMacShellService.cpp')
-rw-r--r--comm/suite/components/shell/nsMacShellService.cpp398
1 files changed, 398 insertions, 0 deletions
diff --git a/comm/suite/components/shell/nsMacShellService.cpp b/comm/suite/components/shell/nsMacShellService.cpp
new file mode 100644
index 0000000000..6aa8aa3088
--- /dev/null
+++ b/comm/suite/components/shell/nsMacShellService.cpp
@@ -0,0 +1,398 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDirectoryServiceDefs.h"
+#include "nsIImageLoadingContent.h"
+#include "mozilla/dom/Document.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIContent.h"
+#include "nsICookieJarSettings.h"
+#include "nsILocalFileMac.h"
+#include "nsIObserverService.h"
+#include "nsIPrefService.h"
+#include "nsIServiceManager.h"
+#include "nsIStringBundle.h"
+#include "nsIURL.h"
+#include "nsIWebBrowserPersist.h"
+#include "nsMacShellService.h"
+#include "nsIProperties.h"
+#include "nsServiceManagerUtils.h"
+#include "nsShellService.h"
+#include "nsString.h"
+#include "nsIDocShell.h"
+#include "nsILoadContext.h"
+#include "nsIPrefService.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/ReferrerInfo.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#define SAFARI_BUNDLE_IDENTIFIER "com.apple.Safari"
+
+using mozilla::dom::Element;
+
+NS_IMPL_ISUPPORTS(nsMacShellService, nsIShellService, nsIWebProgressListener)
+
+NS_IMETHODIMP
+nsMacShellService::IsDefaultClient(bool aStartupCheck, uint16_t aApps, bool *aIsDefaultClient)
+{
+ *aIsDefaultClient = false;
+
+ if (aApps & nsIShellService::BROWSER)
+ if(!isDefaultHandlerForProtocol(CFSTR("http")))
+ return NS_OK;
+ if (aApps & nsIShellService::MAIL)
+ if(!isDefaultHandlerForProtocol(CFSTR("mailto")))
+ return NS_OK;
+ if (aApps & nsIShellService::NEWS)
+ if(!isDefaultHandlerForProtocol(CFSTR("news")))
+ return NS_OK;
+ if (aApps & nsIShellService::RSS)
+ if(!isDefaultHandlerForProtocol(CFSTR("feed")))
+ return NS_OK;
+
+ *aIsDefaultClient = true;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::SetDefaultClient(bool aForAllUsers,
+ bool aClaimAllTypes, uint16_t aApps)
+{
+ // Note: We don't support aForAllUsers on macOS.
+
+ CFStringRef suiteID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
+ if (!suiteID)
+ return NS_ERROR_FAILURE;
+
+ if (aApps & nsIShellService::BROWSER)
+ {
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("http"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("https"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (::LSSetDefaultRoleHandlerForContentType(kUTTypeHTML, kLSRolesAll, suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (::LSSetDefaultRoleHandlerForContentType(CFSTR("public.xhtml"), kLSRolesAll, suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ }
+
+ if (aApps & nsIShellService::MAIL)
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("mailto"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (aApps & nsIShellService::NEWS)
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("news"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+ if (aApps & nsIShellService::RSS)
+ if (::LSSetDefaultHandlerForURLScheme(CFSTR("feed"), suiteID) != noErr)
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+bool
+nsMacShellService::isDefaultHandlerForProtocol(CFStringRef aScheme)
+{
+ bool isDefault = false;
+
+ CFStringRef suiteID = ::CFBundleGetIdentifier(::CFBundleGetMainBundle());
+ if (!suiteID)
+ {
+ // CFBundleGetIdentifier is expected to return nullptr only if the specified
+ // bundle doesn't have a bundle identifier in its dictionary. In this case,
+ // that means a failure, since our bundle does have an identifier.
+ return isDefault;
+ }
+
+ // Get the default handler's bundle ID for the scheme.
+ CFStringRef defaultHandlerID = ::LSCopyDefaultHandlerForURLScheme(aScheme);
+ if (defaultHandlerID)
+ {
+ // The handler ID in LaunchServices is in all lower case, but the bundle
+ // identifier could have upper case characters. So we're using
+ // CFStringCompare with the kCFCompareCaseInsensitive option here.
+ isDefault = ::CFStringCompare(suiteID, defaultHandlerID,
+ kCFCompareCaseInsensitive) == kCFCompareEqualTo;
+ ::CFRelease(defaultHandlerID);
+ }
+
+ return isDefault;
+}
+
+NS_IMETHODIMP
+nsMacShellService::SetDesktopBackground(Element* aElement,
+ int32_t aPosition,
+ const nsACString& aImageName)
+{
+ // Note: We don't support aPosition on OS X.
+
+ // Get the image URI:
+ nsresult rv;
+ nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIURI> imageURI;
+ rv = imageContent->GetCurrentURI(getter_AddRefs(imageURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsIURI *docURI = aElement->OwnerDoc()->GetDocumentURI();
+ if (!docURI)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIProperties> fileLocator
+ (do_GetService("@mozilla.org/file/directory_service;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Get the current user's "Pictures" folder (That's ~/Pictures):
+ fileLocator->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile),
+ getter_AddRefs(mBackgroundFile));
+ if (!mBackgroundFile)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsAutoString fileNameUnicode;
+ CopyUTF8toUTF16(aImageName, fileNameUnicode);
+
+ // and add the image file name itself:
+ mBackgroundFile->Append(fileNameUnicode);
+
+ // Download the image; the desktop background will be set in OnStateChange():
+ nsCOMPtr<nsIWebBrowserPersist> wbp
+ (do_CreateInstance("@mozilla.org/embedding/browser/nsWebBrowserPersist;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION |
+ nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES |
+ nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
+
+ wbp->SetPersistFlags(flags);
+ wbp->SetProgressListener(this);
+
+ nsCOMPtr<nsILoadContext> loadContext;
+ nsCOMPtr<nsISupports> container = aElement->OwnerDoc()->GetContainer();
+ nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
+ if (docShell)
+ {
+ loadContext = do_QueryInterface(docShell);
+ }
+
+ auto referrerInfo = mozilla::MakeRefPtr<mozilla::dom::ReferrerInfo>(*aElement);
+ nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
+ aElement->OwnerDoc()->CookieJarSettings();
+ return wbp->SaveURI(imageURI, aElement->NodePrincipal(), 0, referrerInfo,
+ cookieJarSettings, nullptr, nullptr, mBackgroundFile,
+ nsIContentPolicy::TYPE_IMAGE, loadContext);
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnProgressChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ int32_t aCurSelfProgress,
+ int32_t aMaxSelfProgress,
+ int32_t aCurTotalProgress,
+ int32_t aMaxTotalProgress)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnLocationChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ nsIURI* aLocation,
+ uint32_t aFlags)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnStatusChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ nsresult aStatus,
+ const char16_t* aMessage)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnSecurityChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ uint32_t aState)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ uint32_t aEvent) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ uint32_t aStateFlags,
+ nsresult aStatus)
+{
+ if (aStateFlags & STATE_STOP)
+ {
+ bool exists = false;
+ mBackgroundFile->Exists(&exists);
+ if (!exists)
+ return NS_OK;
+
+ nsAutoCString nativePath;
+ mBackgroundFile->GetNativePath(nativePath);
+
+ AEDesc tAEDesc = { typeNull, nil };
+ OSErr err = noErr;
+ AliasHandle aliasHandle = nil;
+ FSRef pictureRef;
+ OSStatus status;
+
+ // Convert the path into a FSRef:
+ status = ::FSPathMakeRef((const UInt8*)nativePath.get(), &pictureRef,
+ nullptr);
+ if (status == noErr)
+ {
+ err = ::FSNewAlias(nil, &pictureRef, &aliasHandle);
+ if (err == noErr && aliasHandle == nil)
+ err = paramErr;
+
+ if (err == noErr)
+ {
+ // We need the descriptor (based on the picture file reference)
+ // for the 'Set Desktop Picture' apple event.
+ char handleState = ::HGetState((Handle)aliasHandle);
+ ::HLock((Handle)aliasHandle);
+ err = ::AECreateDesc(typeAlias, *aliasHandle,
+ GetHandleSize((Handle)aliasHandle), &tAEDesc);
+ // Unlock the alias handler:
+ ::HSetState((Handle)aliasHandle, handleState);
+ ::DisposeHandle((Handle)aliasHandle);
+ }
+ if (err == noErr)
+ {
+ AppleEvent tAppleEvent;
+ OSType sig = 'MACS';
+ AEBuildError tAEBuildError;
+ // Create a 'Set Desktop Picture' Apple Event:
+ err = ::AEBuildAppleEvent(kAECoreSuite, kAESetData, typeApplSignature,
+ &sig, sizeof(OSType), kAutoGenerateReturnID,
+ kAnyTransactionID, &tAppleEvent, &tAEBuildError,
+ "'----':'obj '{want:type (prop),form:prop" \
+ ",seld:type('dpic'),from:'null'()},data:(@)",
+ &tAEDesc);
+ if (err == noErr)
+ {
+ AppleEvent reply = { typeNull, nil };
+ // Send the event we built, the reply event isn't necessary:
+ err = ::AESend(&tAppleEvent, &reply, kAENoReply, kAENormalPriority,
+ kNoTimeOut, nil, nil);
+ ::AEDisposeDesc(&tAppleEvent);
+ }
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::GetDesktopBackgroundColor(uint32_t *aColor)
+{
+ // This method and |SetDesktopBackgroundColor| has no meaning on macOS.
+ // The mac desktop preferences UI uses pictures for the few solid colors it
+ // supports.
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsMacShellService::SetDesktopBackgroundColor(uint32_t aColor)
+{
+ // This method and |GetDesktopBackgroundColor| has no meaning on macOS.
+ // The mac desktop preferences UI uses pictures for the few solid colors it
+ // supports.
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsMacShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI)
+{
+ nsCOMPtr<nsILocalFileMac> lfm(do_QueryInterface(aApplication));
+ CFURLRef appURL;
+ nsresult rv = lfm->GetCFURL(&appURL);
+ if (NS_FAILED(rv))
+ return rv;
+
+ const nsCString& spec = PromiseFlatCString(aURI);
+ const UInt8* uriString = (const UInt8*)spec.get();
+ CFURLRef uri = ::CFURLCreateWithBytes(nullptr, uriString, aURI.Length(),
+ kCFStringEncodingUTF8, nullptr);
+ if (!uri)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ CFArrayRef uris = ::CFArrayCreate(nullptr, (const void**)&uri, 1, nullptr);
+ if (!uris)
+ {
+ ::CFRelease(uri);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ LSLaunchURLSpec launchSpec;
+ launchSpec.appURL = appURL;
+ launchSpec.itemURLs = uris;
+ launchSpec.passThruParams = nullptr;
+ launchSpec.launchFlags = kLSLaunchDefaults;
+ launchSpec.asyncRefCon = nullptr;
+
+ OSErr err = ::LSOpenFromURLSpec(&launchSpec, nullptr);
+
+ ::CFRelease(uris);
+ ::CFRelease(uri);
+
+ return err != noErr ? NS_ERROR_FAILURE : NS_OK;
+}
+
+NS_IMETHODIMP
+nsMacShellService::GetDefaultFeedReader(nsIFile** _retval)
+{
+ nsresult rv = NS_ERROR_FAILURE;
+ *_retval = nullptr;
+
+ CFStringRef defaultHandlerID = ::LSCopyDefaultHandlerForURLScheme(CFSTR("feed"));
+ if (!defaultHandlerID)
+ {
+ defaultHandlerID = ::CFStringCreateWithCString(kCFAllocatorDefault,
+ SAFARI_BUNDLE_IDENTIFIER,
+ kCFStringEncodingASCII);
+ }
+
+ CFURLRef defaultHandlerURL = nullptr;
+ OSStatus status = ::LSFindApplicationForInfo(kLSUnknownCreator,
+ defaultHandlerID,
+ nullptr, // inName
+ nullptr, // outAppRef
+ &defaultHandlerURL);
+
+ if (status == noErr && defaultHandlerURL)
+ {
+ nsCOMPtr<nsILocalFileMac> defaultReader =
+ do_CreateInstance("@mozilla.org/file/local;1", &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = defaultReader->InitWithCFURL(defaultHandlerURL);
+ if (NS_SUCCEEDED(rv))
+ {
+ NS_ADDREF(*_retval = defaultReader);
+ }
+ }
+
+ ::CFRelease(defaultHandlerURL);
+ }
+
+ ::CFRelease(defaultHandlerID);
+
+ return rv;
+}