Bug 1629313 - Part 1 - Set As Desktop Background fails on macOS r=spohl

Change the nsMacShellService::SetDesktopBackground() implementation (specifically code in the OnStateChange handler) to use the Apple setDesktopImageURL API instead of Apple Events to allow the "Set As Desktop Background..." context menu option to work again.

Alternatively, to allow the AppleEvent-base implementation to work again, Firefox could be signed with the com.apple.security.automation.apple-events entitlement but this would also require the user to grant Firefox permission to control Finder. setDesktopImageURL requires Mac OS 10.6 or newer and hence was not an option originally.

The implementation only changes the background of the focused screen in the current workspace (which matches the behavior of Safari).

Differential Revision: https://phabricator.services.mozilla.com/D71426
This commit is contained in:
Haik Aftandilian
2020-04-21 19:57:29 +00:00
parent 1a2949ad08
commit ccc8fec0cf
4 changed files with 96 additions and 50 deletions

View File

@@ -18,12 +18,14 @@
#include "nsIDocShell.h"
#include "nsILoadContext.h"
#include "mozilla/dom/Element.h"
#include "DesktopBackgroundImage.h"
#include <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include <ApplicationServices/ApplicationServices.h>
using mozilla::dom::Element;
using mozilla::widget::SetDesktopImage;
#define NETWORK_PREFPANE \
NS_LITERAL_CSTRING("/System/Library/PreferencePanes/Network.prefPane")
@@ -206,57 +208,12 @@ nsMacShellService::OnStateChange(nsIWebProgress* aWebProgress,
os->NotifyObservers(nullptr, "shell:desktop-background-changed", nullptr);
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 Pictue' 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};
// Sent the event we built, the reply event isn't necessary
err = ::AESend(&tAppleEvent, &reply, kAENoReply, kAENormalPriority,
kNoTimeOut, nil, nil);
::AEDisposeDesc(&tAppleEvent);
}
}
nsresult rv = mBackgroundFile->Exists(&exists);
if (NS_FAILED(rv) || !exists) {
return NS_OK;
}
SetDesktopImage(mBackgroundFile);
}
return NS_OK;