зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1851529 - Set clang-format ColumnLimit consistently. r=sylvestre,necko-reviewers,kershaw
For some reason, its value in the Google style we use is 80... except for Objective-C, where it's 100, which led to things like: https://hg.mozilla.org/mozilla-central/rev/31bf68247e6e https://hg.mozilla.org/mozilla-central/rev/64ceb33533a4. There's probably a discussion to have about whether 80 is the right limit, but since it's what's used for everything except ObjC, let's roll with it. # ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D187409
This commit is contained in:
Родитель
ccc3244a24
Коммит
9331b9fb07
|
@ -1,4 +1,5 @@
|
|||
BasedOnStyle: Google
|
||||
ColumnLimit: 80
|
||||
|
||||
# Prevent the loss of indentation with these macros
|
||||
MacroBlockBegin: "^\
|
||||
|
|
|
@ -24,27 +24,32 @@ using namespace mozilla::a11y;
|
|||
|
||||
// xpcAccessibleMacNSObjectWrapper
|
||||
|
||||
NS_IMPL_ISUPPORTS(xpcAccessibleMacNSObjectWrapper, nsIAccessibleMacNSObjectWrapper)
|
||||
NS_IMPL_ISUPPORTS(xpcAccessibleMacNSObjectWrapper,
|
||||
nsIAccessibleMacNSObjectWrapper)
|
||||
|
||||
xpcAccessibleMacNSObjectWrapper::xpcAccessibleMacNSObjectWrapper(id aNativeObj)
|
||||
: mNativeObject(aNativeObj) {
|
||||
[mNativeObject retain];
|
||||
}
|
||||
|
||||
xpcAccessibleMacNSObjectWrapper::~xpcAccessibleMacNSObjectWrapper() { [mNativeObject release]; }
|
||||
xpcAccessibleMacNSObjectWrapper::~xpcAccessibleMacNSObjectWrapper() {
|
||||
[mNativeObject release];
|
||||
}
|
||||
|
||||
id xpcAccessibleMacNSObjectWrapper::GetNativeObject() { return mNativeObject; }
|
||||
|
||||
// xpcAccessibleMacInterface
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(xpcAccessibleMacInterface, xpcAccessibleMacNSObjectWrapper,
|
||||
NS_IMPL_ISUPPORTS_INHERITED(xpcAccessibleMacInterface,
|
||||
xpcAccessibleMacNSObjectWrapper,
|
||||
nsIAccessibleMacInterface)
|
||||
|
||||
xpcAccessibleMacInterface::xpcAccessibleMacInterface(Accessible* aObj)
|
||||
: xpcAccessibleMacNSObjectWrapper(GetNativeFromGeckoAccessible(aObj)) {}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibleMacInterface::GetAttributeNames(nsTArray<nsString>& aAttributeNames) {
|
||||
xpcAccessibleMacInterface::GetAttributeNames(
|
||||
nsTArray<nsString>& aAttributeNames) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
||||
|
||||
if (!mNativeObject || [mNativeObject isExpired]) {
|
||||
|
@ -63,14 +68,16 @@ xpcAccessibleMacInterface::GetAttributeNames(nsTArray<nsString>& aAttributeNames
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibleMacInterface::GetParameterizedAttributeNames(nsTArray<nsString>& aAttributeNames) {
|
||||
xpcAccessibleMacInterface::GetParameterizedAttributeNames(
|
||||
nsTArray<nsString>& aAttributeNames) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
||||
|
||||
if (!mNativeObject || [mNativeObject isExpired]) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
for (NSString* name in [mNativeObject accessibilityParameterizedAttributeNames]) {
|
||||
for (NSString* name in
|
||||
[mNativeObject accessibilityParameterizedAttributeNames]) {
|
||||
nsAutoString attribName;
|
||||
nsCocoaUtils::GetStringForNSString(name, attribName);
|
||||
aAttributeNames.AppendElement(attribName);
|
||||
|
@ -117,7 +124,8 @@ xpcAccessibleMacInterface::PerformAction(const nsAString& aActionName) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName, JSContext* aCx,
|
||||
xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName,
|
||||
JSContext* aCx,
|
||||
JS::MutableHandleValue aResult) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
||||
|
||||
|
@ -126,17 +134,20 @@ xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName, JS
|
|||
}
|
||||
|
||||
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
||||
return NSObjectToJsValue([mNativeObject accessibilityAttributeValue:attribName], aCx, aResult);
|
||||
return NSObjectToJsValue(
|
||||
[mNativeObject accessibilityAttributeValue:attribName], aCx, aResult);
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName, bool* aIsSettable) {
|
||||
xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName,
|
||||
bool* aIsSettable) {
|
||||
NS_ENSURE_ARG_POINTER(aIsSettable);
|
||||
|
||||
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
||||
if ([mNativeObject respondsToSelector:@selector(accessibilityIsAttributeSettable:)]) {
|
||||
if ([mNativeObject
|
||||
respondsToSelector:@selector(accessibilityIsAttributeSettable:)]) {
|
||||
*aIsSettable = [mNativeObject accessibilityIsAttributeSettable:attribName];
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -146,13 +157,15 @@ xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName,
|
|||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibleMacInterface::SetAttributeValue(const nsAString& aAttributeName,
|
||||
JS::HandleValue aAttributeValue, JSContext* aCx) {
|
||||
JS::HandleValue aAttributeValue,
|
||||
JSContext* aCx) {
|
||||
nsresult rv = NS_OK;
|
||||
id obj = JsValueToNSObject(aAttributeValue, aCx, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
||||
if ([mNativeObject respondsToSelector:@selector(accessibilitySetValue:forAttribute:)]) {
|
||||
if ([mNativeObject respondsToSelector:@selector(accessibilitySetValue:
|
||||
forAttribute:)]) {
|
||||
// The NSObject has an attribute setter, call that.
|
||||
[mNativeObject accessibilitySetValue:obj forAttribute:attribName];
|
||||
return NS_OK;
|
||||
|
@ -162,29 +175,30 @@ xpcAccessibleMacInterface::SetAttributeValue(const nsAString& aAttributeName,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibleMacInterface::GetParameterizedAttributeValue(const nsAString& aAttributeName,
|
||||
JS::HandleValue aParameter,
|
||||
JSContext* aCx,
|
||||
JS::MutableHandleValue aResult) {
|
||||
xpcAccessibleMacInterface::GetParameterizedAttributeValue(
|
||||
const nsAString& aAttributeName, JS::HandleValue aParameter, JSContext* aCx,
|
||||
JS::MutableHandleValue aResult) {
|
||||
nsresult rv = NS_OK;
|
||||
id paramObj = JsValueToNSObject(aParameter, aCx, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
||||
return NSObjectToJsValue(
|
||||
[mNativeObject accessibilityAttributeValue:attribName forParameter:paramObj], aCx, aResult);
|
||||
return NSObjectToJsValue([mNativeObject accessibilityAttributeValue:attribName
|
||||
forParameter:paramObj],
|
||||
aCx, aResult);
|
||||
}
|
||||
|
||||
bool xpcAccessibleMacInterface::SupportsSelector(SEL aSelector) {
|
||||
// return true if we have this selector, and if isAccessibilitySelectorAllowed
|
||||
// is implemented too whether it is "allowed".
|
||||
return [mNativeObject respondsToSelector:aSelector] &&
|
||||
(![mNativeObject respondsToSelector:@selector(isAccessibilitySelectorAllowed:selector:)] ||
|
||||
(![mNativeObject respondsToSelector:@selector
|
||||
(isAccessibilitySelectorAllowed:selector:)] ||
|
||||
[mNativeObject isAccessibilitySelectorAllowed:aSelector]);
|
||||
}
|
||||
|
||||
nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
||||
JS::MutableHandleValue aResult) {
|
||||
nsresult xpcAccessibleMacInterface::NSObjectToJsValue(
|
||||
id aObj, JSContext* aCx, JS::MutableHandleValue aResult) {
|
||||
if (!aObj) {
|
||||
aResult.set(JS::NullValue());
|
||||
} else if ([aObj isKindOfClass:[NSString class]]) {
|
||||
|
@ -201,7 +215,8 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
if (!mozilla::dom::ToJSValue(aCx, [(NSNumber*)aObj doubleValue], aResult)) {
|
||||
if (!mozilla::dom::ToJSValue(aCx, [(NSNumber*)aObj doubleValue],
|
||||
aResult)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -209,18 +224,25 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
|||
strcmp([(NSValue*)aObj objCType], @encode(NSPoint)) == 0) {
|
||||
NSPoint point = [(NSValue*)aObj pointValue];
|
||||
return NSObjectToJsValue(
|
||||
@[ [NSNumber numberWithDouble:point.x], [NSNumber numberWithDouble:point.y] ], aCx,
|
||||
aResult);
|
||||
@[
|
||||
[NSNumber numberWithDouble:point.x],
|
||||
[NSNumber numberWithDouble:point.y]
|
||||
],
|
||||
aCx, aResult);
|
||||
} else if ([aObj isKindOfClass:[NSValue class]] &&
|
||||
strcmp([(NSValue*)aObj objCType], @encode(NSSize)) == 0) {
|
||||
NSSize size = [(NSValue*)aObj sizeValue];
|
||||
return NSObjectToJsValue(
|
||||
@[ [NSNumber numberWithDouble:size.width], [NSNumber numberWithDouble:size.height] ], aCx,
|
||||
aResult);
|
||||
@[
|
||||
[NSNumber numberWithDouble:size.width],
|
||||
[NSNumber numberWithDouble:size.height]
|
||||
],
|
||||
aCx, aResult);
|
||||
} else if ([aObj isKindOfClass:[NSValue class]] &&
|
||||
strcmp([(NSValue*)aObj objCType], @encode(NSRange)) == 0) {
|
||||
NSRange range = [(NSValue*)aObj rangeValue];
|
||||
return NSObjectToJsValue(@[ @(range.location), @(range.length) ], aCx, aResult);
|
||||
return NSObjectToJsValue(@[ @(range.location), @(range.length) ], aCx,
|
||||
aResult);
|
||||
} else if ([aObj isKindOfClass:[NSValue class]] &&
|
||||
strcmp([(NSValue*)aObj objCType], @encode(NSRect)) == 0) {
|
||||
NSRect rect = [(NSValue*)aObj rectValue];
|
||||
|
@ -263,14 +285,18 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
|||
|
||||
[attrStr
|
||||
enumerateAttributesInRange:NSMakeRange(0, [attrStr length])
|
||||
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
||||
usingBlock:^(NSDictionary* attributes, NSRange range, BOOL* stop) {
|
||||
NSString* str = [[attrStr string] substringWithRange:range];
|
||||
options:
|
||||
NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
||||
usingBlock:^(NSDictionary* attributes, NSRange range,
|
||||
BOOL* stop) {
|
||||
NSString* str =
|
||||
[[attrStr string] substringWithRange:range];
|
||||
if (!str || !attributes) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableDictionary* attrRun = [attributes mutableCopy];
|
||||
NSMutableDictionary* attrRun =
|
||||
[attributes mutableCopy];
|
||||
attrRun[@"string"] = str;
|
||||
|
||||
[attrRunArray addObject:attrRun];
|
||||
|
@ -282,28 +308,34 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
|||
return NSObjectToJsValue(attrRunArray, aCx, aResult);
|
||||
} else if (CFGetTypeID(aObj) == CGColorGetTypeID()) {
|
||||
const CGFloat* components = CGColorGetComponents((CGColorRef)aObj);
|
||||
NSString* hexString =
|
||||
[NSString stringWithFormat:@"#%02x%02x%02x", (int)(components[0] * 0xff),
|
||||
(int)(components[1] * 0xff), (int)(components[2] * 0xff)];
|
||||
NSString* hexString = [NSString
|
||||
stringWithFormat:@"#%02x%02x%02x", (int)(components[0] * 0xff),
|
||||
(int)(components[1] * 0xff),
|
||||
(int)(components[2] * 0xff)];
|
||||
return NSObjectToJsValue(hexString, aCx, aResult);
|
||||
} else if ([aObj respondsToSelector:@selector(isAccessibilityElement)]) {
|
||||
// We expect all of our accessibility objects to implement isAccessibilityElement
|
||||
// at the very least. If it is implemented we will assume its an accessibility object.
|
||||
nsCOMPtr<nsIAccessibleMacInterface> obj = new xpcAccessibleMacInterface(aObj);
|
||||
return nsContentUtils::WrapNative(aCx, obj, &NS_GET_IID(nsIAccessibleMacInterface), aResult);
|
||||
// We expect all of our accessibility objects to implement
|
||||
// isAccessibilityElement at the very least. If it is implemented we will
|
||||
// assume its an accessibility object.
|
||||
nsCOMPtr<nsIAccessibleMacInterface> obj =
|
||||
new xpcAccessibleMacInterface(aObj);
|
||||
return nsContentUtils::WrapNative(
|
||||
aCx, obj, &NS_GET_IID(nsIAccessibleMacInterface), aResult);
|
||||
} else {
|
||||
// If this is any other kind of NSObject, just wrap it and return it.
|
||||
// It will be opaque and immutable on the JS side, but it can be
|
||||
// brought back to us in an argument.
|
||||
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> obj = new xpcAccessibleMacNSObjectWrapper(aObj);
|
||||
return nsContentUtils::WrapNative(aCx, obj, &NS_GET_IID(nsIAccessibleMacNSObjectWrapper),
|
||||
aResult);
|
||||
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> obj =
|
||||
new xpcAccessibleMacNSObjectWrapper(aObj);
|
||||
return nsContentUtils::WrapNative(
|
||||
aCx, obj, &NS_GET_IID(nsIAccessibleMacNSObjectWrapper), aResult);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContext* aCx,
|
||||
id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue,
|
||||
JSContext* aCx,
|
||||
nsresult* aResult) {
|
||||
*aResult = NS_OK;
|
||||
if (aValue.isInt32()) {
|
||||
|
@ -363,9 +395,11 @@ id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContex
|
|||
nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrappedObj;
|
||||
nsresult rv = xpc->GetWrappedNativeOfJSObject(aCx, obj, getter_AddRefs(wrappedObj));
|
||||
nsresult rv =
|
||||
xpc->GetWrappedNativeOfJSObject(aCx, obj, getter_AddRefs(wrappedObj));
|
||||
NS_ENSURE_SUCCESS(rv, nil);
|
||||
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> macObjIface = do_QueryInterface(wrappedObj->Native());
|
||||
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> macObjIface =
|
||||
do_QueryInterface(wrappedObj->Native());
|
||||
return macObjIface->GetNativeObject();
|
||||
}
|
||||
|
||||
|
@ -373,7 +407,8 @@ id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContex
|
|||
return nil;
|
||||
}
|
||||
|
||||
id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject, JSContext* aCx,
|
||||
id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject,
|
||||
JSContext* aCx,
|
||||
nsresult* aResult) {
|
||||
*aResult = NS_ERROR_FAILURE;
|
||||
JS::RootedValue valueTypeValue(aCx);
|
||||
|
@ -421,14 +456,15 @@ id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject, JSConte
|
|||
}
|
||||
|
||||
*aResult = NS_OK;
|
||||
return [NSValue valueWithRange:NSMakeRange(locationValue.toInt32(), lengthValue.toInt32())];
|
||||
return [NSValue valueWithRange:NSMakeRange(locationValue.toInt32(),
|
||||
lengthValue.toInt32())];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
id xpcAccessibleMacInterface::JsValueToSpecifiedNSObject(JS::HandleObject aObject, JSContext* aCx,
|
||||
nsresult* aResult) {
|
||||
id xpcAccessibleMacInterface::JsValueToSpecifiedNSObject(
|
||||
JS::HandleObject aObject, JSContext* aCx, nsresult* aResult) {
|
||||
*aResult = NS_ERROR_FAILURE;
|
||||
JS::RootedValue objectTypeValue(aCx);
|
||||
if (!JS_GetProperty(aCx, aObject, "objectType", &objectTypeValue)) {
|
||||
|
@ -509,7 +545,8 @@ xpcAccessibleMacEvent::~xpcAccessibleMacEvent() {
|
|||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibleMacEvent::GetMacIface(nsIAccessibleMacInterface** aMacIface) {
|
||||
RefPtr<xpcAccessibleMacInterface> macIface = new xpcAccessibleMacInterface(mNativeObject);
|
||||
RefPtr<xpcAccessibleMacInterface> macIface =
|
||||
new xpcAccessibleMacInterface(mNativeObject);
|
||||
macIface.forget(aMacIface);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -519,20 +556,25 @@ xpcAccessibleMacEvent::GetData(JSContext* aCx, JS::MutableHandleValue aData) {
|
|||
return xpcAccessibleMacInterface::NSObjectToJsValue(mData, aCx, aData);
|
||||
}
|
||||
|
||||
void xpcAccessibleMacEvent::FireEvent(id aNativeObj, id aNotification, id aUserInfo) {
|
||||
if (nsCOMPtr<nsIObserverService> obsService = services::GetObserverService()) {
|
||||
void xpcAccessibleMacEvent::FireEvent(id aNativeObj, id aNotification,
|
||||
id aUserInfo) {
|
||||
if (nsCOMPtr<nsIObserverService> obsService =
|
||||
services::GetObserverService()) {
|
||||
nsCOMPtr<nsISimpleEnumerator> observers;
|
||||
// Get all observers for the mac event topic.
|
||||
obsService->EnumerateObservers(NS_ACCESSIBLE_MAC_EVENT_TOPIC, getter_AddRefs(observers));
|
||||
obsService->EnumerateObservers(NS_ACCESSIBLE_MAC_EVENT_TOPIC,
|
||||
getter_AddRefs(observers));
|
||||
if (observers) {
|
||||
bool hasObservers = false;
|
||||
observers->HasMoreElements(&hasObservers);
|
||||
// If we have observers, notify them.
|
||||
if (hasObservers) {
|
||||
nsCOMPtr<nsIAccessibleMacEvent> xpcIface = new xpcAccessibleMacEvent(aNativeObj, aUserInfo);
|
||||
nsCOMPtr<nsIAccessibleMacEvent> xpcIface =
|
||||
new xpcAccessibleMacEvent(aNativeObj, aUserInfo);
|
||||
nsAutoString notificationStr;
|
||||
nsCocoaUtils::GetStringForNSString(aNotification, notificationStr);
|
||||
obsService->NotifyObservers(xpcIface, NS_ACCESSIBLE_MAC_EVENT_TOPIC, notificationStr.get());
|
||||
obsService->NotifyObservers(xpcIface, NS_ACCESSIBLE_MAC_EVENT_TOPIC,
|
||||
notificationStr.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ NS_IMPL_ISUPPORTS(nsKeychainMigrationUtils, nsIKeychainMigrationUtils)
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
|
||||
const nsACString& aAccountName, nsACString& aKey) {
|
||||
const nsACString& aAccountName,
|
||||
nsACString& aKey) {
|
||||
// To retrieve a secret, we create a CFDictionary of the form:
|
||||
// { class: generic password,
|
||||
// service: the given service name
|
||||
|
@ -31,9 +32,12 @@ nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
|
|||
// matching the given service and account names. We then extract the data
|
||||
// (i.e. the secret) and return it.
|
||||
NSDictionary* searchDictionary = @{
|
||||
(__bridge NSString*)kSecClass : (__bridge NSString*)kSecClassGenericPassword,
|
||||
(__bridge NSString*)kSecAttrService : nsCocoaUtils::ToNSString(aServiceName),
|
||||
(__bridge NSString*)kSecAttrAccount : nsCocoaUtils::ToNSString(aAccountName),
|
||||
(__bridge NSString*)
|
||||
kSecClass : (__bridge NSString*)kSecClassGenericPassword,
|
||||
(__bridge NSString*)
|
||||
kSecAttrService : nsCocoaUtils::ToNSString(aServiceName),
|
||||
(__bridge NSString*)
|
||||
kSecAttrAccount : nsCocoaUtils::ToNSString(aAccountName),
|
||||
(__bridge NSString*)kSecMatchLimit : (__bridge NSString*)kSecMatchLimitOne,
|
||||
(__bridge NSString*)kSecReturnAttributes : @YES,
|
||||
(__bridge NSString*)kSecReturnData : @YES
|
||||
|
@ -41,9 +45,11 @@ nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
|
|||
|
||||
CFTypeRef item;
|
||||
// https://developer.apple.com/documentation/security/1398306-secitemcopymatching
|
||||
OSStatus rv = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &item);
|
||||
OSStatus rv =
|
||||
SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &item);
|
||||
if (rv != errSecSuccess) {
|
||||
MOZ_LOG(gKeychainUtilsLog, LogLevel::Debug, ("SecItemCopyMatching failed: %d", rv));
|
||||
MOZ_LOG(gKeychainUtilsLog, LogLevel::Debug,
|
||||
("SecItemCopyMatching failed: %d", rv));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
NSDictionary* resultDict = [(__bridge NSDictionary*)item autorelease];
|
||||
|
@ -53,8 +59,8 @@ nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if ([secret length] != 0) {
|
||||
// We assume that the data is UTF-8 encoded since that seems to be common and
|
||||
// Keychain Access shows it with that encoding.
|
||||
// We assume that the data is UTF-8 encoded since that seems to be common
|
||||
// and Keychain Access shows it with that encoding.
|
||||
aKey.Assign(reinterpret_cast<const char*>([secret bytes]), [secret length]);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,27 +18,31 @@ using namespace mozilla::widget;
|
|||
|
||||
static const int kSystemDefinedEventMediaKeysSubtype = 8;
|
||||
|
||||
static void SendFakeEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource, int aKeyData) {
|
||||
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeSystemDefined
|
||||
location:NSZeroPoint
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:nil
|
||||
subtype:kSystemDefinedEventMediaKeysSubtype
|
||||
data1:aKeyData
|
||||
data2:0];
|
||||
aSource->EventTapCallback(nullptr, static_cast<CGEventType>(0), [event CGEvent], aSource.get());
|
||||
static void SendFakeEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
||||
int aKeyData) {
|
||||
NSEvent* event =
|
||||
[NSEvent otherEventWithType:NSEventTypeSystemDefined
|
||||
location:NSZeroPoint
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:nil
|
||||
subtype:kSystemDefinedEventMediaKeysSubtype
|
||||
data1:aKeyData
|
||||
data2:0];
|
||||
aSource->EventTapCallback(nullptr, static_cast<CGEventType>(0),
|
||||
[event CGEvent], aSource.get());
|
||||
}
|
||||
|
||||
static void NotifyFakeNonMediaKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
||||
bool aIsKeyPressed) {
|
||||
static void NotifyFakeNonMediaKey(
|
||||
RefPtr<MediaHardwareKeysEventSourceMac>& aSource, bool aIsKeyPressed) {
|
||||
int keyData = 0 | ((aIsKeyPressed ? 0xA : 0xB) << 8);
|
||||
SendFakeEvent(aSource, keyData);
|
||||
}
|
||||
|
||||
static void NotifyFakeMediaControlKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
||||
MediaControlKey aEvent, bool aIsKeyPressed) {
|
||||
static void NotifyFakeMediaControlKey(
|
||||
RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent,
|
||||
bool aIsKeyPressed) {
|
||||
int keyData = 0;
|
||||
if (aEvent == MediaControlKey::Playpause) {
|
||||
keyData = NX_KEYTYPE_PLAY << 16;
|
||||
|
@ -51,27 +55,30 @@ static void NotifyFakeMediaControlKey(RefPtr<MediaHardwareKeysEventSourceMac>& a
|
|||
SendFakeEvent(aSource, keyData);
|
||||
}
|
||||
|
||||
static void NotifyKeyPressedMediaKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
||||
MediaControlKey aEvent) {
|
||||
static void NotifyKeyPressedMediaKey(
|
||||
RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent) {
|
||||
NotifyFakeMediaControlKey(aSource, aEvent, true /* key pressed */);
|
||||
}
|
||||
|
||||
static void NotifyKeyReleasedMediaKeysEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
||||
MediaControlKey aEvent) {
|
||||
static void NotifyKeyReleasedMediaKeysEvent(
|
||||
RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent) {
|
||||
NotifyFakeMediaControlKey(aSource, aEvent, false /* key released */);
|
||||
}
|
||||
|
||||
static void NotifyKeyPressedNonMediaKeysEvents(RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
|
||||
static void NotifyKeyPressedNonMediaKeysEvents(
|
||||
RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
|
||||
NotifyFakeNonMediaKey(aSource, true /* key pressed */);
|
||||
}
|
||||
|
||||
static void NotifyKeyReleasedNonMediaKeysEvents(RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
|
||||
static void NotifyKeyReleasedNonMediaKeysEvents(
|
||||
RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
|
||||
NotifyFakeNonMediaKey(aSource, false /* key released */);
|
||||
}
|
||||
|
||||
TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent)
|
||||
{
|
||||
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
|
||||
RefPtr<MediaHardwareKeysEventSourceMac> source =
|
||||
new MediaHardwareKeysEventSourceMac();
|
||||
ASSERT_TRUE(source->GetListenersNum() == 0);
|
||||
|
||||
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
||||
|
@ -94,7 +101,8 @@ TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent)
|
|||
|
||||
TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent)
|
||||
{
|
||||
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
|
||||
RefPtr<MediaHardwareKeysEventSourceMac> source =
|
||||
new MediaHardwareKeysEventSourceMac();
|
||||
ASSERT_TRUE(source->GetListenersNum() == 0);
|
||||
|
||||
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
||||
|
@ -117,7 +125,8 @@ TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent)
|
|||
|
||||
TEST(MediaHardwareKeysEventSourceMac, TestNonMediaKeysEvent)
|
||||
{
|
||||
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
|
||||
RefPtr<MediaHardwareKeysEventSourceMac> source =
|
||||
new MediaHardwareKeysEventSourceMac();
|
||||
ASSERT_TRUE(source->GetListenersNum() == 0);
|
||||
|
||||
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
||||
|
|
|
@ -123,7 +123,8 @@ TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestMediaCenterPrevNextEvent)
|
|||
|
||||
ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Nexttrack));
|
||||
|
||||
MediaCenterEventHandler previousHandler = source->CreatePreviousTrackHandler();
|
||||
MediaCenterEventHandler previousHandler =
|
||||
source->CreatePreviousTrackHandler();
|
||||
|
||||
previousHandler(nil);
|
||||
|
||||
|
@ -153,9 +154,12 @@ TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestSetMetadata)
|
|||
// before checking the result.
|
||||
PR_Sleep(PR_SecondsToInterval(1));
|
||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyTitle] isEqualToString:@"MediaPlayback"]);
|
||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyArtist] isEqualToString:@"Firefox"]);
|
||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyAlbumTitle] isEqualToString:@"Mozilla"]);
|
||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyTitle]
|
||||
isEqualToString:@"MediaPlayback"]);
|
||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyArtist]
|
||||
isEqualToString:@"Firefox"]);
|
||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyAlbumTitle]
|
||||
isEqualToString:@"Mozilla"]);
|
||||
|
||||
source->Close();
|
||||
PR_Sleep(PR_SecondsToInterval(1));
|
||||
|
|
|
@ -28,11 +28,13 @@ using namespace webrtc;
|
|||
using namespace videocapturemodule;
|
||||
|
||||
static NSArray* camera_presets = @[
|
||||
AVCaptureSessionPreset352x288, AVCaptureSessionPreset640x480, AVCaptureSessionPreset1280x720
|
||||
AVCaptureSessionPreset352x288, AVCaptureSessionPreset640x480,
|
||||
AVCaptureSessionPreset1280x720
|
||||
];
|
||||
|
||||
#define IOS_UNSUPPORTED() \
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << " is not supported on the iOS platform."; \
|
||||
#define IOS_UNSUPPORTED() \
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ \
|
||||
<< " is not supported on the iOS platform."; \
|
||||
return -1;
|
||||
|
||||
VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
|
||||
|
@ -60,7 +62,8 @@ int32_t DeviceInfoIos::Init() {
|
|||
for (NSString* preset in camera_presets) {
|
||||
BOOL support = [avDevice supportsAVCaptureSessionPreset:preset];
|
||||
if (support) {
|
||||
VideoCaptureCapability capability = [DeviceInfoIosObjC capabilityForPreset:preset];
|
||||
VideoCaptureCapability capability =
|
||||
[DeviceInfoIosObjC capabilityForPreset:preset];
|
||||
capabilityVector.push_back(capability);
|
||||
}
|
||||
}
|
||||
|
@ -73,31 +76,36 @@ int32_t DeviceInfoIos::Init() {
|
|||
}
|
||||
std::string deviceIdCopy(deviceId);
|
||||
std::pair<std::string, VideoCaptureCapabilities> mapPair =
|
||||
std::pair<std::string, VideoCaptureCapabilities>(deviceIdCopy, capabilityVector);
|
||||
std::pair<std::string, VideoCaptureCapabilities>(deviceIdCopy,
|
||||
capabilityVector);
|
||||
_capabilitiesMap.insert(mapPair);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t DeviceInfoIos::NumberOfDevices() { return [DeviceInfoIosObjC captureDeviceCount]; }
|
||||
uint32_t DeviceInfoIos::NumberOfDevices() {
|
||||
return [DeviceInfoIosObjC captureDeviceCount];
|
||||
}
|
||||
|
||||
int32_t DeviceInfoIos::GetDeviceName(uint32_t deviceNumber, char* deviceNameUTF8,
|
||||
uint32_t deviceNameUTF8Length, char* deviceUniqueIdUTF8,
|
||||
uint32_t deviceUniqueIdUTF8Length, char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length, pid_t* pid) {
|
||||
int32_t DeviceInfoIos::GetDeviceName(
|
||||
uint32_t deviceNumber, char* deviceNameUTF8, uint32_t deviceNameUTF8Length,
|
||||
char* deviceUniqueIdUTF8, uint32_t deviceUniqueIdUTF8Length,
|
||||
char* productUniqueIdUTF8, uint32_t productUniqueIdUTF8Length, pid_t* pid) {
|
||||
if (deviceNumber >= NumberOfDevices()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
NSString* deviceName = [DeviceInfoIosObjC deviceNameForIndex:deviceNumber];
|
||||
|
||||
NSString* deviceUniqueId = [DeviceInfoIosObjC deviceUniqueIdForIndex:deviceNumber];
|
||||
NSString* deviceUniqueId =
|
||||
[DeviceInfoIosObjC deviceUniqueIdForIndex:deviceNumber];
|
||||
|
||||
strncpy(deviceNameUTF8, [deviceName UTF8String], deviceNameUTF8Length);
|
||||
deviceNameUTF8[deviceNameUTF8Length - 1] = '\0';
|
||||
|
||||
strncpy(deviceUniqueIdUTF8, deviceUniqueId.UTF8String, deviceUniqueIdUTF8Length);
|
||||
strncpy(deviceUniqueIdUTF8, deviceUniqueId.UTF8String,
|
||||
deviceUniqueIdUTF8Length);
|
||||
deviceUniqueIdUTF8[deviceUniqueIdUTF8Length - 1] = '\0';
|
||||
|
||||
if (productUniqueIdUTF8) {
|
||||
|
@ -140,14 +148,14 @@ int32_t DeviceInfoIos::GetCapability(const char* deviceUniqueIdUTF8,
|
|||
return -1;
|
||||
}
|
||||
|
||||
int32_t DeviceInfoIos::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
|
||||
const char* dialogTitleUTF8,
|
||||
void* parentWindow, uint32_t positionX,
|
||||
uint32_t positionY) {
|
||||
int32_t DeviceInfoIos::DisplayCaptureSettingsDialogBox(
|
||||
const char* deviceUniqueIdUTF8, const char* dialogTitleUTF8,
|
||||
void* parentWindow, uint32_t positionX, uint32_t positionY) {
|
||||
IOS_UNSUPPORTED();
|
||||
}
|
||||
|
||||
int32_t DeviceInfoIos::GetOrientation(const char* deviceUniqueIdUTF8, VideoRotation& orientation) {
|
||||
int32_t DeviceInfoIos::GetOrientation(const char* deviceUniqueIdUTF8,
|
||||
VideoRotation& orientation) {
|
||||
if (strcmp(deviceUniqueIdUTF8, "Front Camera") == 0) {
|
||||
orientation = kVideoRotation_0;
|
||||
} else {
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
|
||||
namespace webrtc::videocapturemodule {
|
||||
/* static */
|
||||
int32_t DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(Float64 aRate) {
|
||||
int32_t DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
|
||||
Float64 aRate) {
|
||||
return static_cast<int32_t>(aRate);
|
||||
}
|
||||
|
||||
/* static */
|
||||
webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(FourCharCode aCode) {
|
||||
webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(
|
||||
FourCharCode aCode) {
|
||||
switch (aCode) {
|
||||
case kCVPixelFormatType_420YpCbCr8Planar:
|
||||
case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
|
||||
|
@ -57,11 +59,14 @@ webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(FourCharCode
|
|||
}
|
||||
|
||||
DeviceInfoAvFoundation::DeviceInfoAvFoundation()
|
||||
: mInvalidateCapabilities(false), mDeviceChangeCaptureInfo([[DeviceInfoIosObjC alloc] init]) {
|
||||
: mInvalidateCapabilities(false),
|
||||
mDeviceChangeCaptureInfo([[DeviceInfoIosObjC alloc] init]) {
|
||||
[mDeviceChangeCaptureInfo registerOwner:this];
|
||||
}
|
||||
|
||||
DeviceInfoAvFoundation::~DeviceInfoAvFoundation() { [mDeviceChangeCaptureInfo registerOwner:nil]; }
|
||||
DeviceInfoAvFoundation::~DeviceInfoAvFoundation() {
|
||||
[mDeviceChangeCaptureInfo registerOwner:nil];
|
||||
}
|
||||
|
||||
void DeviceInfoAvFoundation::DeviceChange() {
|
||||
mInvalidateCapabilities = true;
|
||||
|
@ -74,12 +79,11 @@ uint32_t DeviceInfoAvFoundation::NumberOfDevices() {
|
|||
return mDevicesAndCapabilities.size();
|
||||
}
|
||||
|
||||
int32_t DeviceInfoAvFoundation::GetDeviceName(uint32_t aDeviceNumber, char* aDeviceNameUTF8,
|
||||
uint32_t aDeviceNameLength, char* aDeviceUniqueIdUTF8,
|
||||
uint32_t aDeviceUniqueIdUTF8Length,
|
||||
char* /* aProductUniqueIdUTF8 */,
|
||||
uint32_t /* aProductUniqueIdUTF8Length */,
|
||||
pid_t* /* aPid */) {
|
||||
int32_t DeviceInfoAvFoundation::GetDeviceName(
|
||||
uint32_t aDeviceNumber, char* aDeviceNameUTF8, uint32_t aDeviceNameLength,
|
||||
char* aDeviceUniqueIdUTF8, uint32_t aDeviceUniqueIdUTF8Length,
|
||||
char* /* aProductUniqueIdUTF8 */, uint32_t /* aProductUniqueIdUTF8Length */,
|
||||
pid_t* /* aPid */) {
|
||||
RTC_DCHECK_RUN_ON(&mChecker);
|
||||
// Don't EnsureCapabilitiesMap() here, since:
|
||||
// 1) That might invalidate the capabilities map
|
||||
|
@ -100,7 +104,8 @@ int32_t DeviceInfoAvFoundation::GetDeviceName(uint32_t aDeviceNumber, char* aDev
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t DeviceInfoAvFoundation::NumberOfCapabilities(const char* aDeviceUniqueIdUTF8) {
|
||||
int32_t DeviceInfoAvFoundation::NumberOfCapabilities(
|
||||
const char* aDeviceUniqueIdUTF8) {
|
||||
RTC_DCHECK_RUN_ON(&mChecker);
|
||||
|
||||
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
||||
|
@ -113,9 +118,9 @@ int32_t DeviceInfoAvFoundation::NumberOfCapabilities(const char* aDeviceUniqueId
|
|||
return static_cast<int32_t>(capabilities.size());
|
||||
}
|
||||
|
||||
int32_t DeviceInfoAvFoundation::GetCapability(const char* aDeviceUniqueIdUTF8,
|
||||
const uint32_t aDeviceCapabilityNumber,
|
||||
VideoCaptureCapability& aCapability) {
|
||||
int32_t DeviceInfoAvFoundation::GetCapability(
|
||||
const char* aDeviceUniqueIdUTF8, const uint32_t aDeviceCapabilityNumber,
|
||||
VideoCaptureCapability& aCapability) {
|
||||
RTC_DCHECK_RUN_ON(&mChecker);
|
||||
|
||||
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
||||
|
@ -133,7 +138,8 @@ int32_t DeviceInfoAvFoundation::GetCapability(const char* aDeviceUniqueIdUTF8,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdUTF8) {
|
||||
int32_t DeviceInfoAvFoundation::CreateCapabilityMap(
|
||||
const char* aDeviceUniqueIdUTF8) {
|
||||
RTC_DCHECK_RUN_ON(&mChecker);
|
||||
|
||||
const size_t deviceUniqueIdUTF8Length = strlen(aDeviceUniqueIdUTF8);
|
||||
|
@ -141,7 +147,8 @@ int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdU
|
|||
RTC_LOG(LS_INFO) << "Device name too long";
|
||||
return -1;
|
||||
}
|
||||
RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device " << aDeviceUniqueIdUTF8;
|
||||
RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device "
|
||||
<< aDeviceUniqueIdUTF8;
|
||||
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
||||
const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
|
||||
if (!tup) {
|
||||
|
@ -151,16 +158,18 @@ int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdU
|
|||
|
||||
// Store the new used device name
|
||||
_lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
|
||||
_lastUsedDeviceName =
|
||||
static_cast<char*>(realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
|
||||
memcpy(_lastUsedDeviceName, aDeviceUniqueIdUTF8, _lastUsedDeviceNameLength + 1);
|
||||
_lastUsedDeviceName = static_cast<char*>(
|
||||
realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
|
||||
memcpy(_lastUsedDeviceName, aDeviceUniqueIdUTF8,
|
||||
_lastUsedDeviceNameLength + 1);
|
||||
|
||||
const auto& [_, __, capabilities] = *tup;
|
||||
_captureCapabilities = capabilities;
|
||||
return static_cast<int32_t>(_captureCapabilities.size());
|
||||
}
|
||||
|
||||
auto DeviceInfoAvFoundation::FindDeviceAndCapabilities(const std::string& aDeviceUniqueId) const
|
||||
auto DeviceInfoAvFoundation::FindDeviceAndCapabilities(
|
||||
const std::string& aDeviceUniqueId) const
|
||||
-> const std::tuple<std::string, std::string, VideoCaptureCapabilities>* {
|
||||
RTC_DCHECK_RUN_ON(&mChecker);
|
||||
for (const auto& tup : mDevicesAndCapabilities) {
|
||||
|
@ -185,13 +194,14 @@ void DeviceInfoAvFoundation::EnsureCapabilitiesMap() {
|
|||
for (AVCaptureDevice* device in [RTCCameraVideoCapturer captureDevices]) {
|
||||
std::string uniqueId = [NSString stdStringForString:device.uniqueID];
|
||||
std::string name = [NSString stdStringForString:device.localizedName];
|
||||
auto& [_, __, capabilities] =
|
||||
mDevicesAndCapabilities.emplace_back(uniqueId, name, VideoCaptureCapabilities());
|
||||
auto& [_, __, capabilities] = mDevicesAndCapabilities.emplace_back(
|
||||
uniqueId, name, VideoCaptureCapabilities());
|
||||
|
||||
for (AVCaptureDeviceFormat* format in
|
||||
[RTCCameraVideoCapturer supportedFormatsForDevice:device]) {
|
||||
VideoCaptureCapability cap;
|
||||
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(format.formatDescription);
|
||||
FourCharCode fourcc =
|
||||
CMFormatDescriptionGetMediaSubType(format.formatDescription);
|
||||
cap.videoType = ConvertFourCCToVideoType(fourcc);
|
||||
CMVideoDimensions dimensions =
|
||||
CMVideoFormatDescriptionGetDimensions(format.formatDescription);
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
if (!_owner && owner) {
|
||||
[self configureObservers];
|
||||
} else if (_owner && !owner) {
|
||||
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
|
||||
NSNotificationCenter* notificationCenter =
|
||||
[NSNotificationCenter defaultCenter];
|
||||
for (id observer in _observers) {
|
||||
[notificationCenter removeObserver:observer];
|
||||
}
|
||||
|
@ -47,7 +48,8 @@
|
|||
+ (int)captureDeviceCount {
|
||||
int cnt = 0;
|
||||
@try {
|
||||
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||
for (AVCaptureDevice* device in
|
||||
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||
if ([device isSuspended]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -62,7 +64,8 @@
|
|||
+ (AVCaptureDevice*)captureDeviceForIndex:(int)index {
|
||||
int cnt = 0;
|
||||
@try {
|
||||
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||
for (AVCaptureDevice* device in
|
||||
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||
if ([device isSuspended]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -79,7 +82,8 @@
|
|||
}
|
||||
|
||||
+ (AVCaptureDevice*)captureDeviceForUniqueId:(NSString*)uniqueId {
|
||||
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||
for (AVCaptureDevice* device in
|
||||
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||
if ([device isSuspended]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -133,34 +137,36 @@
|
|||
|
||||
- (void)configureObservers {
|
||||
// register device connected / disconnected event
|
||||
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
|
||||
NSNotificationCenter* notificationCenter =
|
||||
[NSNotificationCenter defaultCenter];
|
||||
|
||||
id deviceWasConnectedObserver =
|
||||
[notificationCenter addObserverForName:AVCaptureDeviceWasConnectedNotification
|
||||
object:nil
|
||||
queue:[NSOperationQueue mainQueue]
|
||||
usingBlock:^(NSNotification* note) {
|
||||
[_lock lock];
|
||||
AVCaptureDevice* device = [note object];
|
||||
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
|
||||
if (isVideoDevice && _owner) _owner->DeviceChange();
|
||||
[_lock unlock];
|
||||
}];
|
||||
id deviceWasConnectedObserver = [notificationCenter
|
||||
addObserverForName:AVCaptureDeviceWasConnectedNotification
|
||||
object:nil
|
||||
queue:[NSOperationQueue mainQueue]
|
||||
usingBlock:^(NSNotification* note) {
|
||||
[_lock lock];
|
||||
AVCaptureDevice* device = [note object];
|
||||
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
|
||||
if (isVideoDevice && _owner) _owner->DeviceChange();
|
||||
[_lock unlock];
|
||||
}];
|
||||
|
||||
id deviceWasDisconnectedObserver =
|
||||
[notificationCenter addObserverForName:AVCaptureDeviceWasDisconnectedNotification
|
||||
object:nil
|
||||
queue:[NSOperationQueue mainQueue]
|
||||
usingBlock:^(NSNotification* note) {
|
||||
[_lock lock];
|
||||
AVCaptureDevice* device = [note object];
|
||||
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
|
||||
if (isVideoDevice && _owner) _owner->DeviceChange();
|
||||
[_lock unlock];
|
||||
}];
|
||||
id deviceWasDisconnectedObserver = [notificationCenter
|
||||
addObserverForName:AVCaptureDeviceWasDisconnectedNotification
|
||||
object:nil
|
||||
queue:[NSOperationQueue mainQueue]
|
||||
usingBlock:^(NSNotification* note) {
|
||||
[_lock lock];
|
||||
AVCaptureDevice* device = [note object];
|
||||
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
|
||||
if (isVideoDevice && _owner) _owner->DeviceChange();
|
||||
[_lock unlock];
|
||||
}];
|
||||
|
||||
_observers = [[NSArray alloc]
|
||||
initWithObjects:deviceWasConnectedObserver, deviceWasDisconnectedObserver, nil];
|
||||
_observers =
|
||||
[[NSArray alloc] initWithObjects:deviceWasConnectedObserver,
|
||||
deviceWasDisconnectedObserver, nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -57,18 +57,22 @@ using namespace webrtc::videocapturemodule;
|
|||
}
|
||||
|
||||
// create and configure a new output (using callbacks)
|
||||
AVCaptureVideoDataOutput* captureOutput = [[AVCaptureVideoDataOutput alloc] init];
|
||||
AVCaptureVideoDataOutput* captureOutput =
|
||||
[[AVCaptureVideoDataOutput alloc] init];
|
||||
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
|
||||
|
||||
NSNumber* val = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8];
|
||||
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val forKey:key];
|
||||
NSNumber* val =
|
||||
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8];
|
||||
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val
|
||||
forKey:key];
|
||||
captureOutput.videoSettings = videoSettings;
|
||||
|
||||
// add new output
|
||||
if ([_captureSession canAddOutput:captureOutput]) {
|
||||
[_captureSession addOutput:captureOutput];
|
||||
} else {
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << ": Could not add output to AVCaptureSession";
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__
|
||||
<< ": Could not add output to AVCaptureSession";
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_IOS
|
||||
|
@ -86,12 +90,14 @@ using namespace webrtc::videocapturemodule;
|
|||
#endif
|
||||
}
|
||||
|
||||
// Create a serial queue on which video capture will run. By setting the target,
|
||||
// blocks should still run on DISPATH_QUEUE_PRIORITY_DEFAULT rather than creating
|
||||
// a new thread.
|
||||
_frameQueue = dispatch_queue_create("org.webrtc.videocapture", DISPATCH_QUEUE_SERIAL);
|
||||
dispatch_set_target_queue(_frameQueue,
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
||||
// Create a serial queue on which video capture will run. By setting the
|
||||
// target, blocks should still run on DISPATH_QUEUE_PRIORITY_DEFAULT rather
|
||||
// than creating a new thread.
|
||||
_frameQueue =
|
||||
dispatch_queue_create("org.webrtc.videocapture", DISPATCH_QUEUE_SERIAL);
|
||||
dispatch_set_target_queue(
|
||||
_frameQueue,
|
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -144,11 +150,13 @@ using namespace webrtc::videocapturemodule;
|
|||
if (capability.width > 1280 || capability.height > 720) {
|
||||
return NO;
|
||||
}
|
||||
} else if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
|
||||
} else if ([_captureSession
|
||||
canSetSessionPreset:AVCaptureSessionPreset640x480]) {
|
||||
if (capability.width > 640 || capability.height > 480) {
|
||||
return NO;
|
||||
}
|
||||
} else if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset352x288]) {
|
||||
} else if ([_captureSession
|
||||
canSetSessionPreset:AVCaptureSessionPreset352x288]) {
|
||||
if (capability.width > 352 || capability.height > 288) {
|
||||
return NO;
|
||||
}
|
||||
|
@ -175,8 +183,10 @@ using namespace webrtc::videocapturemodule;
|
|||
return [[_captureSession outputs] firstObject];
|
||||
}
|
||||
|
||||
- (void)startCaptureInBackgroundWithOutput:(AVCaptureVideoDataOutput*)currentOutput {
|
||||
NSString* captureQuality = [NSString stringWithString:AVCaptureSessionPresetLow];
|
||||
- (void)startCaptureInBackgroundWithOutput:
|
||||
(AVCaptureVideoDataOutput*)currentOutput {
|
||||
NSString* captureQuality =
|
||||
[NSString stringWithString:AVCaptureSessionPresetLow];
|
||||
if (_capability.width >= 1280 || _capability.height >= 720) {
|
||||
captureQuality = [NSString stringWithString:AVCaptureSessionPreset1280x720];
|
||||
} else if (_capability.width >= 640 || _capability.height >= 480) {
|
||||
|
@ -214,7 +224,8 @@ using namespace webrtc::videocapturemodule;
|
|||
_connection.videoOrientation = AVCaptureVideoOrientationPortrait;
|
||||
break;
|
||||
case UIDeviceOrientationPortraitUpsideDown:
|
||||
_connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
|
||||
_connection.videoOrientation =
|
||||
AVCaptureVideoOrientationPortraitUpsideDown;
|
||||
break;
|
||||
case UIDeviceOrientationLandscapeLeft:
|
||||
_connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
|
||||
|
@ -236,7 +247,8 @@ using namespace webrtc::videocapturemodule;
|
|||
- (void)onVideoError:(NSNotification*)notification {
|
||||
NSLog(@"onVideoError: %@", notification);
|
||||
// TODO(sjlee): make the specific error handling with this notification.
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << ": [AVCaptureSession startRunning] error.";
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__
|
||||
<< ": [AVCaptureSession startRunning] error.";
|
||||
}
|
||||
|
||||
- (BOOL)stopCapture {
|
||||
|
@ -265,7 +277,8 @@ using namespace webrtc::videocapturemodule;
|
|||
NSArray* currentInputs = [_captureSession inputs];
|
||||
// remove current input
|
||||
if ([currentInputs count] > 0) {
|
||||
AVCaptureInput* currentInput = (AVCaptureInput*)[currentInputs objectAtIndex:0];
|
||||
AVCaptureInput* currentInput =
|
||||
(AVCaptureInput*)[currentInputs objectAtIndex:0];
|
||||
|
||||
[_captureSession removeInput:currentInput];
|
||||
}
|
||||
|
@ -277,7 +290,8 @@ using namespace webrtc::videocapturemodule;
|
|||
return NO;
|
||||
}
|
||||
|
||||
AVCaptureDevice* captureDevice = [DeviceInfoIosObjC captureDeviceForUniqueId:uniqueId];
|
||||
AVCaptureDevice* captureDevice =
|
||||
[DeviceInfoIosObjC captureDeviceForUniqueId:uniqueId];
|
||||
|
||||
if (!captureDevice) {
|
||||
return NO;
|
||||
|
@ -285,13 +299,15 @@ using namespace webrtc::videocapturemodule;
|
|||
|
||||
// now create capture session input out of AVCaptureDevice
|
||||
NSError* deviceError = nil;
|
||||
AVCaptureDeviceInput* newCaptureInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice
|
||||
error:&deviceError];
|
||||
AVCaptureDeviceInput* newCaptureInput =
|
||||
[AVCaptureDeviceInput deviceInputWithDevice:captureDevice
|
||||
error:&deviceError];
|
||||
|
||||
if (!newCaptureInput) {
|
||||
const char* errorMessage = [[deviceError localizedDescription] UTF8String];
|
||||
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << ": deviceInputWithDevice error:" << errorMessage;
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__
|
||||
<< ": deviceInputWithDevice error:" << errorMessage;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ using namespace mozilla;
|
|||
using namespace webrtc;
|
||||
using namespace videocapturemodule;
|
||||
|
||||
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(const char* deviceUniqueIdUTF8) {
|
||||
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(
|
||||
const char* deviceUniqueIdUTF8) {
|
||||
if (StaticPrefs::media_getusermedia_camera_macavf_enabled_AtStartup()) {
|
||||
return VideoCaptureAvFoundation::Create(deviceUniqueIdUTF8);
|
||||
}
|
||||
|
@ -44,12 +45,14 @@ VideoCaptureIos::~VideoCaptureIos() {
|
|||
}
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureIos::Create(const char* deviceUniqueIdUTF8) {
|
||||
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureIos::Create(
|
||||
const char* deviceUniqueIdUTF8) {
|
||||
if (!deviceUniqueIdUTF8[0]) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<VideoCaptureIos> capture_module(new rtc::RefCountedObject<VideoCaptureIos>());
|
||||
rtc::scoped_refptr<VideoCaptureIos> capture_module(
|
||||
new rtc::RefCountedObject<VideoCaptureIos>());
|
||||
|
||||
const int32_t name_length = strlen(deviceUniqueIdUTF8);
|
||||
if (name_length >= kVideoCaptureUniqueNameLength) return nullptr;
|
||||
|
@ -65,14 +68,16 @@ rtc::scoped_refptr<VideoCaptureModule> VideoCaptureIos::Create(const char* devic
|
|||
}
|
||||
|
||||
if (![capture_module->capture_device_
|
||||
setCaptureDeviceByUniqueId:[[NSString alloc] initWithCString:deviceUniqueIdUTF8
|
||||
encoding:NSUTF8StringEncoding]]) {
|
||||
setCaptureDeviceByUniqueId:
|
||||
[[NSString alloc] initWithCString:deviceUniqueIdUTF8
|
||||
encoding:NSUTF8StringEncoding]]) {
|
||||
return nullptr;
|
||||
}
|
||||
return capture_module;
|
||||
}
|
||||
|
||||
int32_t VideoCaptureIos::StartCapture(const VideoCaptureCapability& capability) {
|
||||
int32_t VideoCaptureIos::StartCapture(
|
||||
const VideoCaptureCapability& capability) {
|
||||
capability_ = capability;
|
||||
|
||||
if (![capture_device_ startCaptureWithCapability:capability]) {
|
||||
|
|
|
@ -38,30 +38,37 @@ webrtc::VideoRotation ToNativeRotation(RTCVideoRotation aRotation) {
|
|||
case RTCVideoRotation_270:
|
||||
return webrtc::kVideoRotation_270;
|
||||
default:
|
||||
MOZ_CRASH_UNSAFE_PRINTF("Unexpected rotation %d", static_cast<int>(aRotation));
|
||||
MOZ_CRASH_UNSAFE_PRINTF("Unexpected rotation %d",
|
||||
static_cast<int>(aRotation));
|
||||
return webrtc::kVideoRotation_0;
|
||||
}
|
||||
}
|
||||
|
||||
AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
|
||||
webrtc::VideoCaptureCapability aCapability) {
|
||||
AVCaptureDeviceFormat* _Nullable FindFormat(
|
||||
AVCaptureDevice* _Nonnull aDevice,
|
||||
webrtc::VideoCaptureCapability aCapability) {
|
||||
for (AVCaptureDeviceFormat* format in [aDevice formats]) {
|
||||
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
|
||||
CMVideoDimensions dimensions =
|
||||
CMVideoFormatDescriptionGetDimensions(format.formatDescription);
|
||||
if (dimensions.width != aCapability.width) {
|
||||
continue;
|
||||
}
|
||||
if (dimensions.height != aCapability.height) {
|
||||
continue;
|
||||
}
|
||||
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(format.formatDescription);
|
||||
if (aCapability.videoType != DeviceInfoAvFoundation::ConvertFourCCToVideoType(fourcc)) {
|
||||
FourCharCode fourcc =
|
||||
CMFormatDescriptionGetMediaSubType(format.formatDescription);
|
||||
if (aCapability.videoType !=
|
||||
DeviceInfoAvFoundation::ConvertFourCCToVideoType(fourcc)) {
|
||||
continue;
|
||||
}
|
||||
if ([format.videoSupportedFrameRateRanges
|
||||
indexOfObjectPassingTest:^BOOL(AVFrameRateRange* _Nonnull obj, NSUInteger idx,
|
||||
indexOfObjectPassingTest:^BOOL(AVFrameRateRange* _Nonnull obj,
|
||||
NSUInteger idx,
|
||||
BOOL* _Nonnull stop) {
|
||||
return static_cast<BOOL>(DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
|
||||
obj.maxFrameRate) == aCapability.maxFPS);
|
||||
return static_cast<BOOL>(
|
||||
DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
|
||||
obj.maxFrameRate) == aCapability.maxFPS);
|
||||
}] == NSNotFound) {
|
||||
continue;
|
||||
}
|
||||
|
@ -73,7 +80,8 @@ AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
|
|||
} // namespace
|
||||
|
||||
@implementation VideoCaptureAdapter
|
||||
- (void)setCapturer:(webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable)capturer {
|
||||
- (void)setCapturer:
|
||||
(webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable)capturer {
|
||||
webrtc::MutexLock lock(&_mutex);
|
||||
_capturer = capturer;
|
||||
}
|
||||
|
@ -91,10 +99,12 @@ AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
|
|||
@end
|
||||
|
||||
namespace webrtc::videocapturemodule {
|
||||
VideoCaptureAvFoundation::VideoCaptureAvFoundation(AVCaptureDevice* _Nonnull aDevice)
|
||||
VideoCaptureAvFoundation::VideoCaptureAvFoundation(
|
||||
AVCaptureDevice* _Nonnull aDevice)
|
||||
: mDevice(aDevice),
|
||||
mAdapter([[VideoCaptureAdapter alloc] init]),
|
||||
mCapturer([[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc] initWithDelegate:mAdapter]),
|
||||
mCapturer([[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc]
|
||||
initWithDelegate:mAdapter]),
|
||||
mCallbackThreadId() {
|
||||
const char* uniqueId = [[aDevice uniqueID] UTF8String];
|
||||
size_t len = strlen(uniqueId);
|
||||
|
@ -123,7 +133,8 @@ rtc::scoped_refptr<VideoCaptureModule> VideoCaptureAvFoundation::Create(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t VideoCaptureAvFoundation::StartCapture(const VideoCaptureCapability& aCapability) {
|
||||
int32_t VideoCaptureAvFoundation::StartCapture(
|
||||
const VideoCaptureCapability& aCapability) {
|
||||
RTC_DCHECK_RUN_ON(&mChecker);
|
||||
AVCaptureDeviceFormat* format = FindFormat(mDevice, aCapability);
|
||||
if (!format) {
|
||||
|
@ -133,7 +144,8 @@ int32_t VideoCaptureAvFoundation::StartCapture(const VideoCaptureCapability& aCa
|
|||
{
|
||||
MutexLock lock(&api_lock_);
|
||||
if (mCapability) {
|
||||
if (mCapability->width == aCapability.width && mCapability->height == aCapability.height &&
|
||||
if (mCapability->width == aCapability.width &&
|
||||
mCapability->height == aCapability.height &&
|
||||
mCapability->maxFPS == aCapability.maxFPS &&
|
||||
mCapability->videoType == aCapability.videoType) {
|
||||
return 0;
|
||||
|
@ -250,28 +262,33 @@ bool VideoCaptureAvFoundation::CaptureStarted() {
|
|||
return mCapability.isSome();
|
||||
}
|
||||
|
||||
int32_t VideoCaptureAvFoundation::CaptureSettings(VideoCaptureCapability& aSettings) {
|
||||
int32_t VideoCaptureAvFoundation::CaptureSettings(
|
||||
VideoCaptureCapability& aSettings) {
|
||||
MOZ_CRASH("Unexpected call");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t VideoCaptureAvFoundation::OnFrame(__strong RTCVideoFrame* _Nonnull aFrame) {
|
||||
int32_t VideoCaptureAvFoundation::OnFrame(
|
||||
__strong RTCVideoFrame* _Nonnull aFrame) {
|
||||
MaybeRegisterCallbackThread();
|
||||
if (MutexLock lock(&api_lock_); MOZ_LIKELY(mTrackingId)) {
|
||||
mCaptureRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width,
|
||||
aFrame.height, mImageType.valueOr(CaptureStage::ImageType::Unknown));
|
||||
mCaptureRecorder.Start(
|
||||
0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width,
|
||||
aFrame.height, mImageType.valueOr(CaptureStage::ImageType::Unknown));
|
||||
if (mCapability && mCapability->videoType != webrtc::VideoType::kI420) {
|
||||
mConversionRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width,
|
||||
aFrame.height);
|
||||
mConversionRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId,
|
||||
aFrame.width, aFrame.height);
|
||||
}
|
||||
}
|
||||
|
||||
const int64_t timestamp_us = aFrame.timeStampNs / rtc::kNumNanosecsPerMicrosec;
|
||||
const int64_t timestamp_us =
|
||||
aFrame.timeStampNs / rtc::kNumNanosecsPerMicrosec;
|
||||
RTCI420Buffer* buffer = [aFrame.buffer toI420];
|
||||
mConversionRecorder.Record(0);
|
||||
// Accessing the (intended-to-be-private) native buffer directly is hacky but lets us skip two
|
||||
// copies
|
||||
rtc::scoped_refptr<webrtc::I420BufferInterface> nativeBuffer = buffer.nativeI420Buffer;
|
||||
// Accessing the (intended-to-be-private) native buffer directly is hacky but
|
||||
// lets us skip two copies
|
||||
rtc::scoped_refptr<webrtc::I420BufferInterface> nativeBuffer =
|
||||
buffer.nativeI420Buffer;
|
||||
auto frame = webrtc::VideoFrame::Builder()
|
||||
.set_video_frame_buffer(nativeBuffer)
|
||||
.set_rotation(ToNativeRotation(aFrame.rotation))
|
||||
|
@ -288,8 +305,8 @@ void VideoCaptureAvFoundation::SetTrackingId(uint32_t aTrackingIdProcId) {
|
|||
RTC_DCHECK_RUN_ON(&mChecker);
|
||||
MutexLock lock(&api_lock_);
|
||||
if (NS_WARN_IF(mTrackingId.isSome())) {
|
||||
// This capture instance must be shared across multiple camera requests. For now ignore other
|
||||
// requests than the first.
|
||||
// This capture instance must be shared across multiple camera requests. For
|
||||
// now ignore other requests than the first.
|
||||
return;
|
||||
}
|
||||
mTrackingId.emplace(TrackingId::Source::Camera, aTrackingIdProcId);
|
||||
|
@ -301,6 +318,7 @@ void VideoCaptureAvFoundation::MaybeRegisterCallbackThread() {
|
|||
return;
|
||||
}
|
||||
mCallbackThreadId = id;
|
||||
CallbackThreadRegistry::Get()->Register(mCallbackThreadId, "VideoCaptureAVFoundationCallback");
|
||||
CallbackThreadRegistry::Get()->Register(mCallbackThreadId,
|
||||
"VideoCaptureAVFoundationCallback");
|
||||
}
|
||||
} // namespace webrtc::videocapturemodule
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset:
|
||||
* 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=80: */
|
||||
/* 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
|
||||
|
@ -37,7 +38,8 @@ class SpeechTaskCallback final : public nsISpeechTaskCallback {
|
|||
const nsTArray<size_t>& aOffsets);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechTaskCallback, nsISpeechTaskCallback)
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechTaskCallback,
|
||||
nsISpeechTaskCallback)
|
||||
|
||||
NS_DECL_NSISPEECHTASKCALLBACK
|
||||
|
||||
|
@ -79,7 +81,8 @@ class SpeechTaskCallback final : public nsISpeechTaskCallback {
|
|||
mCallback->OnWillSpeakWord(aRange.location, aRange.length);
|
||||
}
|
||||
|
||||
- (void)speechSynthesizer:(NSSpeechSynthesizer*)aSender didFinishSpeaking:(BOOL)aFinishedSpeaking {
|
||||
- (void)speechSynthesizer:(NSSpeechSynthesizer*)aSender
|
||||
didFinishSpeaking:(BOOL)aFinishedSpeaking {
|
||||
mCallback->OnDidFinishSpeaking();
|
||||
}
|
||||
|
||||
|
@ -101,9 +104,13 @@ NS_INTERFACE_MAP_END
|
|||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechTaskCallback)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechTaskCallback)
|
||||
|
||||
SpeechTaskCallback::SpeechTaskCallback(nsISpeechTask* aTask, NSSpeechSynthesizer* aSynth,
|
||||
SpeechTaskCallback::SpeechTaskCallback(nsISpeechTask* aTask,
|
||||
NSSpeechSynthesizer* aSynth,
|
||||
const nsTArray<size_t>& aOffsets)
|
||||
: mTask(aTask), mSpeechSynthesizer(aSynth), mCurrentIndex(0), mOffsets(aOffsets.Clone()) {
|
||||
: mTask(aTask),
|
||||
mSpeechSynthesizer(aSynth),
|
||||
mCurrentIndex(0),
|
||||
mOffsets(aOffsets.Clone()) {
|
||||
mDelegate = [[SpeechDelegate alloc] initWithCallback:this];
|
||||
[mSpeechSynthesizer setDelegate:mDelegate];
|
||||
mStartingTime = TimeStamp::Now();
|
||||
|
@ -179,7 +186,8 @@ void SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex, uint32_t aLength) {
|
|||
if (!mTask) {
|
||||
return;
|
||||
}
|
||||
mTask->DispatchBoundary(u"word"_ns, GetTimeDurationFromStart(), mCurrentIndex, aLength, 1);
|
||||
mTask->DispatchBoundary(u"word"_ns, GetTimeDurationFromStart(), mCurrentIndex,
|
||||
aLength, 1);
|
||||
}
|
||||
|
||||
void SpeechTaskCallback::OnError(uint32_t aIndex) {
|
||||
|
@ -210,8 +218,11 @@ struct OSXVoice {
|
|||
|
||||
class RegisterVoicesRunnable final : public Runnable {
|
||||
public:
|
||||
RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService, nsTArray<OSXVoice>& aList)
|
||||
: Runnable("RegisterVoicesRunnable"), mSpeechService(aSpeechService), mVoices(aList) {}
|
||||
RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService,
|
||||
nsTArray<OSXVoice>& aList)
|
||||
: Runnable("RegisterVoicesRunnable"),
|
||||
mSpeechService(aSpeechService),
|
||||
mVoices(aList) {}
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
|
@ -226,13 +237,15 @@ class RegisterVoicesRunnable final : public Runnable {
|
|||
NS_IMETHODIMP
|
||||
RegisterVoicesRunnable::Run() {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISynthVoiceRegistry> registry = do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID, &rv);
|
||||
nsCOMPtr<nsISynthVoiceRegistry> registry =
|
||||
do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID, &rv);
|
||||
if (!registry) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (OSXVoice voice : mVoices) {
|
||||
rv = registry->AddVoice(mSpeechService, voice.mUri, voice.mName, voice.mLocale, true, false);
|
||||
rv = registry->AddVoice(mSpeechService, voice.mUri, voice.mName,
|
||||
voice.mLocale, true, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
@ -275,11 +288,14 @@ EnumVoicesRunnable::Run() {
|
|||
NSDictionary* attr = [NSSpeechSynthesizer attributesForVoice:voice];
|
||||
|
||||
nsAutoString identifier;
|
||||
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceIdentifier], identifier);
|
||||
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceIdentifier],
|
||||
identifier);
|
||||
|
||||
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceName], item.mName);
|
||||
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceName],
|
||||
item.mName);
|
||||
|
||||
nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceLocaleIdentifier], item.mLocale);
|
||||
nsCocoaUtils::GetStringForNSString(
|
||||
[attr objectForKey:NSVoiceLocaleIdentifier], item.mLocale);
|
||||
item.mLocale.ReplaceChar('_', '-');
|
||||
|
||||
item.mUri.AssignLiteral("urn:moz-tts:osx:");
|
||||
|
@ -292,16 +308,19 @@ EnumVoicesRunnable::Run() {
|
|||
list.AppendElement(item);
|
||||
}
|
||||
|
||||
RefPtr<RegisterVoicesRunnable> runnable = new RegisterVoicesRunnable(mSpeechService, list);
|
||||
RefPtr<RegisterVoicesRunnable> runnable =
|
||||
new RegisterVoicesRunnable(mSpeechService, list);
|
||||
NS_DispatchAndSpinEventLoopUntilComplete("EnumVoicesRunnable"_ns,
|
||||
GetMainThreadSerialEventTarget(), runnable.forget());
|
||||
GetMainThreadSerialEventTarget(),
|
||||
runnable.forget());
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
StaticRefPtr<OSXSpeechSynthesizerService> OSXSpeechSynthesizerService::sSingleton;
|
||||
StaticRefPtr<OSXSpeechSynthesizerService>
|
||||
OSXSpeechSynthesizerService::sSingleton;
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(OSXSpeechSynthesizerService)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISpeechService)
|
||||
|
@ -312,7 +331,8 @@ NS_INTERFACE_MAP_END
|
|||
NS_IMPL_ADDREF(OSXSpeechSynthesizerService)
|
||||
NS_IMPL_RELEASE(OSXSpeechSynthesizerService)
|
||||
|
||||
OSXSpeechSynthesizerService::OSXSpeechSynthesizerService() : mInitialized(false) {}
|
||||
OSXSpeechSynthesizerService::OSXSpeechSynthesizerService()
|
||||
: mInitialized(false) {}
|
||||
|
||||
bool OSXSpeechSynthesizerService::Init() {
|
||||
if (Preferences::GetBool("media.webspeech.synth.test") ||
|
||||
|
@ -335,8 +355,10 @@ bool OSXSpeechSynthesizerService::Init() {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri, float aVolume,
|
||||
float aRate, float aPitch, nsISpeechTask* aTask) {
|
||||
OSXSpeechSynthesizerService::Speak(const nsAString& aText,
|
||||
const nsAString& aUri, float aVolume,
|
||||
float aRate, float aPitch,
|
||||
nsISpeechTask* aTask) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
MOZ_ASSERT(StringBeginsWith(aUri, u"urn:moz-tts:osx:"_ns),
|
||||
|
@ -348,11 +370,16 @@ OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri
|
|||
[synth setVoice:identifier];
|
||||
|
||||
// default rate is 180-220
|
||||
[synth setObject:[NSNumber numberWithInt:aRate * 200] forProperty:NSSpeechRateProperty error:nil];
|
||||
[synth setObject:[NSNumber numberWithInt:aRate * 200]
|
||||
forProperty:NSSpeechRateProperty
|
||||
error:nil];
|
||||
// volume allows 0.0-1.0
|
||||
[synth setObject:[NSNumber numberWithFloat:aVolume] forProperty:NSSpeechVolumeProperty error:nil];
|
||||
[synth setObject:[NSNumber numberWithFloat:aVolume]
|
||||
forProperty:NSSpeechVolumeProperty
|
||||
error:nil];
|
||||
// Use default pitch value to calculate this
|
||||
NSNumber* defaultPitch = [synth objectForProperty:NSSpeechPitchBaseProperty error:nil];
|
||||
NSNumber* defaultPitch = [synth objectForProperty:NSSpeechPitchBaseProperty
|
||||
error:nil];
|
||||
if (defaultPitch) {
|
||||
int newPitch = [defaultPitch intValue] * (aPitch / 2 + 0.5);
|
||||
[synth setObject:[NSNumber numberWithInt:newPitch]
|
||||
|
@ -370,8 +397,8 @@ OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri
|
|||
// This loop looks for occurances of "[[" or "]]", escapes them, and
|
||||
// populates the offsets array to supply a map to the original offsets.
|
||||
for (size_t i = 0; i < aText.Length(); i++) {
|
||||
if (aText.Length() > i + 1 &&
|
||||
((aText[i] == ']' && aText[i + 1] == ']') || (aText[i] == '[' && aText[i + 1] == '['))) {
|
||||
if (aText.Length() > i + 1 && ((aText[i] == ']' && aText[i + 1] == ']') ||
|
||||
(aText[i] == '[' && aText[i + 1] == '['))) {
|
||||
escapedText.AppendLiteral(DLIM_ESCAPE_START);
|
||||
offsets.AppendElements(strlen(DLIM_ESCAPE_START));
|
||||
escapedText.Append(aText[i]);
|
||||
|
@ -386,7 +413,8 @@ OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<SpeechTaskCallback> callback = new SpeechTaskCallback(aTask, synth, offsets);
|
||||
RefPtr<SpeechTaskCallback> callback =
|
||||
new SpeechTaskCallback(aTask, synth, offsets);
|
||||
nsresult rv = aTask->Setup(callback);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -413,7 +441,8 @@ OSXSpeechSynthesizerService* OSXSpeechSynthesizerService::GetInstance() {
|
|||
}
|
||||
|
||||
if (!sSingleton) {
|
||||
RefPtr<OSXSpeechSynthesizerService> speechService = new OSXSpeechSynthesizerService();
|
||||
RefPtr<OSXSpeechSynthesizerService> speechService =
|
||||
new OSXSpeechSynthesizerService();
|
||||
if (speechService->Init()) {
|
||||
sSingleton = speechService;
|
||||
ClearOnShutdown(&sSingleton);
|
||||
|
@ -422,7 +451,8 @@ OSXSpeechSynthesizerService* OSXSpeechSynthesizerService::GetInstance() {
|
|||
return sSingleton;
|
||||
}
|
||||
|
||||
already_AddRefed<OSXSpeechSynthesizerService> OSXSpeechSynthesizerService::GetInstanceForService() {
|
||||
already_AddRefed<OSXSpeechSynthesizerService>
|
||||
OSXSpeechSynthesizerService::GetInstanceForService() {
|
||||
RefPtr<OSXSpeechSynthesizerService> speechService = GetInstance();
|
||||
return speechService.forget();
|
||||
}
|
||||
|
|
|
@ -29,15 +29,18 @@
|
|||
using namespace mozilla;
|
||||
|
||||
static const CLLocationAccuracy kHIGH_ACCURACY = kCLLocationAccuracyBest;
|
||||
static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTenMeters;
|
||||
static const CLLocationAccuracy kDEFAULT_ACCURACY =
|
||||
kCLLocationAccuracyNearestTenMeters;
|
||||
|
||||
@interface LocationDelegate : NSObject <CLLocationManagerDelegate> {
|
||||
CoreLocationLocationProvider* mProvider;
|
||||
}
|
||||
|
||||
- (id)init:(CoreLocationLocationProvider*)aProvider;
|
||||
- (void)locationManager:(CLLocationManager*)aManager didFailWithError:(NSError*)aError;
|
||||
- (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)locations;
|
||||
- (void)locationManager:(CLLocationManager*)aManager
|
||||
didFailWithError:(NSError*)aError;
|
||||
- (void)locationManager:(CLLocationManager*)aManager
|
||||
didUpdateLocations:(NSArray*)locations;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -50,28 +53,32 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager*)aManager didFailWithError:(NSError*)aError {
|
||||
nsCOMPtr<nsIConsoleService> console = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
- (void)locationManager:(CLLocationManager*)aManager
|
||||
didFailWithError:(NSError*)aError {
|
||||
nsCOMPtr<nsIConsoleService> console =
|
||||
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
|
||||
NS_ENSURE_TRUE_VOID(console);
|
||||
|
||||
NSString* message =
|
||||
[@"Failed to acquire position: " stringByAppendingString:[aError localizedDescription]];
|
||||
NSString* message = [@"Failed to acquire position: "
|
||||
stringByAppendingString:[aError localizedDescription]];
|
||||
|
||||
console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get());
|
||||
|
||||
if ([aError code] == kCLErrorDenied) {
|
||||
mProvider->NotifyError(dom::GeolocationPositionError_Binding::PERMISSION_DENIED);
|
||||
mProvider->NotifyError(
|
||||
dom::GeolocationPositionError_Binding::PERMISSION_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
// The CL provider does not fallback to GeoIP, so use NetworkGeolocationProvider for this.
|
||||
// The concept here is: on error, hand off geolocation to MLS, which will then report
|
||||
// back a location or error.
|
||||
// The CL provider does not fallback to GeoIP, so use
|
||||
// NetworkGeolocationProvider for this. The concept here is: on error, hand
|
||||
// off geolocation to MLS, which will then report back a location or error.
|
||||
mProvider->CreateMLSFallbackProvider();
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)aLocations {
|
||||
- (void)locationManager:(CLLocationManager*)aManager
|
||||
didUpdateLocations:(NSArray*)aLocations {
|
||||
if (aLocations.count < 1) {
|
||||
return;
|
||||
}
|
||||
|
@ -92,24 +99,29 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe
|
|||
altitudeAccuracy = UnspecifiedNaN<double>();
|
||||
}
|
||||
|
||||
double speed = location.speed >= 0 ? location.speed : UnspecifiedNaN<double>();
|
||||
double speed =
|
||||
location.speed >= 0 ? location.speed : UnspecifiedNaN<double>();
|
||||
|
||||
double heading = location.course >= 0 ? location.course : UnspecifiedNaN<double>();
|
||||
double heading =
|
||||
location.course >= 0 ? location.course : UnspecifiedNaN<double>();
|
||||
|
||||
// nsGeoPositionCoords will convert NaNs to null for optional properties of
|
||||
// the JavaScript Coordinates object.
|
||||
nsCOMPtr<nsIDOMGeoPosition> geoPosition = new nsGeoPosition(
|
||||
location.coordinate.latitude, location.coordinate.longitude, altitude,
|
||||
location.horizontalAccuracy, altitudeAccuracy, heading, speed, PR_Now() / PR_USEC_PER_MSEC);
|
||||
location.horizontalAccuracy, altitudeAccuracy, heading, speed,
|
||||
PR_Now() / PR_USEC_PER_MSEC);
|
||||
|
||||
mProvider->Update(geoPosition);
|
||||
Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, false);
|
||||
}
|
||||
@end
|
||||
|
||||
NS_IMPL_ISUPPORTS(CoreLocationLocationProvider::MLSUpdate, nsIGeolocationUpdate);
|
||||
NS_IMPL_ISUPPORTS(CoreLocationLocationProvider::MLSUpdate,
|
||||
nsIGeolocationUpdate);
|
||||
|
||||
CoreLocationLocationProvider::MLSUpdate::MLSUpdate(CoreLocationLocationProvider& parentProvider)
|
||||
CoreLocationLocationProvider::MLSUpdate::MLSUpdate(
|
||||
CoreLocationLocationProvider& parentProvider)
|
||||
: mParentLocationProvider(parentProvider) {}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -175,7 +187,8 @@ CoreLocationLocationProvider::Startup() {
|
|||
mCLObjects = clObjs.release();
|
||||
}
|
||||
|
||||
// Must be stopped before starting or response (success or failure) is not guaranteed
|
||||
// Must be stopped before starting or response (success or failure) is not
|
||||
// guaranteed
|
||||
[mCLObjects->mLocationManager stopUpdatingLocation];
|
||||
[mCLObjects->mLocationManager startUpdatingLocation];
|
||||
return NS_OK;
|
||||
|
@ -212,7 +225,8 @@ NS_IMETHODIMP
|
|||
CoreLocationLocationProvider::SetHighAccuracy(bool aEnable) {
|
||||
NS_ENSURE_STATE(mCLObjects);
|
||||
|
||||
mCLObjects->mLocationManager.desiredAccuracy = (aEnable ? kHIGH_ACCURACY : kDEFAULT_ACCURACY);
|
||||
mCLObjects->mLocationManager.desiredAccuracy =
|
||||
(aEnable ? kHIGH_ACCURACY : kDEFAULT_ACCURACY);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ nsOSPermissionRequest::GetScreenCapturePermissionState(uint16_t* aScreen) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx, Promise** aPromiseOut) {
|
||||
nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx,
|
||||
Promise** aPromiseOut) {
|
||||
RefPtr<Promise> promiseHandle;
|
||||
nsresult rv = GetPromise(aCx, promiseHandle);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -45,7 +46,8 @@ nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx, Promise** a
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSPermissionRequest::RequestAudioCapturePermission(JSContext* aCx, Promise** aPromiseOut) {
|
||||
nsOSPermissionRequest::RequestAudioCapturePermission(JSContext* aCx,
|
||||
Promise** aPromiseOut) {
|
||||
RefPtr<Promise> promiseHandle;
|
||||
nsresult rv = GetPromise(aCx, promiseHandle);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -37,7 +37,8 @@ class CGLLibrary {
|
|||
return true;
|
||||
}
|
||||
if (!mOGLLibrary) {
|
||||
mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
|
||||
mOGLLibrary =
|
||||
PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
|
||||
if (!mOGLLibrary) {
|
||||
NS_WARNING("Couldn't load OpenGL Framework.");
|
||||
return false;
|
||||
|
@ -59,7 +60,8 @@ CGLLibrary sCGLLibrary;
|
|||
|
||||
GLContextCGL::GLContextCGL(const GLContextDesc& desc, NSOpenGLContext* context)
|
||||
: GLContext(desc), mContext(context) {
|
||||
CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback, this);
|
||||
CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback,
|
||||
this);
|
||||
}
|
||||
|
||||
GLContextCGL::~GLContextCGL() {
|
||||
|
@ -89,33 +91,39 @@ bool GLContextCGL::MakeCurrentImpl() const {
|
|||
// Use non-blocking swap in "ASAP mode".
|
||||
// ASAP mode means that rendering is iterated as fast as possible.
|
||||
// ASAP mode is entered when layout.frame_rate=0 (requires restart).
|
||||
// If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
|
||||
// When we're iterating as fast as possible, however, we want a non-blocking
|
||||
// glSwapBuffers, which will happen when swapInt==0.
|
||||
// If swapInt is 1, then glSwapBuffers will block and wait for a vblank
|
||||
// signal. When we're iterating as fast as possible, however, we want a
|
||||
// non-blocking glSwapBuffers, which will happen when swapInt==0.
|
||||
GLint swapInt = StaticPrefs::layout_frame_rate() == 0 ? 0 : 1;
|
||||
[mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLContextCGL::IsCurrentImpl() const { return [NSOpenGLContext currentContext] == mContext; }
|
||||
bool GLContextCGL::IsCurrentImpl() const {
|
||||
return [NSOpenGLContext currentContext] == mContext;
|
||||
}
|
||||
|
||||
/* static */ void GLContextCGL::DisplayReconfigurationCallback(CGDirectDisplayID aDisplay,
|
||||
CGDisplayChangeSummaryFlags aFlags,
|
||||
void* aUserInfo) {
|
||||
/* static */ void GLContextCGL::DisplayReconfigurationCallback(
|
||||
CGDirectDisplayID aDisplay, CGDisplayChangeSummaryFlags aFlags,
|
||||
void* aUserInfo) {
|
||||
if (aFlags & kCGDisplaySetModeFlag) {
|
||||
static_cast<GLContextCGL*>(aUserInfo)->mActiveGPUSwitchMayHaveOccurred = true;
|
||||
static_cast<GLContextCGL*>(aUserInfo)->mActiveGPUSwitchMayHaveOccurred =
|
||||
true;
|
||||
}
|
||||
}
|
||||
|
||||
static NSOpenGLContext* CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs) {
|
||||
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||
static NSOpenGLContext* CreateWithFormat(
|
||||
const NSOpenGLPixelFormatAttribute* attribs) {
|
||||
NSOpenGLPixelFormat* format =
|
||||
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||
if (!format) {
|
||||
NS_WARNING("Failed to create NSOpenGLPixelFormat.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nullptr];
|
||||
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format
|
||||
shareContext:nullptr];
|
||||
|
||||
[format release];
|
||||
|
||||
|
@ -124,30 +132,40 @@ static NSOpenGLContext* CreateWithFormat(const NSOpenGLPixelFormatAttribute* att
|
|||
|
||||
// Get the "OpenGL display mask" for a fresh context. The return value of this
|
||||
// function depends on the time at which this function is called.
|
||||
// In practice, on a Macbook Pro with an integrated and a discrete GPU, this function returns the
|
||||
// display mask for the GPU that currently drives the internal display.
|
||||
// In practice, on a Macbook Pro with an integrated and a discrete GPU, this
|
||||
// function returns the display mask for the GPU that currently drives the
|
||||
// internal display.
|
||||
//
|
||||
// Quick reference of the concepts involved in the code below:
|
||||
// GPU switch: On Mac devices with an integrated and a discrete GPU, a GPU switch changes which
|
||||
// GPU drives the internal display. Both GPUs are still usable at all times. (When the
|
||||
// integrated GPU is driving the internal display, using the discrete GPU can incur a longer
|
||||
// warm-up cost.)
|
||||
// Virtual screen: A CGL concept. A "virtual screen" corresponds to a GL renderer. There's one
|
||||
// for the integrated GPU, one for each discrete GPU, and one for the Apple software renderer.
|
||||
// The list of virtual screens is per-NSOpenGLPixelFormat; it is filtered down to only the
|
||||
// renderers that support the requirements from the pixel format attributes. Indexes into this
|
||||
// list (such as currentVirtualScreen) cannot be used interchangably across different
|
||||
// NSOpenGLPixelFormat instances.
|
||||
// Display mask: A bitset per GL renderer. Different renderers have disjoint display masks. The
|
||||
// GPU switch: On Mac devices with an integrated and a discrete GPU, a GPU
|
||||
// switch changes which
|
||||
// GPU drives the internal display. Both GPUs are still usable at all times.
|
||||
// (When the integrated GPU is driving the internal display, using the
|
||||
// discrete GPU can incur a longer warm-up cost.)
|
||||
// Virtual screen: A CGL concept. A "virtual screen" corresponds to a GL
|
||||
// renderer. There's one
|
||||
// for the integrated GPU, one for each discrete GPU, and one for the Apple
|
||||
// software renderer. The list of virtual screens is
|
||||
// per-NSOpenGLPixelFormat; it is filtered down to only the renderers that
|
||||
// support the requirements from the pixel format attributes. Indexes into
|
||||
// this list (such as currentVirtualScreen) cannot be used interchangably
|
||||
// across different NSOpenGLPixelFormat instances.
|
||||
// Display mask: A bitset per GL renderer. Different renderers have disjoint
|
||||
// display masks. The
|
||||
// Apple software renderer has all bits zeroed. For each CGDirectDisplayID,
|
||||
// CGDisplayIDToOpenGLDisplayMask(displayID) returns a single bit in the display mask.
|
||||
// CGDirectDisplayID: An ID for each (physical screen, GPU which can drive this screen) pair. The
|
||||
// current CGDirectDisplayID for an NSScreen object can be obtained using [[[screen
|
||||
// deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; it changes depending on
|
||||
// which GPU is currently driving the screen.
|
||||
// CGDisplayIDToOpenGLDisplayMask(displayID) returns a single bit in the
|
||||
// display mask.
|
||||
// CGDirectDisplayID: An ID for each (physical screen, GPU which can drive
|
||||
// this screen) pair. The
|
||||
// current CGDirectDisplayID for an NSScreen object can be obtained using
|
||||
// [[[screen deviceDescription] objectForKey:@"NSScreenNumber"]
|
||||
// unsignedIntValue]; it changes depending on which GPU is currently driving
|
||||
// the screen.
|
||||
static CGOpenGLDisplayMask GetFreshContextDisplayMask() {
|
||||
NSOpenGLPixelFormatAttribute attribs[] = {NSOpenGLPFAAllowOfflineRenderers, 0};
|
||||
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||
NSOpenGLPixelFormatAttribute attribs[] = {NSOpenGLPFAAllowOfflineRenderers,
|
||||
0};
|
||||
NSOpenGLPixelFormat* pixelFormat =
|
||||
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||
MOZ_RELEASE_ASSERT(pixelFormat);
|
||||
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
|
||||
shareContext:nullptr];
|
||||
|
@ -185,13 +203,15 @@ void GLContextCGL::MigrateToActiveGPU() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Find the "virtual screen" with a display mask that matches newPreferredDisplayMask, if
|
||||
// available, and switch the context over to it.
|
||||
// This code was inspired by equivalent functionality in -[NSOpenGLContext update] which only
|
||||
// kicks in for contexts that present via a CAOpenGLLayer.
|
||||
// Find the "virtual screen" with a display mask that matches
|
||||
// newPreferredDisplayMask, if available, and switch the context over to it.
|
||||
// This code was inspired by equivalent functionality in -[NSOpenGLContext
|
||||
// update] which only kicks in for contexts that present via a CAOpenGLLayer.
|
||||
for (const auto i : IntegerRange([pixelFormat numberOfVirtualScreens])) {
|
||||
GLint displayMask = 0;
|
||||
[pixelFormat getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:i];
|
||||
[pixelFormat getValues:&displayMask
|
||||
forAttribute:NSOpenGLPFAScreenMask
|
||||
forVirtualScreen:i];
|
||||
if (IsSameGPU(displayMask, newPreferredDisplayMask)) {
|
||||
CGLSetVirtualScreen([mContext CGLContextObj], i);
|
||||
return;
|
||||
|
@ -212,7 +232,9 @@ bool GLContextCGL::SwapBuffers() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void GLContextCGL::GetWSIInfo(nsCString* const out) const { out->AppendLiteral("CGL"); }
|
||||
void GLContextCGL::GetWSIInfo(nsCString* const out) const {
|
||||
out->AppendLiteral("CGL");
|
||||
}
|
||||
|
||||
Maybe<SymbolLoader> GLContextCGL::GetSymbolLoader() const {
|
||||
const auto& lib = sCGLLibrary.Library();
|
||||
|
@ -220,7 +242,8 @@ Maybe<SymbolLoader> GLContextCGL::GetSymbolLoader() const {
|
|||
}
|
||||
|
||||
already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
|
||||
CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) {
|
||||
CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
|
||||
bool aForceAccelerated) {
|
||||
CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER;
|
||||
if (aForceAccelerated) {
|
||||
flags |= CreateContextFlags::FORBID_SOFTWARE;
|
||||
|
@ -232,7 +255,8 @@ already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
|
|||
return CreateHeadless({flags}, &failureUnused);
|
||||
}
|
||||
|
||||
static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc) {
|
||||
static RefPtr<GLContextCGL> CreateOffscreenFBOContext(
|
||||
GLContextCreateDesc desc) {
|
||||
if (!sCGLLibrary.EnsureInitialized()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -247,8 +271,9 @@ static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc)
|
|||
}
|
||||
if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER ||
|
||||
!(flags & CreateContextFlags::HIGH_POWER)) {
|
||||
// This is really poorly named on Apple's part, but "AllowOfflineRenderers" means
|
||||
// that we want to allow running on the iGPU instead of requiring the dGPU.
|
||||
// This is really poorly named on Apple's part, but "AllowOfflineRenderers"
|
||||
// means that we want to allow running on the iGPU instead of requiring the
|
||||
// dGPU.
|
||||
attribs.push_back(NSOpenGLPFAAllowOfflineRenderers);
|
||||
}
|
||||
|
||||
|
@ -298,8 +323,8 @@ static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc)
|
|||
return glContext;
|
||||
}
|
||||
|
||||
already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(const GLContextCreateDesc& desc,
|
||||
nsACString* const out_failureId) {
|
||||
already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(
|
||||
const GLContextCreateDesc& desc, nsACString* const out_failureId) {
|
||||
auto gl = CreateOffscreenFBOContext(desc);
|
||||
if (!gl) {
|
||||
*out_failureId = "FEATURE_FAILURE_CGL_FBO"_ns;
|
||||
|
|
|
@ -52,7 +52,8 @@ bool GLContextEAGL::AttachToWindow(nsIWidget* aWidget) {
|
|||
// This should only be called once
|
||||
MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
|
||||
|
||||
UIView* view = reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET));
|
||||
UIView* view =
|
||||
reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET));
|
||||
|
||||
if (!view) {
|
||||
MOZ_CRASH("no view!");
|
||||
|
@ -82,10 +83,11 @@ bool GLContextEAGL::RecreateRB() {
|
|||
[mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer];
|
||||
|
||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB);
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER,
|
||||
mBackbufferRB);
|
||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
|
||||
LOCAL_GL_RENDERBUFFER, mBackbufferRB);
|
||||
|
||||
return LOCAL_GL_FRAMEBUFFER_COMPLETE == fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
return LOCAL_GL_FRAMEBUFFER_COMPLETE ==
|
||||
fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
}
|
||||
|
||||
bool GLContextEAGL::MakeCurrentImpl() const {
|
||||
|
@ -97,7 +99,9 @@ bool GLContextEAGL::MakeCurrentImpl() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GLContextEAGL::IsCurrentImpl() const { return [EAGLContext currentContext] == mContext; }
|
||||
bool GLContextEAGL::IsCurrentImpl() const {
|
||||
return [EAGLContext currentContext] == mContext;
|
||||
}
|
||||
|
||||
static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) {
|
||||
PRLibrary* lib = nullptr;
|
||||
|
@ -121,7 +125,9 @@ bool GLContextEAGL::SwapBuffers() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void GLContextEAGL::GetWSIInfo(nsCString* const out) const { out->AppendLiteral("EAGL"); }
|
||||
void GLContextEAGL::GetWSIInfo(nsCString* const out) const {
|
||||
out->AppendLiteral("EAGL");
|
||||
}
|
||||
|
||||
static GLContextEAGL* GetGlobalContextEAGL() {
|
||||
return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
|
||||
|
@ -129,14 +135,16 @@ static GLContextEAGL* GetGlobalContextEAGL() {
|
|||
|
||||
static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
|
||||
GLContextEAGL* sharedContext) {
|
||||
EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3, kEAGLRenderingAPIOpenGLES2};
|
||||
EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3,
|
||||
kEAGLRenderingAPIOpenGLES2};
|
||||
|
||||
// Try to create a GLES3 context if we can, otherwise fall back to GLES2
|
||||
EAGLContext* context = nullptr;
|
||||
for (EAGLRenderingAPI api : apis) {
|
||||
if (sharedContext) {
|
||||
context = [[EAGLContext alloc] initWithAPI:api
|
||||
sharegroup:sharedContext->GetEAGLContext().sharegroup];
|
||||
context = [[EAGLContext alloc]
|
||||
initWithAPI:api
|
||||
sharegroup:sharedContext->GetEAGLContext().sharegroup];
|
||||
} else {
|
||||
context = [[EAGLContext alloc] initWithAPI:api];
|
||||
}
|
||||
|
@ -150,7 +158,8 @@ static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GLContextEAGL> glContext = new GLContextEAGL(desc, context, sharedContext);
|
||||
RefPtr<GLContextEAGL> glContext =
|
||||
new GLContextEAGL(desc, context, sharedContext);
|
||||
if (!glContext->Init()) {
|
||||
glContext = nullptr;
|
||||
return nullptr;
|
||||
|
@ -160,7 +169,8 @@ static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
|
|||
}
|
||||
|
||||
already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
|
||||
CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) {
|
||||
CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
|
||||
bool aForceAccelerated) {
|
||||
if (!aCompositorWidget) {
|
||||
MOZ_ASSERT(false);
|
||||
return nullptr;
|
||||
|
@ -172,7 +182,8 @@ already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aCompositorWidget->RealWidget())) {
|
||||
if (!GLContextEAGL::Cast(glContext)->AttachToWindow(
|
||||
aCompositorWidget->RealWidget())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -193,7 +204,8 @@ GLContext* GLContextProviderEAGL::GetGlobalContext() {
|
|||
if (!triedToCreateContext) {
|
||||
triedToCreateContext = true;
|
||||
|
||||
MOZ_RELEASE_ASSERT(!gGlobalContext, "GFX: Global GL context already initialized.");
|
||||
MOZ_RELEASE_ASSERT(!gGlobalContext,
|
||||
"GFX: Global GL context already initialized.");
|
||||
RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE);
|
||||
gGlobalContext = temp;
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nullptr; c-basic-offset: 2 -*-
|
||||
/* -*- Mode: C++; tab-width: 20; 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/. */
|
||||
|
@ -36,11 +36,13 @@ using gl::GLContextCGL;
|
|||
|
||||
// SurfacePoolCA::LockedPool
|
||||
|
||||
SurfacePoolCA::LockedPool::LockedPool(size_t aPoolSizeLimit) : mPoolSizeLimit(aPoolSizeLimit) {}
|
||||
SurfacePoolCA::LockedPool::LockedPool(size_t aPoolSizeLimit)
|
||||
: mPoolSizeLimit(aPoolSizeLimit) {}
|
||||
|
||||
SurfacePoolCA::LockedPool::~LockedPool() {
|
||||
MOZ_RELEASE_ASSERT(mWrappers.empty(),
|
||||
"Any outstanding wrappers should have kept the surface pool alive");
|
||||
MOZ_RELEASE_ASSERT(
|
||||
mWrappers.empty(),
|
||||
"Any outstanding wrappers should have kept the surface pool alive");
|
||||
MOZ_RELEASE_ASSERT(mInUseEntries.empty(),
|
||||
"Leak! No more surfaces should be in use at this point.");
|
||||
// Remove all entries in mPendingEntries and mAvailableEntries.
|
||||
|
@ -50,8 +52,8 @@ SurfacePoolCA::LockedPool::~LockedPool() {
|
|||
});
|
||||
}
|
||||
|
||||
RefPtr<SurfacePoolCAWrapperForGL> SurfacePoolCA::LockedPool::GetWrapperForGL(SurfacePoolCA* aPool,
|
||||
GLContext* aGL) {
|
||||
RefPtr<SurfacePoolCAWrapperForGL> SurfacePoolCA::LockedPool::GetWrapperForGL(
|
||||
SurfacePoolCA* aPool, GLContext* aGL) {
|
||||
auto& wrapper = mWrappers[aGL];
|
||||
if (!wrapper) {
|
||||
wrapper = new SurfacePoolCAWrapperForGL(aPool, aGL);
|
||||
|
@ -71,7 +73,8 @@ void SurfacePoolCA::LockedPool::DestroyGLResourcesForContext(GLContext* aGL) {
|
|||
|
||||
template <typename F>
|
||||
void SurfacePoolCA::LockedPool::MutateEntryStorage(const char* aMutationType,
|
||||
const gfx::IntSize& aSize, F aFn) {
|
||||
const gfx::IntSize& aSize,
|
||||
F aFn) {
|
||||
[[maybe_unused]] size_t inUseCountBefore = mInUseEntries.size();
|
||||
[[maybe_unused]] size_t pendingCountBefore = mPendingEntries.Length();
|
||||
[[maybe_unused]] size_t availableCountBefore = mAvailableEntries.Length();
|
||||
|
@ -84,9 +87,11 @@ void SurfacePoolCA::LockedPool::MutateEntryStorage(const char* aMutationType,
|
|||
"SurfacePool", GRAPHICS, MarkerTiming::IntervalUntilNowFrom(before),
|
||||
nsPrintfCString("%d -> %d in use | %d -> %d waiting for | %d -> %d "
|
||||
"available | %s %dx%d | %dMB total memory",
|
||||
int(inUseCountBefore), int(mInUseEntries.size()), int(pendingCountBefore),
|
||||
int(mPendingEntries.Length()), int(availableCountBefore),
|
||||
int(mAvailableEntries.Length()), aMutationType, aSize.width, aSize.height,
|
||||
int(inUseCountBefore), int(mInUseEntries.size()),
|
||||
int(pendingCountBefore), int(mPendingEntries.Length()),
|
||||
int(availableCountBefore),
|
||||
int(mAvailableEntries.Length()), aMutationType,
|
||||
aSize.width, aSize.height,
|
||||
int(EstimateTotalMemory() / 1000 / 1000)));
|
||||
}
|
||||
}
|
||||
|
@ -126,8 +131,8 @@ uint64_t SurfacePoolCA::LockedPool::EstimateTotalMemory() {
|
|||
return memBytes;
|
||||
}
|
||||
|
||||
bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(const SurfacePoolEntry& aEntry,
|
||||
const IntSize& aSize, GLContext* aGL) {
|
||||
bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(
|
||||
const SurfacePoolEntry& aEntry, const IntSize& aSize, GLContext* aGL) {
|
||||
if (aEntry.mSize != aSize) {
|
||||
return false;
|
||||
}
|
||||
|
@ -137,14 +142,16 @@ bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(const SurfacePoolEnt
|
|||
return true;
|
||||
}
|
||||
|
||||
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(const IntSize& aSize,
|
||||
GLContext* aGL) {
|
||||
// Do a linear scan through mAvailableEntries to find an eligible surface, going from oldest to
|
||||
// newest. The size of this array is limited, so the linear scan is fast.
|
||||
auto iterToRecycle = std::find_if(mAvailableEntries.begin(), mAvailableEntries.end(),
|
||||
[&](const SurfacePoolEntry& aEntry) {
|
||||
return CanRecycleSurfaceForRequest(aEntry, aSize, aGL);
|
||||
});
|
||||
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(
|
||||
const IntSize& aSize, GLContext* aGL) {
|
||||
// Do a linear scan through mAvailableEntries to find an eligible surface,
|
||||
// going from oldest to newest. The size of this array is limited, so the
|
||||
// linear scan is fast.
|
||||
auto iterToRecycle =
|
||||
std::find_if(mAvailableEntries.begin(), mAvailableEntries.end(),
|
||||
[&](const SurfacePoolEntry& aEntry) {
|
||||
return CanRecycleSurfaceForRequest(aEntry, aSize, aGL);
|
||||
});
|
||||
if (iterToRecycle != mAvailableEntries.end()) {
|
||||
CFTypeRefPtr<IOSurfaceRef> surface = iterToRecycle->mIOSurface;
|
||||
MOZ_RELEASE_ASSERT(surface.get(), "Available surfaces should be non-null.");
|
||||
|
@ -156,18 +163,22 @@ CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(cons
|
|||
return surface;
|
||||
}
|
||||
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("IOSurface creation", GRAPHICS_TileAllocation,
|
||||
nsPrintfCString("%dx%d", aSize.width, aSize.height));
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
|
||||
"IOSurface creation", GRAPHICS_TileAllocation,
|
||||
nsPrintfCString("%dx%d", aSize.width, aSize.height));
|
||||
CFTypeRefPtr<IOSurfaceRef> surface =
|
||||
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(IOSurfaceCreate((__bridge CFDictionaryRef) @{
|
||||
(__bridge NSString*)kIOSurfaceWidth : @(aSize.width),
|
||||
(__bridge NSString*)kIOSurfaceHeight : @(aSize.height),
|
||||
(__bridge NSString*)kIOSurfacePixelFormat : @(kCVPixelFormatType_32BGRA),
|
||||
(__bridge NSString*)kIOSurfaceBytesPerElement : @(4),
|
||||
}));
|
||||
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
|
||||
IOSurfaceCreate((__bridge CFDictionaryRef) @{
|
||||
(__bridge NSString*)kIOSurfaceWidth : @(aSize.width),
|
||||
(__bridge NSString*)kIOSurfaceHeight : @(aSize.height),
|
||||
(__bridge NSString*)
|
||||
kIOSurfacePixelFormat : @(kCVPixelFormatType_32BGRA),
|
||||
(__bridge NSString*)kIOSurfaceBytesPerElement : @(4),
|
||||
}));
|
||||
if (surface) {
|
||||
if (StaticPrefs::gfx_color_management_native_srgb()) {
|
||||
IOSurfaceSetValue(surface.get(), CFSTR("IOSurfaceColorSpace"), kCGColorSpaceSRGB);
|
||||
IOSurfaceSetValue(surface.get(), CFSTR("IOSurfaceColorSpace"),
|
||||
kCGColorSpaceSRGB);
|
||||
}
|
||||
// Create a new entry in mInUseEntries.
|
||||
MutateEntryStorage("Create", aSize, [&]() {
|
||||
|
@ -177,16 +188,18 @@ CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(cons
|
|||
return surface;
|
||||
}
|
||||
|
||||
void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> aSurface) {
|
||||
void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(
|
||||
CFTypeRefPtr<IOSurfaceRef> aSurface) {
|
||||
auto inUseEntryIter = mInUseEntries.find(aSurface);
|
||||
MOZ_RELEASE_ASSERT(inUseEntryIter != mInUseEntries.end());
|
||||
if (IOSurfaceIsInUse(aSurface.get())) {
|
||||
// Move the entry from mInUseEntries to mPendingEntries.
|
||||
MutateEntryStorage("Start waiting for", IntSize(inUseEntryIter->second.mSize), [&]() {
|
||||
mPendingEntries.AppendElement(
|
||||
PendingSurfaceEntry{std::move(inUseEntryIter->second), mCollectionGeneration, 0});
|
||||
mInUseEntries.erase(inUseEntryIter);
|
||||
});
|
||||
MutateEntryStorage(
|
||||
"Start waiting for", IntSize(inUseEntryIter->second.mSize), [&]() {
|
||||
mPendingEntries.AppendElement(PendingSurfaceEntry{
|
||||
std::move(inUseEntryIter->second), mCollectionGeneration, 0});
|
||||
mInUseEntries.erase(inUseEntryIter);
|
||||
});
|
||||
} else {
|
||||
// Move the entry from mInUseEntries to mAvailableEntries.
|
||||
MOZ_RELEASE_ASSERT(inUseEntryIter->second.mIOSurface.get(),
|
||||
|
@ -199,14 +212,16 @@ void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> a
|
|||
}
|
||||
|
||||
void SurfacePoolCA::LockedPool::EnforcePoolSizeLimit() {
|
||||
// Enforce the pool size limit, removing least-recently-used entries as necessary.
|
||||
// Enforce the pool size limit, removing least-recently-used entries as
|
||||
// necessary.
|
||||
while (mAvailableEntries.Length() > mPoolSizeLimit) {
|
||||
MutateEntryStorage("Evict", IntSize(mAvailableEntries[0].mSize),
|
||||
[&]() { mAvailableEntries.RemoveElementAt(0); });
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(uint64_t aCheckGenerationsUpTo) {
|
||||
uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(
|
||||
uint64_t aCheckGenerationsUpTo) {
|
||||
mCollectionGeneration++;
|
||||
|
||||
// Loop from back to front, potentially deleting items as we iterate.
|
||||
|
@ -218,18 +233,21 @@ uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(uint64_t aCheckGenera
|
|||
if (pendingSurf.mPreviousCheckGeneration > aCheckGenerationsUpTo) {
|
||||
continue;
|
||||
}
|
||||
// Check if the window server is still using the surface. As long as it is doing that, we cannot
|
||||
// move the surface to mAvailableSurfaces because anything we draw to it could reach the screen
|
||||
// in a place where we don't expect it.
|
||||
// Check if the window server is still using the surface. As long as it is
|
||||
// doing that, we cannot move the surface to mAvailableSurfaces because
|
||||
// anything we draw to it could reach the screen in a place where we don't
|
||||
// expect it.
|
||||
if (IOSurfaceIsInUse(pendingSurf.mEntry.mIOSurface.get())) {
|
||||
// The surface is still in use. Update mPreviousCheckGeneration and mCheckCount.
|
||||
// The surface is still in use. Update mPreviousCheckGeneration and
|
||||
// mCheckCount.
|
||||
pendingSurf.mPreviousCheckGeneration = mCollectionGeneration;
|
||||
pendingSurf.mCheckCount++;
|
||||
if (pendingSurf.mCheckCount >= 30) {
|
||||
// The window server has been holding on to this surface for an unreasonably long time. This
|
||||
// is known to happen sometimes, for example in occluded windows or after a GPU switch. In
|
||||
// that case, release our references to the surface so that it's Not Our Problem anymore.
|
||||
// Remove the entry from mPendingEntries.
|
||||
// The window server has been holding on to this surface for an
|
||||
// unreasonably long time. This is known to happen sometimes, for
|
||||
// example in occluded windows or after a GPU switch. In that case,
|
||||
// release our references to the surface so that it's Not Our Problem
|
||||
// anymore. Remove the entry from mPendingEntries.
|
||||
MutateEntryStorage("Eject", IntSize(pendingSurf.mEntry.mSize),
|
||||
[&]() { mPendingEntries.RemoveElementAt(i); });
|
||||
}
|
||||
|
@ -238,30 +256,33 @@ uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(uint64_t aCheckGenera
|
|||
// Move the entry from mPendingEntries to mAvailableEntries.
|
||||
MOZ_RELEASE_ASSERT(pendingSurf.mEntry.mIOSurface.get(),
|
||||
"Pending surfaces should be non-null.");
|
||||
MutateEntryStorage("Stop waiting for", IntSize(pendingSurf.mEntry.mSize), [&]() {
|
||||
mAvailableEntries.AppendElement(std::move(pendingSurf.mEntry));
|
||||
mPendingEntries.RemoveElementAt(i);
|
||||
});
|
||||
MutateEntryStorage(
|
||||
"Stop waiting for", IntSize(pendingSurf.mEntry.mSize), [&]() {
|
||||
mAvailableEntries.AppendElement(std::move(pendingSurf.mEntry));
|
||||
mPendingEntries.RemoveElementAt(i);
|
||||
});
|
||||
}
|
||||
}
|
||||
return mCollectionGeneration;
|
||||
}
|
||||
|
||||
void SurfacePoolCA::LockedPool::OnWrapperDestroyed(gl::GLContext* aGL,
|
||||
SurfacePoolCAWrapperForGL* aWrapper) {
|
||||
void SurfacePoolCA::LockedPool::OnWrapperDestroyed(
|
||||
gl::GLContext* aGL, SurfacePoolCAWrapperForGL* aWrapper) {
|
||||
if (aGL) {
|
||||
DestroyGLResourcesForContext(aGL);
|
||||
}
|
||||
|
||||
auto iter = mWrappers.find(aGL);
|
||||
MOZ_RELEASE_ASSERT(iter != mWrappers.end());
|
||||
MOZ_RELEASE_ASSERT(iter->second == aWrapper, "Only one SurfacePoolCAWrapperForGL object should "
|
||||
"exist for each GLContext* at any time");
|
||||
MOZ_RELEASE_ASSERT(iter->second == aWrapper,
|
||||
"Only one SurfacePoolCAWrapperForGL object should "
|
||||
"exist for each GLContext* at any time");
|
||||
mWrappers.erase(iter);
|
||||
}
|
||||
|
||||
Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
||||
CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL, bool aNeedsDepthBuffer) {
|
||||
CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL,
|
||||
bool aNeedsDepthBuffer) {
|
||||
MOZ_RELEASE_ASSERT(aGL);
|
||||
|
||||
auto inUseEntryIter = mInUseEntries.find(aSurface);
|
||||
|
@ -271,7 +292,8 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
|||
if (entry.mGLResources) {
|
||||
// We have an existing framebuffer.
|
||||
MOZ_RELEASE_ASSERT(entry.mGLResources->mGLContext == aGL,
|
||||
"Recycled surface that still had GL resources from a different GL context. "
|
||||
"Recycled surface that still had GL resources from a "
|
||||
"different GL context. "
|
||||
"This shouldn't happen.");
|
||||
if (!aNeedsDepthBuffer || entry.mGLResources->mFramebuffer->HasDepth()) {
|
||||
return Some(entry.mGLResources->mFramebuffer->mFB);
|
||||
|
@ -294,13 +316,16 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
|||
|
||||
GLuint tex = aGL->CreateTexture();
|
||||
{
|
||||
const gl::ScopedBindTexture bindTex(aGL, tex, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
||||
CGLTexImageIOSurface2D(cgl->GetCGLContext(), LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_RGBA,
|
||||
entry.mSize.width, entry.mSize.height, LOCAL_GL_BGRA,
|
||||
LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, entry.mIOSurface.get(), 0);
|
||||
const gl::ScopedBindTexture bindTex(aGL, tex,
|
||||
LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
||||
CGLTexImageIOSurface2D(cgl->GetCGLContext(), LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_RGBA, entry.mSize.width, entry.mSize.height,
|
||||
LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
entry.mIOSurface.get(), 0);
|
||||
}
|
||||
|
||||
auto fb = CreateFramebufferForTexture(aGL, entry.mSize, tex, aNeedsDepthBuffer);
|
||||
auto fb =
|
||||
CreateFramebufferForTexture(aGL, entry.mSize, tex, aNeedsDepthBuffer);
|
||||
if (!fb) {
|
||||
// Framebuffer completeness check may have failed.
|
||||
return {};
|
||||
|
@ -311,10 +336,12 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
|||
return Some(fbo);
|
||||
}
|
||||
|
||||
RefPtr<gl::DepthAndStencilBuffer> SurfacePoolCA::LockedPool::GetDepthBufferForSharing(
|
||||
GLContext* aGL, const IntSize& aSize) {
|
||||
RefPtr<gl::DepthAndStencilBuffer>
|
||||
SurfacePoolCA::LockedPool::GetDepthBufferForSharing(GLContext* aGL,
|
||||
const IntSize& aSize) {
|
||||
// Clean out entries for which the weak pointer has become null.
|
||||
mDepthBuffers.RemoveElementsBy([&](const DepthBufferEntry& entry) { return !entry.mBuffer; });
|
||||
mDepthBuffers.RemoveElementsBy(
|
||||
[&](const DepthBufferEntry& entry) { return !entry.mBuffer; });
|
||||
|
||||
for (const auto& entry : mDepthBuffers) {
|
||||
if (entry.mGLContext == aGL && entry.mSize == aSize) {
|
||||
|
@ -324,22 +351,29 @@ RefPtr<gl::DepthAndStencilBuffer> SurfacePoolCA::LockedPool::GetDepthBufferForSh
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
UniquePtr<gl::MozFramebuffer> SurfacePoolCA::LockedPool::CreateFramebufferForTexture(
|
||||
GLContext* aGL, const IntSize& aSize, GLuint aTexture, bool aNeedsDepthBuffer) {
|
||||
UniquePtr<gl::MozFramebuffer>
|
||||
SurfacePoolCA::LockedPool::CreateFramebufferForTexture(GLContext* aGL,
|
||||
const IntSize& aSize,
|
||||
GLuint aTexture,
|
||||
bool aNeedsDepthBuffer) {
|
||||
if (aNeedsDepthBuffer) {
|
||||
// Try to find an existing depth buffer of aSize in aGL and create a framebuffer that shares it.
|
||||
// Try to find an existing depth buffer of aSize in aGL and create a
|
||||
// framebuffer that shares it.
|
||||
if (auto buffer = GetDepthBufferForSharing(aGL, aSize)) {
|
||||
return gl::MozFramebuffer::CreateForBackingWithSharedDepthAndStencil(
|
||||
aSize, 0, LOCAL_GL_TEXTURE_RECTANGLE_ARB, aTexture, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// No depth buffer needed or we didn't find one. Create a framebuffer with a new depth buffer and
|
||||
// store a weak pointer to the new depth buffer in mDepthBuffers.
|
||||
// No depth buffer needed or we didn't find one. Create a framebuffer with a
|
||||
// new depth buffer and store a weak pointer to the new depth buffer in
|
||||
// mDepthBuffers.
|
||||
UniquePtr<gl::MozFramebuffer> fb = gl::MozFramebuffer::CreateForBacking(
|
||||
aGL, aSize, 0, aNeedsDepthBuffer, LOCAL_GL_TEXTURE_RECTANGLE_ARB, aTexture);
|
||||
aGL, aSize, 0, aNeedsDepthBuffer, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
aTexture);
|
||||
if (fb && fb->GetDepthAndStencilBuffer()) {
|
||||
mDepthBuffers.AppendElement(DepthBufferEntry{aGL, aSize, fb->GetDepthAndStencilBuffer().get()});
|
||||
mDepthBuffers.AppendElement(
|
||||
DepthBufferEntry{aGL, aSize, fb->GetDepthAndStencilBuffer().get()});
|
||||
}
|
||||
|
||||
return fb;
|
||||
|
@ -347,8 +381,9 @@ UniquePtr<gl::MozFramebuffer> SurfacePoolCA::LockedPool::CreateFramebufferForTex
|
|||
|
||||
// SurfacePoolHandleCA
|
||||
|
||||
SurfacePoolHandleCA::SurfacePoolHandleCA(RefPtr<SurfacePoolCAWrapperForGL>&& aPoolWrapper,
|
||||
uint64_t aCurrentCollectionGeneration)
|
||||
SurfacePoolHandleCA::SurfacePoolHandleCA(
|
||||
RefPtr<SurfacePoolCAWrapperForGL>&& aPoolWrapper,
|
||||
uint64_t aCurrentCollectionGeneration)
|
||||
: mPoolWrapper(aPoolWrapper),
|
||||
mPreviousFrameCollectionGeneration(
|
||||
"SurfacePoolHandleCA::mPreviousFrameCollectionGeneration") {
|
||||
|
@ -363,20 +398,24 @@ void SurfacePoolHandleCA::OnBeginFrame() {
|
|||
*generation = mPoolWrapper->mPool->CollectPendingSurfaces(*generation);
|
||||
}
|
||||
|
||||
void SurfacePoolHandleCA::OnEndFrame() { mPoolWrapper->mPool->EnforcePoolSizeLimit(); }
|
||||
void SurfacePoolHandleCA::OnEndFrame() {
|
||||
mPoolWrapper->mPool->EnforcePoolSizeLimit();
|
||||
}
|
||||
|
||||
CFTypeRefPtr<IOSurfaceRef> SurfacePoolHandleCA::ObtainSurfaceFromPool(const IntSize& aSize) {
|
||||
CFTypeRefPtr<IOSurfaceRef> SurfacePoolHandleCA::ObtainSurfaceFromPool(
|
||||
const IntSize& aSize) {
|
||||
return mPoolWrapper->mPool->ObtainSurfaceFromPool(aSize, mPoolWrapper->mGL);
|
||||
}
|
||||
|
||||
void SurfacePoolHandleCA::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> aSurface) {
|
||||
void SurfacePoolHandleCA::ReturnSurfaceToPool(
|
||||
CFTypeRefPtr<IOSurfaceRef> aSurface) {
|
||||
mPoolWrapper->mPool->ReturnSurfaceToPool(aSurface);
|
||||
}
|
||||
|
||||
Maybe<GLuint> SurfacePoolHandleCA::GetFramebufferForSurface(CFTypeRefPtr<IOSurfaceRef> aSurface,
|
||||
bool aNeedsDepthBuffer) {
|
||||
return mPoolWrapper->mPool->GetFramebufferForSurface(aSurface, mPoolWrapper->mGL,
|
||||
aNeedsDepthBuffer);
|
||||
Maybe<GLuint> SurfacePoolHandleCA::GetFramebufferForSurface(
|
||||
CFTypeRefPtr<IOSurfaceRef> aSurface, bool aNeedsDepthBuffer) {
|
||||
return mPoolWrapper->mPool->GetFramebufferForSurface(
|
||||
aSurface, mPoolWrapper->mGL, aNeedsDepthBuffer);
|
||||
}
|
||||
|
||||
// SurfacePoolCA
|
||||
|
@ -405,8 +444,8 @@ void SurfacePoolCA::DestroyGLResourcesForContext(GLContext* aGL) {
|
|||
pool->DestroyGLResourcesForContext(aGL);
|
||||
}
|
||||
|
||||
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::ObtainSurfaceFromPool(const IntSize& aSize,
|
||||
GLContext* aGL) {
|
||||
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::ObtainSurfaceFromPool(
|
||||
const IntSize& aSize, GLContext* aGL) {
|
||||
auto pool = mPool.Lock();
|
||||
return pool->ObtainSurfaceFromPool(aSize, aGL);
|
||||
}
|
||||
|
@ -425,13 +464,15 @@ void SurfacePoolCA::EnforcePoolSizeLimit() {
|
|||
pool->EnforcePoolSizeLimit();
|
||||
}
|
||||
|
||||
Maybe<GLuint> SurfacePoolCA::GetFramebufferForSurface(CFTypeRefPtr<IOSurfaceRef> aSurface,
|
||||
GLContext* aGL, bool aNeedsDepthBuffer) {
|
||||
Maybe<GLuint> SurfacePoolCA::GetFramebufferForSurface(
|
||||
CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL,
|
||||
bool aNeedsDepthBuffer) {
|
||||
auto pool = mPool.Lock();
|
||||
return pool->GetFramebufferForSurface(aSurface, aGL, aNeedsDepthBuffer);
|
||||
}
|
||||
|
||||
void SurfacePoolCA::OnWrapperDestroyed(gl::GLContext* aGL, SurfacePoolCAWrapperForGL* aWrapper) {
|
||||
void SurfacePoolCA::OnWrapperDestroyed(gl::GLContext* aGL,
|
||||
SurfacePoolCAWrapperForGL* aWrapper) {
|
||||
auto pool = mPool.Lock();
|
||||
return pool->OnWrapperDestroyed(aGL, aWrapper);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,14 @@
|
|||
|
||||
namespace mozilla::gfx {
|
||||
|
||||
static size_t PutBytesNull(void* info, const void* buffer, size_t count) { return count; }
|
||||
static size_t PutBytesNull(void* info, const void* buffer, size_t count) {
|
||||
return count;
|
||||
}
|
||||
|
||||
PrintTargetCG::PrintTargetCG(CGContextRef aPrintToStreamContext, PMPrintSession aPrintSession,
|
||||
PMPageFormat aPageFormat, PMPrintSettings aPrintSettings,
|
||||
PrintTargetCG::PrintTargetCG(CGContextRef aPrintToStreamContext,
|
||||
PMPrintSession aPrintSession,
|
||||
PMPageFormat aPageFormat,
|
||||
PMPrintSettings aPrintSettings,
|
||||
const IntSize& aSize)
|
||||
: PrintTarget(/* aCairoSurface */ nullptr, aSize),
|
||||
mPrintToStreamContext(aPrintToStreamContext),
|
||||
|
@ -53,14 +57,16 @@ PrintTargetCG::~PrintTargetCG() {
|
|||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
static size_t WriteStreamBytes(void* aInfo, const void* aBuffer, size_t aCount) {
|
||||
static size_t WriteStreamBytes(void* aInfo, const void* aBuffer,
|
||||
size_t aCount) {
|
||||
auto* stream = static_cast<nsIOutputStream*>(aInfo);
|
||||
auto* data = static_cast<const char*>(aBuffer);
|
||||
size_t remaining = aCount;
|
||||
do {
|
||||
uint32_t wrote = 0;
|
||||
// Handle potential narrowing from size_t to uint32_t.
|
||||
uint32_t toWrite = uint32_t(std::min(remaining, size_t(std::numeric_limits<uint32_t>::max())));
|
||||
uint32_t toWrite = uint32_t(
|
||||
std::min(remaining, size_t(std::numeric_limits<uint32_t>::max())));
|
||||
if (NS_WARN_IF(NS_FAILED(stream->Write(data, toWrite, &wrote)))) {
|
||||
break;
|
||||
}
|
||||
|
@ -87,21 +93,25 @@ static CGContextRef CreatePrintToStreamContext(nsIOutputStream* aOutputStream,
|
|||
CGDataConsumerRef consumer = CGDataConsumerCreate(aOutputStream, &callbacks);
|
||||
|
||||
// This metadata is added by the CorePrinting APIs in the non-stream case.
|
||||
NSString* bundleName =
|
||||
[NSBundle.mainBundle.localizedInfoDictionary objectForKey:(NSString*)kCFBundleNameKey];
|
||||
NSString* bundleName = [NSBundle.mainBundle.localizedInfoDictionary
|
||||
objectForKey:(NSString*)kCFBundleNameKey];
|
||||
CFMutableDictionaryRef auxiliaryInfo = CFDictionaryCreateMutable(
|
||||
kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFDictionaryAddValue(auxiliaryInfo, kCGPDFContextCreator, (__bridge CFStringRef)bundleName);
|
||||
kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
CFDictionaryAddValue(auxiliaryInfo, kCGPDFContextCreator,
|
||||
(__bridge CFStringRef)bundleName);
|
||||
|
||||
CGContextRef pdfContext = CGPDFContextCreate(consumer, &pageBox, auxiliaryInfo);
|
||||
CGContextRef pdfContext =
|
||||
CGPDFContextCreate(consumer, &pageBox, auxiliaryInfo);
|
||||
CGDataConsumerRelease(consumer);
|
||||
CFRelease(auxiliaryInfo);
|
||||
return pdfContext;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<PrintTargetCG> PrintTargetCG::CreateOrNull(
|
||||
nsIOutputStream* aOutputStream, PMPrintSession aPrintSession, PMPageFormat aPageFormat,
|
||||
PMPrintSettings aPrintSettings, const IntSize& aSize) {
|
||||
nsIOutputStream* aOutputStream, PMPrintSession aPrintSession,
|
||||
PMPageFormat aPageFormat, PMPrintSettings aPrintSettings,
|
||||
const IntSize& aSize) {
|
||||
if (!Factory::CheckSurfaceSize(aSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -114,8 +124,8 @@ static CGContextRef CreatePrintToStreamContext(nsIOutputStream* aOutputStream,
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<PrintTargetCG> target =
|
||||
new PrintTargetCG(printToStreamContext, aPrintSession, aPageFormat, aPrintSettings, aSize);
|
||||
RefPtr<PrintTargetCG> target = new PrintTargetCG(
|
||||
printToStreamContext, aPrintSession, aPageFormat, aPrintSettings, aSize);
|
||||
|
||||
return target.forget();
|
||||
}
|
||||
|
@ -129,8 +139,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
|
|||
CGContextRef pdfContext = CGPDFContextCreate(consumer, nullptr, nullptr);
|
||||
CGDataConsumerRelease(consumer);
|
||||
|
||||
cairo_surface_t* similar =
|
||||
cairo_quartz_surface_create_for_cg_context(pdfContext, size.width, size.height);
|
||||
cairo_surface_t* similar = cairo_quartz_surface_create_for_cg_context(
|
||||
pdfContext, size.width, size.height);
|
||||
|
||||
CGContextRelease(pdfContext);
|
||||
|
||||
|
@ -138,7 +148,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForCairoSurface(similar, size);
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateDrawTargetForCairoSurface(similar, size);
|
||||
|
||||
// The DT addrefs the surface, so we need drop our own reference to it:
|
||||
cairo_surface_destroy(similar);
|
||||
|
@ -152,7 +163,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
|
|||
return do_AddRef(mRefDT);
|
||||
}
|
||||
|
||||
nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName,
|
||||
nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage, int32_t aEndPage) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
|
@ -182,7 +194,8 @@ nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle, const nsAString&
|
|||
status = ::PMSetLastPage(mPrintSettings, aEndPage, false);
|
||||
NS_ASSERTION(status == noErr, "PMSetLastPage failed");
|
||||
|
||||
status = ::PMSessionBeginCGDocumentNoDialog(mPrintSession, mPrintSettings, mPageFormat);
|
||||
status = ::PMSessionBeginCGDocumentNoDialog(mPrintSession, mPrintSettings,
|
||||
mPageFormat);
|
||||
|
||||
return status == noErr ? NS_OK : NS_ERROR_ABORT;
|
||||
|
||||
|
@ -224,11 +237,13 @@ nsresult PrintTargetCG::BeginPage(const IntSize& aSizeInPoints) {
|
|||
|
||||
if (StaticPrefs::layout_css_page_orientation_enabled()) {
|
||||
::PMOrientation pageOrientation =
|
||||
aSizeInPoints.width < aSizeInPoints.height ? kPMPortrait : kPMLandscape;
|
||||
aSizeInPoints.width < aSizeInPoints.height ? kPMPortrait
|
||||
: kPMLandscape;
|
||||
::PMSetOrientation(mPageFormat, pageOrientation, kPMUnlocked);
|
||||
// We don't need to reset the orientation, since we set it for every page.
|
||||
}
|
||||
OSStatus status = ::PMSessionBeginPageNoDialog(mPrintSession, mPageFormat, nullptr);
|
||||
OSStatus status =
|
||||
::PMSessionBeginPageNoDialog(mPrintSession, mPageFormat, nullptr);
|
||||
if (status != noErr) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
@ -257,7 +272,8 @@ nsresult PrintTargetCG::BeginPage(const IntSize& aSizeInPoints) {
|
|||
CGContextTranslateCTM(context, 0, height);
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
|
||||
cairo_surface_t* surface = cairo_quartz_surface_create_for_cg_context(context, width, height);
|
||||
cairo_surface_t* surface =
|
||||
cairo_quartz_surface_create_for_cg_context(context, width, height);
|
||||
|
||||
if (cairo_surface_status(surface)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -63,8 +63,9 @@ static void GetStringForNSString(const NSString* aSrc, nsAString& aDest) {
|
|||
}
|
||||
|
||||
static NSString* GetNSStringForString(const nsAString& aSrc) {
|
||||
return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading())
|
||||
length:aSrc.Length()];
|
||||
return [NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading())
|
||||
length:aSrc.Length()];
|
||||
}
|
||||
|
||||
#define LOG_FONTLIST(args) \
|
||||
|
@ -77,7 +78,8 @@ static NSString* GetNSStringForString(const nsAString& aSrc) {
|
|||
class gfxMacFontFamily final : public CTFontFamily {
|
||||
public:
|
||||
gfxMacFontFamily(const nsACString& aName, NSFont* aSystemFont)
|
||||
: CTFontFamily(aName, FontVisibility::Unknown), mForSystemFont(aSystemFont) {
|
||||
: CTFontFamily(aName, FontVisibility::Unknown),
|
||||
mForSystemFont(aSystemFont) {
|
||||
// I don't think the system font instance is at much risk of being deleted,
|
||||
// but to be on the safe side let's retain a reference until we're finished
|
||||
// using it for lazy initialization.
|
||||
|
@ -88,9 +90,9 @@ class gfxMacFontFamily final : public CTFontFamily {
|
|||
MOZ_REQUIRES(mLock) override;
|
||||
|
||||
protected:
|
||||
// If non-null, this is a family representing the system UI font, and should use
|
||||
// the given NSFont as the basis for initialization as the normal font-manager APIs
|
||||
// based on family name won't handle it.
|
||||
// If non-null, this is a family representing the system UI font, and should
|
||||
// use the given NSFont as the basis for initialization as the normal
|
||||
// font-manager APIs based on family name won't handle it.
|
||||
NSFont* mForSystemFont = nullptr;
|
||||
};
|
||||
|
||||
|
@ -99,7 +101,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
|||
return;
|
||||
}
|
||||
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxMacFontFamily::FindStyleVariations", LAYOUT, mName);
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxMacFontFamily::FindStyleVariations",
|
||||
LAYOUT, mName);
|
||||
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
|
@ -113,12 +116,14 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
|||
nsCocoaUtils::GetStringForNSString(psNameNS, nameUTF16);
|
||||
CopyUTF16toUTF8(nameUTF16, psName);
|
||||
|
||||
auto* fe = new CTFontEntry(psName, WeightRange(FontWeight::NORMAL), true, 0.0);
|
||||
auto* fe =
|
||||
new CTFontEntry(psName, WeightRange(FontWeight::NORMAL), true, 0.0);
|
||||
|
||||
// Set the appropriate style, assuming it may not have a variation range.
|
||||
fe->mStyleRange = SlantStyleRange(
|
||||
([[aNSFont fontDescriptor] symbolicTraits] & NSFontItalicTrait) ? FontSlantStyle::ITALIC
|
||||
: FontSlantStyle::NORMAL);
|
||||
([[aNSFont fontDescriptor] symbolicTraits] & NSFontItalicTrait)
|
||||
? FontSlantStyle::ITALIC
|
||||
: FontSlantStyle::NORMAL);
|
||||
|
||||
// Set up weight (and width, if present) ranges.
|
||||
fe->SetupVariationRanges();
|
||||
|
@ -128,7 +133,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
|||
addToFamily(mForSystemFont);
|
||||
|
||||
// See if there is a corresponding italic face, and add it to the family.
|
||||
NSFont* italicFont = [sFontManager convertFont:mForSystemFont toHaveTrait:NSItalicFontMask];
|
||||
NSFont* italicFont = [sFontManager convertFont:mForSystemFont
|
||||
toHaveTrait:NSItalicFontMask];
|
||||
if (italicFont != mForSystemFont) {
|
||||
addToFamily(italicFont);
|
||||
}
|
||||
|
@ -147,7 +153,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
|||
|
||||
class gfxSingleFaceMacFontFamily final : public gfxFontFamily {
|
||||
public:
|
||||
gfxSingleFaceMacFontFamily(const nsACString& aName, FontVisibility aVisibility)
|
||||
gfxSingleFaceMacFontFamily(const nsACString& aName,
|
||||
FontVisibility aVisibility)
|
||||
: gfxFontFamily(aName, aVisibility) {
|
||||
mFaceNamesInitialized = true; // omit from face name lists
|
||||
}
|
||||
|
@ -175,8 +182,9 @@ void gfxSingleFaceMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
|
|||
}
|
||||
|
||||
gfxFontEntry* fe = mAvailableFonts[0];
|
||||
NSFont* font = [NSFont fontWithName:GetNSStringForString(NS_ConvertUTF8toUTF16(fe->Name()))
|
||||
size:0.0];
|
||||
NSFont* font = [NSFont
|
||||
fontWithName:GetNSStringForString(NS_ConvertUTF8toUTF16(fe->Name()))
|
||||
size:0.0];
|
||||
if (font) {
|
||||
NSString* localized = [font displayName];
|
||||
if (localized) {
|
||||
|
@ -191,7 +199,8 @@ void gfxSingleFaceMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
|
|||
aLocalizedName = mName;
|
||||
}
|
||||
|
||||
void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList* aPlatformFontList) {
|
||||
void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(
|
||||
gfxPlatformFontList* aPlatformFontList) {
|
||||
AutoWriteLock lock(mLock);
|
||||
if (mOtherFamilyNamesInitialized) {
|
||||
return;
|
||||
|
@ -209,7 +218,8 @@ void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList* aPlat
|
|||
return;
|
||||
}
|
||||
|
||||
mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable, true);
|
||||
mHasOtherFamilyNames =
|
||||
ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable, true);
|
||||
|
||||
mOtherFamilyNamesInitialized = true;
|
||||
}
|
||||
|
@ -229,7 +239,8 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() : CoreTextFontList() {
|
|||
gfxFontUtils::GetPrefsFontList("font.single-face-list", mSingleFaceFonts);
|
||||
}
|
||||
|
||||
FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily(const nsACString& aName) const {
|
||||
FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily(
|
||||
const nsACString& aName) const {
|
||||
if (aName[0] == '.' || aName.LowerCaseEqualsLiteral("lastresort")) {
|
||||
return FontVisibility::Hidden;
|
||||
}
|
||||
|
@ -244,7 +255,8 @@ FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily(const nsACString&
|
|||
return FontVisibility::User;
|
||||
}
|
||||
|
||||
bool gfxMacPlatformFontList::DeprecatedFamilyIsAvailable(const nsACString& aName) {
|
||||
bool gfxMacPlatformFontList::DeprecatedFamilyIsAvailable(
|
||||
const nsACString& aName) {
|
||||
NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(aName));
|
||||
return [[sFontManager availableMembersOfFontFamily:family] count] > 0;
|
||||
}
|
||||
|
@ -364,7 +376,8 @@ void gfxMacPlatformFontList::InitSingleFaceList() {
|
|||
|
||||
// We found the correct face, so create the single-face family record.
|
||||
GenerateFontListKey(aliasName, key);
|
||||
LOG_FONTLIST(("(fontlist-singleface) family name: %s, key: %s\n", aliasName.get(), key.get()));
|
||||
LOG_FONTLIST(("(fontlist-singleface) family name: %s, key: %s\n",
|
||||
aliasName.get(), key.get()));
|
||||
|
||||
// add only if doesn't exist already
|
||||
if (!mFontFamilies.GetWeak(key)) {
|
||||
|
@ -372,13 +385,14 @@ void gfxMacPlatformFontList::InitSingleFaceList() {
|
|||
new gfxSingleFaceMacFontFamily(aliasName, family->Visibility());
|
||||
// We need a separate font entry, because its family name will
|
||||
// differ from the one we found in the main list.
|
||||
CTFontEntry* fontEntry = new CTFontEntry(fe->Name(), fe->Weight(), true,
|
||||
static_cast<const CTFontEntry*>(fe)->mSizeHint);
|
||||
CTFontEntry* fontEntry =
|
||||
new CTFontEntry(fe->Name(), fe->Weight(), true,
|
||||
static_cast<const CTFontEntry*>(fe)->mSizeHint);
|
||||
familyEntry->AddFontEntry(fontEntry);
|
||||
familyEntry->SetHasStyles(true);
|
||||
mFontFamilies.InsertOrUpdate(key, std::move(familyEntry));
|
||||
LOG_FONTLIST(
|
||||
("(fontlist-singleface) added new family: %s, key: %s\n", aliasName.get(), key.get()));
|
||||
LOG_FONTLIST(("(fontlist-singleface) added new family: %s, key: %s\n",
|
||||
aliasName.get(), key.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -404,12 +418,14 @@ static NSString* GetRealFamilyName(NSFont* aFont) {
|
|||
// Eventually we should move to using CTFontUIFontType constants to identify
|
||||
// system fonts, and eliminate the need to instantiate them (indirectly) from
|
||||
// their postscript names.
|
||||
AutoCFRelease<CGFontRef> cgFont = CGFontCreateWithFontName(CFStringRef(psName));
|
||||
AutoCFRelease<CGFontRef> cgFont =
|
||||
CGFontCreateWithFontName(CFStringRef(psName));
|
||||
if (!cgFont) {
|
||||
return [aFont familyName];
|
||||
}
|
||||
|
||||
AutoCFRelease<CTFontRef> ctFont = CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr);
|
||||
AutoCFRelease<CTFontRef> ctFont =
|
||||
CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr);
|
||||
if (!ctFont) {
|
||||
return [aFont familyName];
|
||||
}
|
||||
|
@ -441,7 +457,8 @@ void gfxMacPlatformFontList::InitSystemFontNames() {
|
|||
// the hidden system fonts may be excluded from the font list altogether.
|
||||
if (nsCocoaFeatures::OnCatalinaOrLater()) {
|
||||
// This family will be populated based on the given NSFont.
|
||||
RefPtr<gfxFontFamily> fam = new gfxMacFontFamily(mSystemTextFontFamilyName, sys);
|
||||
RefPtr<gfxFontFamily> fam =
|
||||
new gfxMacFontFamily(mSystemTextFontFamilyName, sys);
|
||||
if (fam) {
|
||||
nsAutoCString key;
|
||||
GenerateFontListKey(mSystemTextFontFamilyName, key);
|
||||
|
@ -465,20 +482,23 @@ void gfxMacPlatformFontList::InitSystemFontNames() {
|
|||
// different system font API's always map to the same family under OSX, so
|
||||
// just assume that and emit a warning if that ever changes
|
||||
NSString* sysFamily = GetRealFamilyName([NSFont systemFontOfSize:0.0]);
|
||||
if ([sysFamily compare:GetRealFamilyName([NSFont boldSystemFontOfSize:0.0])] != NSOrderedSame ||
|
||||
[sysFamily compare:GetRealFamilyName([NSFont controlContentFontOfSize:0.0])] !=
|
||||
if ([sysFamily compare:GetRealFamilyName([NSFont
|
||||
boldSystemFontOfSize:0.0])] != NSOrderedSame ||
|
||||
[sysFamily compare:GetRealFamilyName([NSFont
|
||||
controlContentFontOfSize:0.0])] != NSOrderedSame ||
|
||||
[sysFamily compare:GetRealFamilyName([NSFont menuBarFontOfSize:0.0])] !=
|
||||
NSOrderedSame ||
|
||||
[sysFamily compare:GetRealFamilyName([NSFont menuBarFontOfSize:0.0])] != NSOrderedSame ||
|
||||
[sysFamily compare:GetRealFamilyName([NSFont toolTipsFontOfSize:0.0])] != NSOrderedSame) {
|
||||
[sysFamily compare:GetRealFamilyName([NSFont toolTipsFontOfSize:0.0])] !=
|
||||
NSOrderedSame) {
|
||||
NS_WARNING("system font types map to different font families"
|
||||
" -- please log a bug!!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(nsPresContext* aPresContext,
|
||||
const gfxFontStyle* aStyle,
|
||||
nsAtom* aLanguage) {
|
||||
FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(
|
||||
nsPresContext* aPresContext, const gfxFontStyle* aStyle,
|
||||
nsAtom* aLanguage) {
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
|
||||
|
@ -538,11 +558,14 @@ void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
|
|||
}
|
||||
|
||||
NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
|
||||
aFontStyle.style = (traits & NSFontItalicTrait) ? FontSlantStyle::ITALIC : FontSlantStyle::NORMAL;
|
||||
aFontStyle.weight = (traits & NSFontBoldTrait) ? FontWeight::BOLD : FontWeight::NORMAL;
|
||||
aFontStyle.stretch = (traits & NSFontExpandedTrait) ? FontStretch::EXPANDED
|
||||
: (traits & NSFontCondensedTrait) ? FontStretch::CONDENSED
|
||||
: FontStretch::NORMAL;
|
||||
aFontStyle.style = (traits & NSFontItalicTrait) ? FontSlantStyle::ITALIC
|
||||
: FontSlantStyle::NORMAL;
|
||||
aFontStyle.weight =
|
||||
(traits & NSFontBoldTrait) ? FontWeight::BOLD : FontWeight::NORMAL;
|
||||
aFontStyle.stretch = (traits & NSFontExpandedTrait) ? FontStretch::EXPANDED
|
||||
: (traits & NSFontCondensedTrait)
|
||||
? FontStretch::CONDENSED
|
||||
: FontStretch::NORMAL;
|
||||
aFontStyle.size = [font pointSize];
|
||||
aFontStyle.systemFont = true;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ static io_connect_t sDataPort = IO_OBJECT_NULL;
|
|||
static uint64_t sLastMean = -1;
|
||||
static float LMUvalueToLux(uint64_t aValue) {
|
||||
// Conversion formula from regression. See Bug 793728.
|
||||
// -3*(10^-27)*x^4 + 2.6*(10^-19)*x^3 + -3.4*(10^-12)*x^2 + 3.9*(10^-5)*x - 0.19
|
||||
// -3*(10^-27)*x^4 + 2.6*(10^-19)*x^3 + -3.4*(10^-12)*x^2 + 3.9*(10^-5)*x -
|
||||
// 0.19
|
||||
long double powerC4 = 1 / pow((long double)10, 27);
|
||||
long double powerC3 = 1 / pow((long double)10, 19);
|
||||
long double powerC2 = 1 / pow((long double)10, 12);
|
||||
|
@ -54,7 +55,8 @@ void UpdateHandler(nsITimer* aTimer, void* aClosure) {
|
|||
uint32_t outputs = 2;
|
||||
uint64_t lightLMU[outputs];
|
||||
|
||||
kr = IOConnectCallMethod(sDataPort, 0, nil, 0, nil, 0, lightLMU, &outputs, nil, 0);
|
||||
kr = IOConnectCallMethod(sDataPort, 0, nil, 0, nil, 0, lightLMU, &outputs,
|
||||
nil, 0);
|
||||
if (kr == KERN_SUCCESS) {
|
||||
uint64_t mean = (lightLMU[0] + lightLMU[1]) / 2;
|
||||
if (mean == sLastMean) {
|
||||
|
@ -84,8 +86,8 @@ void EnableSensorNotifications(SensorType aSensor) {
|
|||
}
|
||||
} else if (aSensor == SENSOR_LIGHT) {
|
||||
io_service_t serviceObject;
|
||||
serviceObject =
|
||||
IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
|
||||
serviceObject = IOServiceGetMatchingService(
|
||||
kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
|
||||
if (!serviceObject) {
|
||||
return;
|
||||
}
|
||||
|
@ -104,14 +106,15 @@ void EnableSensorNotifications(SensorType aSensor) {
|
|||
if (!sUpdateTimer) {
|
||||
CallCreateInstance("@mozilla.org/timer;1", &sUpdateTimer);
|
||||
if (sUpdateTimer) {
|
||||
sUpdateTimer->InitWithNamedFuncCallback(UpdateHandler, nullptr, DEFAULT_SENSOR_POLL,
|
||||
nsITimer::TYPE_REPEATING_SLACK,
|
||||
"hal_impl::UpdateHandler");
|
||||
sUpdateTimer->InitWithNamedFuncCallback(
|
||||
UpdateHandler, nullptr, DEFAULT_SENSOR_POLL,
|
||||
nsITimer::TYPE_REPEATING_SLACK, "hal_impl::UpdateHandler");
|
||||
}
|
||||
}
|
||||
}
|
||||
void DisableSensorNotifications(SensorType aSensor) {
|
||||
if (!sActiveSensors[aSensor] || (aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) {
|
||||
if (!sActiveSensors[aSensor] ||
|
||||
(aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,20 +80,21 @@ typedef struct sensorSpec {
|
|||
//
|
||||
// These values came from SeisMaCalibrate calibration reports. In general I've
|
||||
// found the following:
|
||||
// - All Intel-based SMSs have 250 counts per g, centered on 0, but the signs
|
||||
// are different (and in one case two axes are swapped)
|
||||
// - All Intel-based SMSs have 250 counts per g, centered on 0, but the
|
||||
// signs are different (and in one case two axes are swapped)
|
||||
// - PowerBooks and iBooks all have sensors centered on 0, and reading
|
||||
// 50-53 steps per gravity (but with differing polarities!)
|
||||
// - PowerBooks and iBooks of the same model all have the same axis polarities
|
||||
// - PowerBooks and iBooks of the same model all have the same axis
|
||||
// polarities
|
||||
// - PowerBook and iBook access methods are model- and OS version-specific
|
||||
//
|
||||
// So, the sequence of tests is:
|
||||
// - Try model-specific access methods. Note that the test is for a match to the
|
||||
// beginning of the model name, e.g. the record with model name "MacBook"
|
||||
// matches computer models "MacBookPro1,2" and "MacBook1,1" (and ""
|
||||
// - Try model-specific access methods. Note that the test is for a match
|
||||
// to the beginning of the model name, e.g. the record with model name
|
||||
// "MacBook" matches computer models "MacBookPro1,2" and "MacBook1,1" (and ""
|
||||
// matches any model).
|
||||
// - If no model-specific record's access fails, then try each model-independent
|
||||
// access method in order, stopping when one works.
|
||||
// - If no model-specific record's access fails, then try each
|
||||
// model-independent access method in order, stopping when one works.
|
||||
static const sensorSpec sensors[] = {
|
||||
// ****** Model-dependent methods ******
|
||||
// The PowerBook5,6 is one of the G4 models that seems to lose
|
||||
|
@ -142,7 +143,8 @@ static const sensorSpec sensors[] = {
|
|||
5,
|
||||
40,
|
||||
{{1, 0, 2, 0, 251}, {1, 2, 2, 0, -251}, {1, 4, 2, 0, -251}}},
|
||||
// MacBook Pro Core 2 Duo 15" AND 17" with LED backlight, introduced June '07.
|
||||
// MacBook Pro Core 2 Duo 15" AND 17" with LED backlight, introduced June
|
||||
// '07.
|
||||
// NOTE! The 17" machines have the signs of their X and Y axes reversed
|
||||
// from this calibration, but there's no clear way to discriminate between
|
||||
// the two machines.
|
||||
|
@ -169,7 +171,8 @@ static const sensorSpec sensors[] = {
|
|||
5,
|
||||
40,
|
||||
{{1, 0, 2, 0, -251}, {1, 2, 2, 0, -251}, {1, 4, 2, 0, 251}}},
|
||||
// This is speculative, based on a single user's report. Looks like the X and Y axes
|
||||
// This is speculative, based on a single user's report. Looks like the X
|
||||
// and Y axes
|
||||
// are swapped. This is true for no other known Appple laptop.
|
||||
{"MacBookPro5,3",
|
||||
"SMCMotionSensor",
|
||||
|
@ -185,10 +188,18 @@ static const sensorSpec sensors[] = {
|
|||
// ****** Model-independent methods ******
|
||||
// Seen once with PowerBook6,8 under system 10.3.9; I suspect
|
||||
// other G4-based 10.3.* systems might use this
|
||||
{"", "IOI2CMotionSensor", 24, 60, {{1, 0, 1, 0, 51.5}, {1, 1, 1, 0, 51.5}, {1, 2, 1, 0, 51.5}}},
|
||||
{"",
|
||||
"IOI2CMotionSensor",
|
||||
24,
|
||||
60,
|
||||
{{1, 0, 1, 0, 51.5}, {1, 1, 1, 0, 51.5}, {1, 2, 1, 0, 51.5}}},
|
||||
// PowerBook5,6 , PowerBook5,7 , PowerBook6,7 , PowerBook6,8
|
||||
// under OS X 10.4.*
|
||||
{"", "IOI2CMotionSensor", 21, 60, {{1, 0, 1, 0, 51.5}, {1, 1, 1, 0, 51.5}, {1, 2, 1, 0, 51.5}}},
|
||||
{"",
|
||||
"IOI2CMotionSensor",
|
||||
21,
|
||||
60,
|
||||
{{1, 0, 1, 0, 51.5}, {1, 1, 1, 0, 51.5}, {1, 2, 1, 0, 51.5}}},
|
||||
// PowerBook5,8 , PowerBook5,9 under OS X 10.4.*
|
||||
{"",
|
||||
"PMUMotionSensor",
|
||||
|
@ -200,9 +211,11 @@ static const sensorSpec sensors[] = {
|
|||
{1, 0, 1, 0, -51.5},
|
||||
{1, 1, 1, -6, -51.5},
|
||||
{1, 2, 1, 0, -51.5}}},
|
||||
// All MacBook, MacBookPro models. Hardware (at least on early MacBookPro 15")
|
||||
// All MacBook, MacBookPro models. Hardware (at least on early MacBookPro
|
||||
// 15")
|
||||
// is Kionix KXM52-1050 three-axis accelerometer chip. Data is at
|
||||
// http://kionix.com/Product-Index/product-index.htm. Specific MB and MBP models
|
||||
// http://kionix.com/Product-Index/product-index.htm. Specific MB and MBP
|
||||
// models
|
||||
// that use this are:
|
||||
// MacBook1,1
|
||||
// MacBook2,1
|
||||
|
@ -215,13 +228,18 @@ static const sensorSpec sensors[] = {
|
|||
// MacBookPro1,2
|
||||
// MacBookPro4,1
|
||||
// MacBookPro5,5
|
||||
{"", "SMCMotionSensor", 5, 40, {{1, 0, 2, 0, 251}, {1, 2, 2, 0, 251}, {1, 4, 2, 0, 251}}}};
|
||||
{"",
|
||||
"SMCMotionSensor",
|
||||
5,
|
||||
40,
|
||||
{{1, 0, 2, 0, 251}, {1, 2, 2, 0, 251}, {1, 4, 2, 0, 251}}}};
|
||||
|
||||
#define SENSOR_COUNT (sizeof(sensors) / sizeof(sensorSpec))
|
||||
|
||||
#pragma mark Internal prototypes
|
||||
|
||||
static int getData(sms_acceleration* accel, int calibrated, id logObject, SEL logSelector);
|
||||
static int getData(sms_acceleration* accel, int calibrated, id logObject,
|
||||
SEL logSelector);
|
||||
static float getAxis(int which, int calibrated);
|
||||
static int signExtend(int value, int size);
|
||||
static NSString* getModelName(void);
|
||||
|
@ -259,7 +277,8 @@ static float onegs[3]; // X, Y and Z one-g calibration values
|
|||
// Name of configuration for given axis' zero (axis specified by integer)
|
||||
#define ZERO_NAME(a) [NSString stringWithFormat:@"%@-Axis-Zero", INT_TO_AXIS(a)]
|
||||
// Name of configuration for given axis' oneg (axis specified by integer)
|
||||
#define ONEG_NAME(a) [NSString stringWithFormat:@"%@-Axis-One-g", INT_TO_AXIS(a)]
|
||||
#define ONEG_NAME(a) \
|
||||
[NSString stringWithFormat:@"%@-Axis-One-g", INT_TO_AXIS(a)]
|
||||
// Name of "Is calibrated" preference
|
||||
#define CALIBRATED_NAME (@"Calibrated")
|
||||
// Application domain for SeisMac library
|
||||
|
@ -271,19 +290,22 @@ static float onegs[3]; // X, Y and Z one-g calibration values
|
|||
if (logObject) { \
|
||||
[logObject performSelector:logSelector withObject:message]; \
|
||||
}
|
||||
#define LOG_ARG(format, var1) \
|
||||
if (logObject) { \
|
||||
[logObject performSelector:logSelector withObject:[NSString stringWithFormat:format, var1]]; \
|
||||
#define LOG_ARG(format, var1) \
|
||||
if (logObject) { \
|
||||
[logObject performSelector:logSelector \
|
||||
withObject:[NSString stringWithFormat:format, var1]]; \
|
||||
}
|
||||
#define LOG_2ARG(format, var1, var2) \
|
||||
if (logObject) { \
|
||||
[logObject performSelector:logSelector \
|
||||
withObject:[NSString stringWithFormat:format, var1, var2]]; \
|
||||
#define LOG_2ARG(format, var1, var2) \
|
||||
if (logObject) { \
|
||||
[logObject \
|
||||
performSelector:logSelector \
|
||||
withObject:[NSString stringWithFormat:format, var1, var2]]; \
|
||||
}
|
||||
#define LOG_3ARG(format, var1, var2, var3) \
|
||||
if (logObject) { \
|
||||
[logObject performSelector:logSelector \
|
||||
withObject:[NSString stringWithFormat:format, var1, var2, var3]]; \
|
||||
#define LOG_3ARG(format, var1, var2, var3) \
|
||||
if (logObject) { \
|
||||
[logObject \
|
||||
performSelector:logSelector \
|
||||
withObject:[NSString stringWithFormat:format, var1, var2, var3]]; \
|
||||
}
|
||||
|
||||
#pragma mark Function definitions
|
||||
|
@ -322,11 +344,12 @@ int smsStartup(id logObject, SEL logSelector) {
|
|||
recordSize = sensors[sensorNum].recordSize;
|
||||
function = sensors[sensorNum].function;
|
||||
|
||||
LOG_3ARG(@"Trying service \"%s\" with selector %d and %d byte record:\n", serviceName, function,
|
||||
recordSize);
|
||||
LOG_3ARG(@"Trying service \"%s\" with selector %d and %d byte record:\n",
|
||||
serviceName, function, recordSize);
|
||||
|
||||
NSString* targetName = [NSString stringWithCString:sensors[sensorNum].model
|
||||
encoding:NSMacOSRomanStringEncoding];
|
||||
NSString* targetName =
|
||||
[NSString stringWithCString:sensors[sensorNum].model
|
||||
encoding:NSMacOSRomanStringEncoding];
|
||||
LOG_ARG(@" Comparing model name to target \"%@\": ", targetName);
|
||||
if ([targetName length] == 0 || [modelName hasPrefix:targetName]) {
|
||||
LOG(@"success.\n");
|
||||
|
@ -350,7 +373,8 @@ int smsStartup(id logObject, SEL logSelector) {
|
|||
}
|
||||
|
||||
LOG(@" Getting list of matching services: ");
|
||||
result = IOServiceGetMatchingServices(kIOMasterPortDefault, dict, &iterator);
|
||||
result =
|
||||
IOServiceGetMatchingServices(kIOMasterPortDefault, dict, &iterator);
|
||||
|
||||
if (result == KERN_SUCCESS) {
|
||||
LOG(@"success.\n");
|
||||
|
@ -386,7 +410,9 @@ int smsStartup(id logObject, SEL logSelector) {
|
|||
}
|
||||
continue;
|
||||
} else if (connection == 0) {
|
||||
LOG_ARG(@"'success', but didn't get a connection (return value was: 0x%x).\n", result);
|
||||
LOG_ARG(
|
||||
@"'success', but didn't get a connection (return value was: 0x%x).\n",
|
||||
result);
|
||||
IOObjectRelease(device);
|
||||
if (failure_result < SMS_FAIL_CONNECTION) {
|
||||
failure_result = SMS_FAIL_CONNECTION;
|
||||
|
@ -551,14 +577,15 @@ void smsGetBufferData(char* buffer) {
|
|||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||
const size_t InStructSize = recordSize;
|
||||
size_t OutStructSize = recordSize;
|
||||
result =
|
||||
IOConnectCallStructMethod(connection,
|
||||
function, // magic kernel function number
|
||||
(const void*)iRecord, InStructSize, (void*)buffer, &OutStructSize);
|
||||
result = IOConnectCallStructMethod(connection,
|
||||
function, // magic kernel function number
|
||||
(const void*)iRecord, InStructSize,
|
||||
(void*)buffer, &OutStructSize);
|
||||
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||
result = IOConnectMethodStructureIStructureO(connection,
|
||||
function, // magic kernel function number
|
||||
iSize, &oSize, iRecord, buffer);
|
||||
result = IOConnectMethodStructureIStructureO(
|
||||
connection,
|
||||
function, // magic kernel function number
|
||||
iSize, &oSize, iRecord, buffer);
|
||||
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||
|
||||
if (result != KERN_SUCCESS) {
|
||||
|
@ -580,9 +607,10 @@ NSString* smsGetCalibrationDescription(void) {
|
|||
[s appendString:@"---- SeisMac Calibration Record ----\n \n"];
|
||||
[s appendFormat:@"Machine model: %@\n", getModelName()];
|
||||
[s appendFormat:@"OS X build: %@\n", getOSVersion()];
|
||||
[s appendFormat:@"SeisMacLib version %s, record %d\n \n", SMSLIB_VERSION, sensorNum];
|
||||
[s appendFormat:@"Using service \"%s\", function index %d, size %d\n \n", serviceName, function,
|
||||
recordSize];
|
||||
[s appendFormat:@"SeisMacLib version %s, record %d\n \n", SMSLIB_VERSION,
|
||||
sensorNum];
|
||||
[s appendFormat:@"Using service \"%s\", function index %d, size %d\n \n",
|
||||
serviceName, function, recordSize];
|
||||
if (prefIntRead(CALIBRATED_NAME, &success) && success) {
|
||||
[s appendString:@"Calibration values (from calibration):\n"];
|
||||
} else {
|
||||
|
@ -670,7 +698,8 @@ static void deleteCalibration(void) {
|
|||
static float prefFloatRead(NSString* prefName, BOOL* success) {
|
||||
float result = 0.0f;
|
||||
|
||||
CFPropertyListRef ref = CFPreferencesCopyAppValue((CFStringRef)prefName, APP_ID);
|
||||
CFPropertyListRef ref =
|
||||
CFPreferencesCopyAppValue((CFStringRef)prefName, APP_ID);
|
||||
// If there isn't such a preference, fail
|
||||
if (ref == NULL) {
|
||||
*success = NO;
|
||||
|
@ -682,7 +711,8 @@ static float prefFloatRead(NSString* prefName, BOOL* success) {
|
|||
// Is it a floating point number?
|
||||
if (CFNumberIsFloatType((CFNumberRef)ref)) {
|
||||
// Yup: grab it.
|
||||
*success = CFNumberGetValue((__CFNumber*)ref, kCFNumberFloat32Type, &result);
|
||||
*success =
|
||||
CFNumberGetValue((__CFNumber*)ref, kCFNumberFloat32Type, &result);
|
||||
} else {
|
||||
// Nope: grab as an integer, and convert to a float.
|
||||
long num;
|
||||
|
@ -707,7 +737,8 @@ static float prefFloatRead(NSString* prefName, BOOL* success) {
|
|||
|
||||
// Writes a named floating point value to the stored preferences.
|
||||
static void prefFloatWrite(NSString* prefName, float prefValue) {
|
||||
CFNumberRef cfFloat = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &prefValue);
|
||||
CFNumberRef cfFloat =
|
||||
CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &prefValue);
|
||||
CFPreferencesSetAppValue((CFStringRef)prefName, cfFloat, APP_ID);
|
||||
CFRelease(cfFloat);
|
||||
}
|
||||
|
@ -715,7 +746,8 @@ static void prefFloatWrite(NSString* prefName, float prefValue) {
|
|||
// Reads a named integer value from the stored preferences.
|
||||
static int prefIntRead(NSString* prefName, BOOL* success) {
|
||||
Boolean internalSuccess;
|
||||
CFIndex result = CFPreferencesGetAppIntegerValue((CFStringRef)prefName, APP_ID, &internalSuccess);
|
||||
CFIndex result = CFPreferencesGetAppIntegerValue((CFStringRef)prefName,
|
||||
APP_ID, &internalSuccess);
|
||||
*success = internalSuccess;
|
||||
|
||||
return result;
|
||||
|
@ -723,7 +755,8 @@ static int prefIntRead(NSString* prefName, BOOL* success) {
|
|||
|
||||
// Writes a named integer value to the stored preferences.
|
||||
static void prefIntWrite(NSString* prefName, int prefValue) {
|
||||
CFPreferencesSetAppValue((CFStringRef)prefName, (CFNumberRef)[NSNumber numberWithInt:prefValue],
|
||||
CFPreferencesSetAppValue((CFStringRef)prefName,
|
||||
(CFNumberRef)[NSNumber numberWithInt:prefValue],
|
||||
APP_ID);
|
||||
}
|
||||
|
||||
|
@ -736,7 +769,8 @@ static void prefDelete(NSString* prefName) {
|
|||
static void prefSynchronize(void) { CFPreferencesAppSynchronize(APP_ID); }
|
||||
|
||||
// Internal version of accelGetData, with logging
|
||||
int getData(sms_acceleration* accel, int calibrated, id logObject, SEL logSelector) {
|
||||
int getData(sms_acceleration* accel, int calibrated, id logObject,
|
||||
SEL logSelector) {
|
||||
IOItemCount iSize = recordSize;
|
||||
IOByteCount oSize = recordSize;
|
||||
kern_return_t result;
|
||||
|
@ -754,14 +788,15 @@ int getData(sms_acceleration* accel, int calibrated, id logObject, SEL logSelect
|
|||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||
const size_t InStructSize = recordSize;
|
||||
size_t OutStructSize = recordSize;
|
||||
result =
|
||||
IOConnectCallStructMethod(connection,
|
||||
function, // magic kernel function number
|
||||
(const void*)iRecord, InStructSize, (void*)oRecord, &OutStructSize);
|
||||
result = IOConnectCallStructMethod(connection,
|
||||
function, // magic kernel function number
|
||||
(const void*)iRecord, InStructSize,
|
||||
(void*)oRecord, &OutStructSize);
|
||||
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||
result = IOConnectMethodStructureIStructureO(connection,
|
||||
function, // magic kernel function number
|
||||
iSize, &oSize, iRecord, oRecord);
|
||||
result = IOConnectMethodStructureIStructureO(
|
||||
connection,
|
||||
function, // magic kernel function number
|
||||
iSize, &oSize, iRecord, oRecord);
|
||||
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||
|
||||
if (result != KERN_SUCCESS) {
|
||||
|
@ -845,11 +880,13 @@ NSString* getModelName(void) {
|
|||
|
||||
// Returns the current OS X version and build (e.g. "10.4.7 (build 8J2135a)")
|
||||
NSString* getOSVersion(void) {
|
||||
NSDictionary* dict = [NSDictionary
|
||||
dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
|
||||
NSDictionary* dict =
|
||||
[NSDictionary dictionaryWithContentsOfFile:
|
||||
@"/System/Library/CoreServices/SystemVersion.plist"];
|
||||
NSString* versionString = [dict objectForKey:@"ProductVersion"];
|
||||
NSString* buildString = [dict objectForKey:@"ProductBuildVersion"];
|
||||
NSString* wholeString = [NSString stringWithFormat:@"%@ (build %@)", versionString, buildString];
|
||||
NSString* wholeString =
|
||||
[NSString stringWithFormat:@"%@ (build %@)", versionString, buildString];
|
||||
return wholeString;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ nsIconChannel::~nsIconChannel() {
|
|||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsIconChannel, nsIChannel, nsIRequest, nsIRequestObserver, nsIStreamListener)
|
||||
NS_IMPL_ISUPPORTS(nsIconChannel, nsIChannel, nsIRequest, nsIRequestObserver,
|
||||
nsIStreamListener)
|
||||
|
||||
nsresult nsIconChannel::Init(nsIURI* uri) {
|
||||
NS_ASSERTION(uri, "no uri");
|
||||
|
@ -73,7 +74,8 @@ NS_IMETHODIMP nsIconChannel::GetCanceledReason(nsACString& aReason) {
|
|||
return GetCanceledReasonImpl(aReason);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsIconChannel::CancelWithReason(nsresult aStatus, const nsACString& aReason) {
|
||||
NS_IMETHODIMP nsIconChannel::CancelWithReason(nsresult aStatus,
|
||||
const nsACString& aReason) {
|
||||
return CancelWithReasonImpl(aStatus, aReason);
|
||||
}
|
||||
|
||||
|
@ -121,8 +123,8 @@ nsIconChannel::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
|
|||
|
||||
// nsIStreamListener methods
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aStream, uint64_t aOffset,
|
||||
uint32_t aCount) {
|
||||
nsIconChannel::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aStream,
|
||||
uint64_t aOffset, uint32_t aCount) {
|
||||
if (mListener) {
|
||||
return mListener->OnDataAvailable(this, aStream, aOffset, aCount);
|
||||
}
|
||||
|
@ -156,13 +158,15 @@ nsIconChannel::GetURI(nsIURI** aURI) {
|
|||
NS_IMETHODIMP
|
||||
nsIconChannel::Open(nsIInputStream** _retval) {
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
nsresult rv =
|
||||
nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return MakeInputStream(_retval, false);
|
||||
}
|
||||
|
||||
nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile, uint32_t* aDesiredImageSize,
|
||||
nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile,
|
||||
uint32_t* aDesiredImageSize,
|
||||
nsACString& aContentType,
|
||||
nsACString& aFileExtension) {
|
||||
nsresult rv = NS_OK;
|
||||
|
@ -196,18 +200,21 @@ nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile, uint32_t* a
|
|||
NS_IMETHODIMP
|
||||
nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
|
||||
nsCOMPtr<nsIStreamListener> listener = aListener;
|
||||
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
nsresult rv =
|
||||
nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||
if (NS_FAILED(rv)) {
|
||||
mCallbacks = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mLoadInfo->GetSecurityMode() == 0 || mLoadInfo->GetInitialSecurityCheckDone() ||
|
||||
(mLoadInfo->GetSecurityMode() ==
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
|
||||
mLoadInfo->GetLoadingPrincipal() &&
|
||||
mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()),
|
||||
"security flags in loadInfo but doContentSecurityCheck() not called");
|
||||
MOZ_ASSERT(
|
||||
mLoadInfo->GetSecurityMode() == 0 ||
|
||||
mLoadInfo->GetInitialSecurityCheckDone() ||
|
||||
(mLoadInfo->GetSecurityMode() ==
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
|
||||
mLoadInfo->GetLoadingPrincipal() &&
|
||||
mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()),
|
||||
"security flags in loadInfo but doContentSecurityCheck() not called");
|
||||
|
||||
nsCOMPtr<nsIInputStream> inStream;
|
||||
rv = MakeInputStream(getter_AddRefs(inStream), true);
|
||||
|
@ -218,7 +225,8 @@ nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
|
|||
|
||||
// Init our stream pump
|
||||
nsCOMPtr<nsISerialEventTarget> target =
|
||||
nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo, mozilla::TaskCategory::Other);
|
||||
nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo,
|
||||
mozilla::TaskCategory::Other);
|
||||
rv = mPump->Init(inStream, 0, 0, false, target);
|
||||
if (NS_FAILED(rv)) {
|
||||
mCallbacks = nullptr;
|
||||
|
@ -240,15 +248,16 @@ nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlocking) {
|
||||
nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval,
|
||||
bool aNonBlocking) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsCString contentType;
|
||||
nsAutoCString fileExt;
|
||||
nsCOMPtr<nsIFile> fileloc; // file we want an icon for
|
||||
uint32_t desiredImageSize;
|
||||
nsresult rv =
|
||||
ExtractIconInfoFromUrl(getter_AddRefs(fileloc), &desiredImageSize, contentType, fileExt);
|
||||
nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(fileloc),
|
||||
&desiredImageSize, contentType, fileExt);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool fileExists = false;
|
||||
|
@ -265,7 +274,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
|
|||
|
||||
CFURLRef macURL;
|
||||
if (NS_SUCCEEDED(localFileMac->GetCFURL(&macURL))) {
|
||||
iconImage = [[NSWorkspace sharedWorkspace] iconForFile:[(NSURL*)macURL path]];
|
||||
iconImage =
|
||||
[[NSWorkspace sharedWorkspace] iconForFile:[(NSURL*)macURL path]];
|
||||
::CFRelease(macURL);
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +288,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
|
|||
|
||||
// If we still don't have an icon, get the generic document icon.
|
||||
if (!iconImage) {
|
||||
iconImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeUnknown];
|
||||
iconImage =
|
||||
[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeUnknown];
|
||||
}
|
||||
|
||||
if (!iconImage) {
|
||||
|
@ -296,8 +307,10 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
|
|||
// account when it requests these icons; e.g. it will request an icon with
|
||||
// size 16, place it in a 16x16 CSS pixel sized image, and then display it in
|
||||
// a window on a HiDPI screen where the icon now covers 32x32 physical screen
|
||||
// pixels. So we just always double the size here in order to prevent blurriness.
|
||||
uint32_t size = (desiredImageSize < 128) ? desiredImageSize * 2 : desiredImageSize;
|
||||
// pixels. So we just always double the size here in order to prevent
|
||||
// blurriness.
|
||||
uint32_t size =
|
||||
(desiredImageSize < 128) ? desiredImageSize * 2 : desiredImageSize;
|
||||
uint32_t width = size;
|
||||
uint32_t height = size;
|
||||
|
||||
|
@ -322,14 +335,15 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
|
|||
// This gives us the image data in the format we want: BGRA, four bytes per
|
||||
// pixel, in host endianness, with premultiplied alpha.
|
||||
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef ctx =
|
||||
CGBitmapContextCreate(imageBuf, width, height, 8 /* bitsPerComponent */, width * 4, cs,
|
||||
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
|
||||
CGContextRef ctx = CGBitmapContextCreate(
|
||||
imageBuf, width, height, 8 /* bitsPerComponent */, width * 4, cs,
|
||||
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
|
||||
CGColorSpaceRelease(cs);
|
||||
|
||||
NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
|
||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:ctx
|
||||
flipped:NO]];
|
||||
[NSGraphicsContext
|
||||
setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:ctx
|
||||
flipped:NO]];
|
||||
|
||||
[iconImage drawInRect:NSMakeRect(0, 0, width, height)];
|
||||
|
||||
|
@ -340,8 +354,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
|
|||
// Now, create a pipe and stuff our data into it
|
||||
nsCOMPtr<nsIInputStream> inStream;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream), bufferCapacity, bufferCapacity,
|
||||
aNonBlocking);
|
||||
NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream),
|
||||
bufferCapacity, bufferCapacity, aNonBlocking);
|
||||
|
||||
uint32_t written;
|
||||
rv = outStream->Write((char*)fileBuf.get(), bufferCapacity, &written);
|
||||
|
@ -368,10 +382,14 @@ nsIconChannel::SetLoadFlags(uint32_t aLoadAttributes) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) { return GetTRRModeImpl(aTRRMode); }
|
||||
nsIconChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
|
||||
return GetTRRModeImpl(aTRRMode);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) { return SetTRRModeImpl(aTRRMode); }
|
||||
nsIconChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
|
||||
return SetTRRModeImpl(aTRRMode);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::GetIsDocument(bool* aIsDocument) {
|
||||
|
@ -415,17 +433,20 @@ nsIconChannel::SetContentDisposition(uint32_t aContentDisposition) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename) {
|
||||
nsIconChannel::GetContentDispositionFilename(
|
||||
nsAString& aContentDispositionFilename) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename) {
|
||||
nsIconChannel::SetContentDispositionFilename(
|
||||
const nsAString& aContentDispositionFilename) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader) {
|
||||
nsIconChannel::GetContentDispositionHeader(
|
||||
nsACString& aContentDispositionHeader) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
|
@ -481,14 +502,16 @@ nsIconChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor** aNotificationCallbacks) {
|
||||
nsIconChannel::GetNotificationCallbacks(
|
||||
nsIInterfaceRequestor** aNotificationCallbacks) {
|
||||
*aNotificationCallbacks = mCallbacks.get();
|
||||
NS_IF_ADDREF(*aNotificationCallbacks);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) {
|
||||
nsIconChannel::SetNotificationCallbacks(
|
||||
nsIInterfaceRequestor* aNotificationCallbacks) {
|
||||
mCallbacks = aNotificationCallbacks;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
#include "base/logging.h"
|
||||
|
||||
@interface CrApplication ()
|
||||
@property(readwrite, getter=isHandlingSendEvent, nonatomic) BOOL handlingSendEvent;
|
||||
@property(readwrite, getter=isHandlingSendEvent, nonatomic)
|
||||
BOOL handlingSendEvent;
|
||||
@end
|
||||
|
||||
@implementation CrApplication
|
||||
|
@ -19,7 +20,8 @@
|
|||
+ (NSApplication*)sharedApplication {
|
||||
NSApplication* app = [super sharedApplication];
|
||||
if (![NSApp isKindOfClass:self]) {
|
||||
CHROMIUM_LOG(ERROR) << "NSApp should be of type " << [[self className] UTF8String] << ", not "
|
||||
CHROMIUM_LOG(ERROR) << "NSApp should be of type "
|
||||
<< [[self className] UTF8String] << ", not "
|
||||
<< [[NSApp className] UTF8String];
|
||||
DCHECK(false) << "NSApp is of wrong type";
|
||||
}
|
||||
|
@ -59,6 +61,8 @@ ScopedSendingEvent::ScopedSendingEvent()
|
|||
[app_ setHandlingSendEvent:YES];
|
||||
}
|
||||
|
||||
ScopedSendingEvent::~ScopedSendingEvent() { [app_ setHandlingSendEvent:handling_]; }
|
||||
ScopedSendingEvent::~ScopedSendingEvent() {
|
||||
[app_ setHandlingSendEvent:handling_];
|
||||
}
|
||||
|
||||
} // namespace chrome_application_mac
|
||||
|
|
|
@ -22,7 +22,8 @@ bool AmIBundled() {
|
|||
if (GetProcessBundleLocation(&psn, &fsref) != noErr) return false;
|
||||
|
||||
FSCatalogInfo info;
|
||||
if (FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info, NULL, NULL, NULL) != noErr) {
|
||||
if (FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info, NULL, NULL, NULL) !=
|
||||
noErr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ namespace {
|
|||
|
||||
void NoOp(void* info) {}
|
||||
|
||||
const CFTimeInterval kCFTimeIntervalMax = std::numeric_limits<CFTimeInterval>::max();
|
||||
const CFTimeInterval kCFTimeIntervalMax =
|
||||
std::numeric_limits<CFTimeInterval>::max();
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -57,12 +58,13 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
|
|||
// as needed when ScheduleDelayedWork is called.
|
||||
CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
|
||||
timer_context.info = this;
|
||||
delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator
|
||||
kCFTimeIntervalMax, // fire time
|
||||
kCFTimeIntervalMax, // interval
|
||||
0, // flags
|
||||
0, // priority
|
||||
RunDelayedWorkTimer, &timer_context);
|
||||
delayed_work_timer_ =
|
||||
CFRunLoopTimerCreate(NULL, // allocator
|
||||
kCFTimeIntervalMax, // fire time
|
||||
kCFTimeIntervalMax, // interval
|
||||
0, // flags
|
||||
0, // priority
|
||||
RunDelayedWorkTimer, &timer_context);
|
||||
CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
|
||||
|
||||
CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
|
||||
|
@ -89,36 +91,42 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
|
|||
nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
|
||||
0, // priority
|
||||
&source_context);
|
||||
CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_, kCFRunLoopCommonModes);
|
||||
CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
|
||||
kCFRunLoopCommonModes);
|
||||
|
||||
CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
|
||||
observer_context.info = this;
|
||||
pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator
|
||||
kCFRunLoopBeforeWaiting,
|
||||
true, // repeat
|
||||
0, // priority
|
||||
PreWaitObserver, &observer_context);
|
||||
pre_wait_observer_ =
|
||||
CFRunLoopObserverCreate(NULL, // allocator
|
||||
kCFRunLoopBeforeWaiting,
|
||||
true, // repeat
|
||||
0, // priority
|
||||
PreWaitObserver, &observer_context);
|
||||
CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
|
||||
|
||||
pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator
|
||||
kCFRunLoopBeforeSources,
|
||||
true, // repeat
|
||||
0, // priority
|
||||
PreSourceObserver, &observer_context);
|
||||
pre_source_observer_ =
|
||||
CFRunLoopObserverCreate(NULL, // allocator
|
||||
kCFRunLoopBeforeSources,
|
||||
true, // repeat
|
||||
0, // priority
|
||||
PreSourceObserver, &observer_context);
|
||||
CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
|
||||
|
||||
enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator
|
||||
kCFRunLoopEntry | kCFRunLoopExit,
|
||||
true, // repeat
|
||||
0, // priority
|
||||
EnterExitObserver, &observer_context);
|
||||
enter_exit_observer_ =
|
||||
CFRunLoopObserverCreate(NULL, // allocator
|
||||
kCFRunLoopEntry | kCFRunLoopExit,
|
||||
true, // repeat
|
||||
0, // priority
|
||||
EnterExitObserver, &observer_context);
|
||||
CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
|
||||
|
||||
root_power_domain_ = IORegisterForSystemPower(
|
||||
this, &power_notification_port_, PowerStateNotification, &power_notification_object_);
|
||||
root_power_domain_ = IORegisterForSystemPower(this, &power_notification_port_,
|
||||
PowerStateNotification,
|
||||
&power_notification_object_);
|
||||
if (root_power_domain_ != MACH_PORT_NULL) {
|
||||
CFRunLoopAddSource(run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
|
||||
kCFRunLoopCommonModes);
|
||||
CFRunLoopAddSource(
|
||||
run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
|
||||
kCFRunLoopCommonModes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,23 +135,27 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
|
|||
// same number of run loops must be running when this object is destroyed.
|
||||
MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
|
||||
if (root_power_domain_ != MACH_PORT_NULL) {
|
||||
CFRunLoopRemoveSource(run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
|
||||
kCFRunLoopCommonModes);
|
||||
CFRunLoopRemoveSource(
|
||||
run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
|
||||
kCFRunLoopCommonModes);
|
||||
IODeregisterForSystemPower(&power_notification_object_);
|
||||
IOServiceClose(root_power_domain_);
|
||||
IONotificationPortDestroy(power_notification_port_);
|
||||
}
|
||||
|
||||
CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
|
||||
CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
|
||||
kCFRunLoopCommonModes);
|
||||
CFRelease(enter_exit_observer_);
|
||||
|
||||
CFRunLoopRemoveObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
|
||||
CFRunLoopRemoveObserver(run_loop_, pre_source_observer_,
|
||||
kCFRunLoopCommonModes);
|
||||
CFRelease(pre_source_observer_);
|
||||
|
||||
CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
|
||||
CFRelease(pre_wait_observer_);
|
||||
|
||||
CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_, kCFRunLoopCommonModes);
|
||||
CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_,
|
||||
kCFRunLoopCommonModes);
|
||||
CFRelease(nesting_deferred_work_source_);
|
||||
|
||||
CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
|
||||
|
@ -203,7 +215,8 @@ void MessagePumpCFRunLoopBase::ScheduleWork() {
|
|||
}
|
||||
|
||||
// Must be called on the run loop thread.
|
||||
void MessagePumpCFRunLoopBase::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
|
||||
void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
|
||||
const TimeTicks& delayed_work_time) {
|
||||
TimeDelta delta = delayed_work_time - TimeTicks::Now();
|
||||
delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF();
|
||||
CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
|
||||
|
@ -211,7 +224,8 @@ void MessagePumpCFRunLoopBase::ScheduleDelayedWork(const TimeTicks& delayed_work
|
|||
|
||||
// Called from the run loop.
|
||||
// static
|
||||
void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info) {
|
||||
void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
|
||||
void* info) {
|
||||
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
||||
|
||||
// The timer won't fire again until it's reset.
|
||||
|
@ -392,7 +406,8 @@ void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
|
|||
// Called from the run loop.
|
||||
// static
|
||||
void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
|
||||
CFRunLoopActivity activity, void* info) {
|
||||
CFRunLoopActivity activity,
|
||||
void* info) {
|
||||
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
||||
|
||||
// Attempt to do some idle work before going to sleep.
|
||||
|
@ -408,7 +423,8 @@ void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
|
|||
// Called from the run loop.
|
||||
// static
|
||||
void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
|
||||
CFRunLoopActivity activity, void* info) {
|
||||
CFRunLoopActivity activity,
|
||||
void* info) {
|
||||
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
||||
|
||||
// The run loop has reached the top of the loop and is about to begin
|
||||
|
@ -422,7 +438,8 @@ void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
|
|||
// Called from the run loop.
|
||||
// static
|
||||
void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
|
||||
CFRunLoopActivity activity, void* info) {
|
||||
CFRunLoopActivity activity,
|
||||
void* info) {
|
||||
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
||||
|
||||
switch (activity) {
|
||||
|
@ -463,7 +480,8 @@ void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
|
|||
|
||||
// Called from the run loop.
|
||||
// static
|
||||
void MessagePumpCFRunLoopBase::PowerStateNotification(void* info, io_service_t service,
|
||||
void MessagePumpCFRunLoopBase::PowerStateNotification(void* info,
|
||||
io_service_t service,
|
||||
uint32_t message_type,
|
||||
void* message_argument) {
|
||||
// CFRunLoopTimer (NSTimer) is scheduled in terms of CFAbsoluteTime, which
|
||||
|
@ -508,7 +526,8 @@ void MessagePumpCFRunLoopBase::PowerStateNotification(void* info, io_service_t s
|
|||
switch (message_type) {
|
||||
case kIOMessageSystemWillPowerOn:
|
||||
if (self->delayed_work_fire_time_ != kCFTimeIntervalMax) {
|
||||
CFRunLoopTimerSetNextFireDate(self->delayed_work_timer_, self->delayed_work_fire_time_);
|
||||
CFRunLoopTimerSetNextFireDate(self->delayed_work_timer_,
|
||||
self->delayed_work_fire_time_);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -517,7 +536,8 @@ void MessagePumpCFRunLoopBase::PowerStateNotification(void* info, io_service_t s
|
|||
// The system will wait for 30 seconds before entering sleep if neither
|
||||
// IOAllowPowerChange nor IOCancelPowerChange are called. That would be
|
||||
// pretty antisocial.
|
||||
IOAllowPowerChange(self->root_power_domain_, reinterpret_cast<long>(message_argument));
|
||||
IOAllowPowerChange(self->root_power_domain_,
|
||||
reinterpret_cast<long>(message_argument));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -546,7 +566,8 @@ void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
|
|||
int result;
|
||||
do {
|
||||
MessagePumpScopedAutoreleasePool autorelease_pool(this);
|
||||
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, kCFTimeIntervalMax, false);
|
||||
result =
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, kCFTimeIntervalMax, false);
|
||||
} while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
|
||||
}
|
||||
|
||||
|
@ -568,7 +589,8 @@ void MessagePumpCFRunLoop::Quit() {
|
|||
|
||||
// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
|
||||
void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
|
||||
if (activity == kCFRunLoopExit && nesting_level() == run_nesting_level() && quit_pending_) {
|
||||
if (activity == kCFRunLoopExit && nesting_level() == run_nesting_level() &&
|
||||
quit_pending_) {
|
||||
// Quit was called while loops other than those managed by this object
|
||||
// were running further inside a run loop managed by this object. Now
|
||||
// that all unmanaged inner run loops are gone, stop the loop running
|
||||
|
@ -595,7 +617,8 @@ MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
|
|||
void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
|
||||
while (keep_running_) {
|
||||
// NSRunLoop manages autorelease pools itself.
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate distantFuture]];
|
||||
}
|
||||
|
||||
keep_running_ = true;
|
||||
|
|
|
@ -42,7 +42,9 @@ void InitThreading() {
|
|||
|
||||
static BOOL multithreaded = [NSThread isMultiThreaded];
|
||||
if (!multithreaded) {
|
||||
[NSThread detachNewThreadSelector:@selector(noOp) toTarget:[NoOp class] withObject:nil];
|
||||
[NSThread detachNewThreadSelector:@selector(noOp)
|
||||
toTarget:[NoOp class]
|
||||
withObject:nil];
|
||||
multithreaded = YES;
|
||||
|
||||
DCHECK([NSThread isMultiThreaded]);
|
||||
|
|
|
@ -41,7 +41,8 @@ static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
|
|||
namespace base {
|
||||
|
||||
Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
||||
const LaunchOptions& options, ProcessHandle* process_handle) {
|
||||
const LaunchOptions& options,
|
||||
ProcessHandle* process_handle) {
|
||||
Result<Ok, LaunchError> retval = Ok();
|
||||
|
||||
char* argv_copy[argv.size() + 1];
|
||||
|
@ -52,7 +53,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
|||
|
||||
EnvironmentArray env_storage;
|
||||
const EnvironmentArray& vars =
|
||||
options.full_env ? options.full_env : (env_storage = BuildEnvironmentArray(options.env_map));
|
||||
options.full_env ? options.full_env
|
||||
: (env_storage = BuildEnvironmentArray(options.env_map));
|
||||
|
||||
posix_spawn_file_actions_t file_actions;
|
||||
int err = posix_spawn_file_actions_init(&file_actions);
|
||||
|
@ -60,8 +62,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
|||
DLOG(WARNING) << "posix_spawn_file_actions_init failed";
|
||||
return Err(LaunchError("posix_spawn_file_actions_init", err));
|
||||
}
|
||||
auto file_actions_guard =
|
||||
mozilla::MakeScopeExit([&file_actions] { posix_spawn_file_actions_destroy(&file_actions); });
|
||||
auto file_actions_guard = mozilla::MakeScopeExit(
|
||||
[&file_actions] { posix_spawn_file_actions_destroy(&file_actions); });
|
||||
|
||||
// Turn fds_to_remap array into a set of dup2 calls.
|
||||
//
|
||||
|
@ -85,7 +87,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
|||
}
|
||||
|
||||
if (!options.workdir.empty()) {
|
||||
int rv = posix_spawn_file_actions_addchdir_np(&file_actions, options.workdir.c_str());
|
||||
int rv = posix_spawn_file_actions_addchdir_np(&file_actions,
|
||||
options.workdir.c_str());
|
||||
if (rv != 0) {
|
||||
DLOG(WARNING) << "posix_spawn_file_actions_addchdir_np failed";
|
||||
return Err(LaunchError("posix_spawn_file_actions_addchdir", rv));
|
||||
|
@ -99,15 +102,16 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
|||
DLOG(WARNING) << "posix_spawnattr_init failed";
|
||||
return Err(LaunchError("posix_spawnattr_init", err));
|
||||
}
|
||||
auto spawnattr_guard =
|
||||
mozilla::MakeScopeExit([&spawnattr] { posix_spawnattr_destroy(&spawnattr); });
|
||||
auto spawnattr_guard = mozilla::MakeScopeExit(
|
||||
[&spawnattr] { posix_spawnattr_destroy(&spawnattr); });
|
||||
|
||||
#if defined(XP_MACOSX) && defined(__aarch64__)
|
||||
if (options.arch == PROCESS_ARCH_X86_64) {
|
||||
cpu_type_t cpu_pref = CPU_TYPE_X86_64;
|
||||
size_t count = 1;
|
||||
size_t ocount = 0;
|
||||
int rv = posix_spawnattr_setbinpref_np(&spawnattr, count, &cpu_pref, &ocount);
|
||||
int rv =
|
||||
posix_spawnattr_setbinpref_np(&spawnattr, count, &cpu_pref, &ocount);
|
||||
if ((rv != 0) || (ocount != count)) {
|
||||
DLOG(WARNING) << "posix_spawnattr_setbinpref_np failed";
|
||||
return Err(LaunchError("posix_spawnattr_setbinpref_np", rv));
|
||||
|
@ -142,15 +146,16 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
|||
}
|
||||
|
||||
int pid = 0;
|
||||
int spawn_succeeded =
|
||||
(posix_spawnp(&pid, argv_copy[0], &file_actions, &spawnattr, argv_copy, vars.get()) == 0);
|
||||
int spawn_succeeded = (posix_spawnp(&pid, argv_copy[0], &file_actions,
|
||||
&spawnattr, argv_copy, vars.get()) == 0);
|
||||
|
||||
bool process_handle_valid = pid > 0;
|
||||
if (!spawn_succeeded || !process_handle_valid) {
|
||||
DLOG(WARNING) << "posix_spawnp failed";
|
||||
retval = Err(LaunchError("posix_spawnp", spawn_succeeded));
|
||||
} else {
|
||||
gProcessLog.print("==> process %d launched child process %d\n", GetCurrentProcId(), pid);
|
||||
gProcessLog.print("==> process %d launched child process %d\n",
|
||||
GetCurrentProcId(), pid);
|
||||
if (options.wait) HANDLE_EINTR(waitpid(pid, 0, 0));
|
||||
|
||||
if (process_handle) *process_handle = pid;
|
||||
|
@ -159,7 +164,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
|||
return retval;
|
||||
}
|
||||
|
||||
Result<Ok, LaunchError> LaunchApp(const CommandLine& cl, const LaunchOptions& options,
|
||||
Result<Ok, LaunchError> LaunchApp(const CommandLine& cl,
|
||||
const LaunchOptions& options,
|
||||
ProcessHandle* process_handle) {
|
||||
return LaunchApp(cl.argv(), options, process_handle);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@ ScopedNSAutoreleasePool::ScopedNSAutoreleasePool()
|
|||
DCHECK(autorelease_pool_);
|
||||
}
|
||||
|
||||
ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() { [autorelease_pool_ drain]; }
|
||||
ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() {
|
||||
[autorelease_pool_ drain];
|
||||
}
|
||||
|
||||
// Cycle the internal pool, allowing everything there to get cleaned up and
|
||||
// start anew.
|
||||
|
|
|
@ -44,11 +44,12 @@ static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
|
|||
out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
|
||||
|
||||
std::vector<typename StringType::value_type> out_buffer(elements);
|
||||
converted = CFStringGetBytes(cfstring, whole_string, encoding,
|
||||
0, // lossByte
|
||||
false, // isExternalRepresentation
|
||||
reinterpret_cast<UInt8*>(&out_buffer[0]), out_size,
|
||||
NULL); // usedBufLen
|
||||
converted =
|
||||
CFStringGetBytes(cfstring, whole_string, encoding,
|
||||
0, // lossByte
|
||||
false, // isExternalRepresentation
|
||||
reinterpret_cast<UInt8*>(&out_buffer[0]), out_size,
|
||||
NULL); // usedBufLen
|
||||
if (converted == 0) return StringType();
|
||||
|
||||
out_buffer[elements - 1] = '\0';
|
||||
|
@ -61,31 +62,33 @@ static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
|
|||
//
|
||||
// Do not assert in this function since it is used by the asssertion code!
|
||||
template <typename InStringType, typename OutStringType>
|
||||
static OutStringType STLStringToSTLStringWithEncodingsT(const InStringType& in,
|
||||
CFStringEncoding in_encoding,
|
||||
CFStringEncoding out_encoding) {
|
||||
static OutStringType STLStringToSTLStringWithEncodingsT(
|
||||
const InStringType& in, CFStringEncoding in_encoding,
|
||||
CFStringEncoding out_encoding) {
|
||||
typename InStringType::size_type in_length = in.length();
|
||||
if (in_length == 0) return OutStringType();
|
||||
|
||||
scoped_cftyperef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy(
|
||||
NULL, reinterpret_cast<const UInt8*>(in.data()),
|
||||
in_length * sizeof(typename InStringType::value_type), in_encoding, false, kCFAllocatorNull));
|
||||
in_length * sizeof(typename InStringType::value_type), in_encoding, false,
|
||||
kCFAllocatorNull));
|
||||
if (!cfstring) return OutStringType();
|
||||
|
||||
return CFStringToSTLStringWithEncodingT<OutStringType>(cfstring, out_encoding);
|
||||
return CFStringToSTLStringWithEncodingT<OutStringType>(cfstring,
|
||||
out_encoding);
|
||||
}
|
||||
|
||||
// Given an STL string |in| with an encoding specified by |in_encoding|,
|
||||
// return it as a CFStringRef. Returns NULL on failure.
|
||||
template <typename StringType>
|
||||
static CFStringRef STLStringToCFStringWithEncodingsT(const StringType& in,
|
||||
CFStringEncoding in_encoding) {
|
||||
static CFStringRef STLStringToCFStringWithEncodingsT(
|
||||
const StringType& in, CFStringEncoding in_encoding) {
|
||||
typename StringType::size_type in_length = in.length();
|
||||
if (in_length == 0) return CFSTR("");
|
||||
|
||||
return CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()),
|
||||
in_length * sizeof(typename StringType::value_type), in_encoding,
|
||||
false);
|
||||
return CFStringCreateWithBytes(
|
||||
kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()),
|
||||
in_length * sizeof(typename StringType::value_type), in_encoding, false);
|
||||
}
|
||||
|
||||
// Specify the byte ordering explicitly, otherwise CFString will be confused
|
||||
|
@ -102,18 +105,22 @@ static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE;
|
|||
|
||||
// Do not assert in this function since it is used by the asssertion code!
|
||||
std::string SysWideToUTF8(const std::wstring& wide) {
|
||||
return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(wide, kWideStringEncoding,
|
||||
kNarrowStringEncoding);
|
||||
return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(
|
||||
wide, kWideStringEncoding, kNarrowStringEncoding);
|
||||
}
|
||||
|
||||
// Do not assert in this function since it is used by the asssertion code!
|
||||
std::wstring SysUTF8ToWide(const StringPiece& utf8) {
|
||||
return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(utf8, kNarrowStringEncoding,
|
||||
kWideStringEncoding);
|
||||
return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(
|
||||
utf8, kNarrowStringEncoding, kWideStringEncoding);
|
||||
}
|
||||
|
||||
std::string SysWideToNativeMB(const std::wstring& wide) { return SysWideToUTF8(wide); }
|
||||
std::string SysWideToNativeMB(const std::wstring& wide) {
|
||||
return SysWideToUTF8(wide);
|
||||
}
|
||||
|
||||
std::wstring SysNativeMBToWide(const StringPiece& native_mb) { return SysUTF8ToWide(native_mb); }
|
||||
std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
|
||||
return SysUTF8ToWide(native_mb);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
|
|
@ -20,7 +20,8 @@ NS_IMPL_ADDREF_INHERITED(MessagePumpForNonMainUIThreads, MessagePump)
|
|||
NS_IMPL_RELEASE_INHERITED(MessagePumpForNonMainUIThreads, MessagePump)
|
||||
NS_IMPL_QUERY_INTERFACE(MessagePumpForNonMainUIThreads, nsIThreadObserver)
|
||||
|
||||
MessagePumpForNonMainUIThreads::MessagePumpForNonMainUIThreads(nsISerialEventTarget* aEventTarget)
|
||||
MessagePumpForNonMainUIThreads::MessagePumpForNonMainUIThreads(
|
||||
nsISerialEventTarget* aEventTarget)
|
||||
: mEventTarget(aEventTarget), keep_running_(true) {
|
||||
MOZ_ASSERT(mEventTarget);
|
||||
CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
|
||||
|
@ -36,13 +37,15 @@ MessagePumpForNonMainUIThreads::~MessagePumpForNonMainUIThreads() {
|
|||
CFRelease(quit_source_);
|
||||
}
|
||||
|
||||
void MessagePumpForNonMainUIThreads::DoRun(base::MessagePump::Delegate* aDelegate) {
|
||||
// If this is a chromium thread and no nsThread is associated with it, this call will create a
|
||||
// new nsThread.
|
||||
void MessagePumpForNonMainUIThreads::DoRun(
|
||||
base::MessagePump::Delegate* aDelegate) {
|
||||
// If this is a chromium thread and no nsThread is associated with it, this
|
||||
// call will create a new nsThread.
|
||||
nsIThread* thread = NS_GetCurrentThread();
|
||||
MOZ_ASSERT(thread);
|
||||
|
||||
// Set the main thread observer so we can wake up when xpcom events need to get processed.
|
||||
// Set the main thread observer so we can wake up when xpcom events need to
|
||||
// get processed.
|
||||
nsCOMPtr<nsIThreadInternal> ti(do_QueryInterface(thread));
|
||||
MOZ_ASSERT(ti);
|
||||
ti->SetObserver(this);
|
||||
|
@ -63,7 +66,8 @@ void MessagePumpForNonMainUIThreads::DoRun(base::MessagePump::Delegate* aDelegat
|
|||
|
||||
// Now process the CFRunLoop. It exits after running once.
|
||||
// NSRunLoop manages autorelease pools itself.
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate distantFuture]];
|
||||
}
|
||||
|
||||
ti->SetObserver(nullptr);
|
||||
|
@ -77,14 +81,15 @@ void MessagePumpForNonMainUIThreads::Quit() {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP MessagePumpForNonMainUIThreads::OnDispatchedEvent() {
|
||||
// ScheduleWork will signal an input source to the run loop, making it exit so it can process the
|
||||
// xpcom event.
|
||||
// ScheduleWork will signal an input source to the run loop, making it exit so
|
||||
// it can process the xpcom event.
|
||||
ScheduleWork();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MessagePumpForNonMainUIThreads::OnProcessNextEvent(nsIThreadInternal* thread, bool mayWait) {
|
||||
MessagePumpForNonMainUIThreads::OnProcessNextEvent(nsIThreadInternal* thread,
|
||||
bool mayWait) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,28 +25,32 @@ void SetThisProcessName(const char* aProcessName) {
|
|||
return;
|
||||
}
|
||||
|
||||
NSString* currentName =
|
||||
[[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:(NSString*)kCFBundleNameKey];
|
||||
NSString* currentName = [[[NSBundle mainBundle] localizedInfoDictionary]
|
||||
objectForKey:(NSString*)kCFBundleNameKey];
|
||||
|
||||
char formattedName[1024];
|
||||
SprintfLiteral(formattedName, "%s %s", [currentName UTF8String], aProcessName);
|
||||
SprintfLiteral(formattedName, "%s %s", [currentName UTF8String],
|
||||
aProcessName);
|
||||
|
||||
aProcessName = formattedName;
|
||||
|
||||
// This function is based on Chrome/Webkit's and relies on potentially dangerous SPI.
|
||||
// This function is based on Chrome/Webkit's and relies on potentially
|
||||
// dangerous SPI.
|
||||
typedef CFTypeRef (*LSGetASNType)();
|
||||
typedef OSStatus (*LSSetInformationItemType)(int, CFTypeRef, CFStringRef, CFStringRef,
|
||||
CFDictionaryRef*);
|
||||
typedef OSStatus (*LSSetInformationItemType)(int, CFTypeRef, CFStringRef,
|
||||
CFStringRef, CFDictionaryRef*);
|
||||
|
||||
CFBundleRef launchServices = ::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
|
||||
CFBundleRef launchServices =
|
||||
::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
|
||||
if (!launchServices) {
|
||||
NS_WARNING("Failed to set process name: Could not open LaunchServices bundle");
|
||||
NS_WARNING(
|
||||
"Failed to set process name: Could not open LaunchServices bundle");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sApplicationASN) {
|
||||
sApplicationASN =
|
||||
::CFBundleGetFunctionPointerForName(launchServices, CFSTR("_LSGetCurrentApplicationASN"));
|
||||
sApplicationASN = ::CFBundleGetFunctionPointerForName(
|
||||
launchServices, CFSTR("_LSGetCurrentApplicationASN"));
|
||||
if (!sApplicationASN) {
|
||||
NS_WARNING("Failed to set process name: Could not get function pointer "
|
||||
"for LaunchServices");
|
||||
|
@ -64,12 +68,13 @@ void SetThisProcessName(const char* aProcessName) {
|
|||
LSSetInformationItemType setInformationItemFunc =
|
||||
reinterpret_cast<LSSetInformationItemType>(sApplicationInfoItem);
|
||||
|
||||
void* displayNameKeyAddr =
|
||||
::CFBundleGetDataPointerForName(launchServices, CFSTR("_kLSDisplayNameKey"));
|
||||
void* displayNameKeyAddr = ::CFBundleGetDataPointerForName(
|
||||
launchServices, CFSTR("_kLSDisplayNameKey"));
|
||||
|
||||
CFStringRef displayNameKey = nil;
|
||||
if (displayNameKeyAddr) {
|
||||
displayNameKey = reinterpret_cast<CFStringRef>(*(CFStringRef*)displayNameKeyAddr);
|
||||
displayNameKey =
|
||||
reinterpret_cast<CFStringRef>(*(CFStringRef*)displayNameKeyAddr);
|
||||
}
|
||||
|
||||
// We need this to ensure we have a connection to the Process Manager, not
|
||||
|
@ -81,20 +86,22 @@ void SetThisProcessName(const char* aProcessName) {
|
|||
|
||||
CFTypeRef currentAsn = getASNFunc ? getASNFunc() : nullptr;
|
||||
|
||||
if (!getASNFunc || !setInformationItemFunc || !displayNameKey || !currentAsn) {
|
||||
if (!getASNFunc || !setInformationItemFunc || !displayNameKey ||
|
||||
!currentAsn) {
|
||||
NS_WARNING("Failed to set process name: Accessing launchServices failed");
|
||||
return;
|
||||
}
|
||||
|
||||
CFStringRef processName = ::CFStringCreateWithCString(nil, aProcessName, kCFStringEncodingASCII);
|
||||
CFStringRef processName =
|
||||
::CFStringCreateWithCString(nil, aProcessName, kCFStringEncodingASCII);
|
||||
if (!processName) {
|
||||
NS_WARNING("Failed to set process name: Could not create CFStringRef");
|
||||
return;
|
||||
}
|
||||
|
||||
OSErr err =
|
||||
setInformationItemFunc(UNDOCUMENTED_SESSION_CONSTANT, currentAsn, displayNameKey, processName,
|
||||
nil); // Optional out param
|
||||
OSErr err = setInformationItemFunc(UNDOCUMENTED_SESSION_CONSTANT, currentAsn,
|
||||
displayNameKey, processName,
|
||||
nil); // Optional out param
|
||||
::CFRelease(processName);
|
||||
if (err != noErr) {
|
||||
NS_WARNING("Failed to set process name: LSSetInformationItemType err");
|
||||
|
|
|
@ -71,12 +71,13 @@ bool SharedMemoryBasic::Create(size_t size) {
|
|||
|
||||
memory_object_size_t memoryObjectSize = round_page(size);
|
||||
|
||||
kern_return_t kr = mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
|
||||
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
|
||||
getter_Transfers(mPort), MACH_PORT_NULL);
|
||||
kern_return_t kr =
|
||||
mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
|
||||
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
|
||||
getter_Transfers(mPort), MACH_PORT_NULL);
|
||||
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
|
||||
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size, mach_error_string(kr),
|
||||
kr);
|
||||
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size,
|
||||
mach_error_string(kr), kr);
|
||||
CloseHandle();
|
||||
return false;
|
||||
}
|
||||
|
@ -101,12 +102,15 @@ bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
|
|||
}
|
||||
|
||||
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
|
||||
fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE, mPort.get(), 0, false,
|
||||
vmProtection, vmProtection, VM_INHERIT_NONE);
|
||||
fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
|
||||
mPort.get(), 0, false, vmProtection, vmProtection,
|
||||
VM_INHERIT_NONE);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
if (!fixed_address) {
|
||||
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n", size,
|
||||
mach_task_self(), mach_port_t(mPort.get()), mach_error_string(kr), kr);
|
||||
LOG_ERROR(
|
||||
"Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
|
||||
size, mach_task_self(), mach_port_t(mPort.get()),
|
||||
mach_error_string(kr), kr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -116,7 +120,8 @@ bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
|
|||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR("Failed to unmap shared memory at unsuitable address "
|
||||
"(%zu bytes) from %x, port %x. %s (%x)\n",
|
||||
size, mach_task_self(), mach_port_t(mPort.get()), mach_error_string(kr), kr);
|
||||
size, mach_task_self(), mach_port_t(mPort.get()),
|
||||
mach_error_string(kr), kr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -129,8 +134,9 @@ bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
|
|||
void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
|
||||
mach_vm_address_t address = 0;
|
||||
size = round_page(size);
|
||||
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0,
|
||||
false, VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_NONE) != KERN_SUCCESS ||
|
||||
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE,
|
||||
MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE,
|
||||
VM_INHERIT_NONE) != KERN_SUCCESS ||
|
||||
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -146,9 +152,11 @@ void SharedMemoryBasic::Unmap() {
|
|||
return;
|
||||
}
|
||||
vm_address_t address = toVMAddress(mMemory);
|
||||
kern_return_t kr = vm_deallocate(mach_task_self(), address, round_page(mMappedSize));
|
||||
kern_return_t kr =
|
||||
vm_deallocate(mach_task_self(), address, round_page(mMappedSize));
|
||||
if (kr != KERN_SUCCESS) {
|
||||
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n", mach_error_string(kr), kr);
|
||||
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n",
|
||||
mach_error_string(kr), kr);
|
||||
return;
|
||||
}
|
||||
mMemory = nullptr;
|
||||
|
@ -161,7 +169,9 @@ void SharedMemoryBasic::CloseHandle() {
|
|||
}
|
||||
}
|
||||
|
||||
bool SharedMemoryBasic::IsHandleValid(const Handle& aHandle) const { return aHandle != nullptr; }
|
||||
bool SharedMemoryBasic::IsHandleValid(const Handle& aHandle) const {
|
||||
return aHandle != nullptr;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -75,7 +75,9 @@ static OSStatus getErrorCodeBool(Boolean success) {
|
|||
}
|
||||
|
||||
// If given a NULL pointer, return the error code.
|
||||
static OSStatus getErrorCodePtr(const void* value) { return getErrorCodeBool(value != nullptr); }
|
||||
static OSStatus getErrorCodePtr(const void* value) {
|
||||
return getErrorCodeBool(value != nullptr);
|
||||
}
|
||||
|
||||
// Convenience function to allow NULL input.
|
||||
static void CFReleaseSafe(CFTypeRef cf) {
|
||||
|
@ -86,8 +88,8 @@ static void CFReleaseSafe(CFTypeRef cf) {
|
|||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver, nsITimerCallback,
|
||||
nsINamed)
|
||||
NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver,
|
||||
nsITimerCallback, nsINamed)
|
||||
|
||||
nsNetworkLinkService::nsNetworkLinkService()
|
||||
: mLinkUp(true),
|
||||
|
@ -129,7 +131,8 @@ nsNetworkLinkService::GetNetworkID(nsACString& aNetworkID) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::GetPlatformDNSIndications(uint32_t* aPlatformDNSIndications) {
|
||||
nsNetworkLinkService::GetPlatformDNSIndications(
|
||||
uint32_t* aPlatformDNSIndications) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -139,8 +142,9 @@ void nsNetworkLinkService::GetDnsSuffixListInternal() {
|
|||
|
||||
auto sendNotification = mozilla::MakeScopeExit([self = RefPtr{this}] {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"nsNetworkLinkService::GetDnsSuffixListInternal",
|
||||
[self]() { self->NotifyObservers(NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, nullptr); }));
|
||||
"nsNetworkLinkService::GetDnsSuffixListInternal", [self]() {
|
||||
self->NotifyObservers(NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, nullptr);
|
||||
}));
|
||||
});
|
||||
|
||||
nsTArray<nsCString> result;
|
||||
|
@ -176,15 +180,17 @@ nsNetworkLinkService::GetResolvers(nsTArray<RefPtr<nsINetAddr>>& aResolvers) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::GetNativeResolvers(nsTArray<mozilla::net::NetAddr>& aResolvers) {
|
||||
nsNetworkLinkService::GetNativeResolvers(
|
||||
nsTArray<mozilla::net::NetAddr>& aResolvers) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
#ifndef SA_SIZE
|
||||
# define SA_SIZE(sa) \
|
||||
((!(sa) || ((struct sockaddr*)(sa))->sa_len == 0) \
|
||||
? sizeof(uint32_t) \
|
||||
: 1 + ((((struct sockaddr*)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1)))
|
||||
# define SA_SIZE(sa) \
|
||||
((!(sa) || ((struct sockaddr*)(sa))->sa_len == 0) \
|
||||
? sizeof(uint32_t) \
|
||||
: 1 + ((((struct sockaddr*)(sa))->sa_len - 1) | \
|
||||
(sizeof(uint32_t) - 1)))
|
||||
#endif
|
||||
|
||||
static bool getMac(struct sockaddr_dl* sdl, char* buf, size_t bufsize) {
|
||||
|
@ -196,14 +202,14 @@ static bool getMac(struct sockaddr_dl* sdl, char* buf, size_t bufsize) {
|
|||
return false;
|
||||
}
|
||||
|
||||
snprintf(buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4],
|
||||
mac[5]);
|
||||
snprintf(buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1],
|
||||
mac[2], mac[3], mac[4], mac[5]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If the IP matches, get the MAC and return true */
|
||||
static bool matchIp(struct sockaddr_dl* sdl, struct sockaddr_inarp* addr, char* ip, char* buf,
|
||||
size_t bufsize) {
|
||||
static bool matchIp(struct sockaddr_dl* sdl, struct sockaddr_inarp* addr,
|
||||
char* ip, char* buf, size_t bufsize) {
|
||||
if (sdl->sdl_alen) {
|
||||
if (!strcmp(inet_ntoa(addr->sin_addr), ip)) {
|
||||
if (getMac(sdl, buf, bufsize)) {
|
||||
|
@ -275,8 +281,10 @@ static bool scanArp(char* ip, char* mac, size_t maclen) {
|
|||
struct rt_msghdr* rtm;
|
||||
for (next = &buf[0]; next < lim; next += rtm->rtm_msglen) {
|
||||
rtm = reinterpret_cast<struct rt_msghdr*>(next);
|
||||
struct sockaddr_inarp* sin2 = reinterpret_cast<struct sockaddr_inarp*>(rtm + 1);
|
||||
struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>((char*)sin2 + SA_SIZE(sin2));
|
||||
struct sockaddr_inarp* sin2 =
|
||||
reinterpret_cast<struct sockaddr_inarp*>(rtm + 1);
|
||||
struct sockaddr_dl* sdl =
|
||||
reinterpret_cast<struct sockaddr_dl*>((char*)sin2 + SA_SIZE(sin2));
|
||||
if (matchIp(sdl, sin2, ip, mac, maclen)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -285,9 +293,10 @@ static bool scanArp(char* ip, char* mac, size_t maclen) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Append the mac address of rtm to `stringsToHash`. If it's not in arp table, append
|
||||
// ifname and IP address.
|
||||
static bool parseHashKey(struct rt_msghdr* rtm, nsTArray<nsCString>& stringsToHash,
|
||||
// Append the mac address of rtm to `stringsToHash`. If it's not in arp table,
|
||||
// append ifname and IP address.
|
||||
static bool parseHashKey(struct rt_msghdr* rtm,
|
||||
nsTArray<nsCString>& stringsToHash,
|
||||
bool skipDstCheck) {
|
||||
struct sockaddr* sa;
|
||||
struct sockaddr_in* sockin;
|
||||
|
@ -317,8 +326,8 @@ static bool parseHashKey(struct rt_msghdr* rtm, nsTArray<nsCString>& stringsToHa
|
|||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr* gateway =
|
||||
reinterpret_cast<struct sockaddr*>((char*)sa + RTAX_GATEWAY * SA_SIZE(sa));
|
||||
struct sockaddr* gateway = reinterpret_cast<struct sockaddr*>(
|
||||
(char*)sa + RTAX_GATEWAY * SA_SIZE(sa));
|
||||
|
||||
if (!gateway) {
|
||||
return false;
|
||||
|
@ -440,7 +449,8 @@ bool nsNetworkLinkService::RoutingFromKernel(nsTArray<nsCString>& aHash) {
|
|||
sin->sin_addr = mRouteCheckIPv4;
|
||||
|
||||
if (write(sockfd, rtm, rtm->rtm_msglen) == -1) {
|
||||
LOG(("RoutingFromKernel: write() failed. No route to the predefine destincation"));
|
||||
LOG(("RoutingFromKernel: write() failed. No route to the predefine "
|
||||
"destincation"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -451,9 +461,11 @@ bool nsNetworkLinkService::RoutingFromKernel(nsTArray<nsCString>& aHash) {
|
|||
return false;
|
||||
}
|
||||
|
||||
LOG(("RoutingFromKernel: read() rtm_type: %d (%d), rtm_pid: %d (%d), rtm_seq: %d (%d)\n",
|
||||
LOG(("RoutingFromKernel: read() rtm_type: %d (%d), rtm_pid: %d (%d), "
|
||||
"rtm_seq: %d (%d)\n",
|
||||
rtm->rtm_type, RTM_GET, rtm->rtm_pid, pid, rtm->rtm_seq, seq));
|
||||
} while (rtm->rtm_type != RTM_GET || rtm->rtm_pid != pid || rtm->rtm_seq != seq);
|
||||
} while (rtm->rtm_type != RTM_GET || rtm->rtm_pid != pid ||
|
||||
rtm->rtm_seq != seq);
|
||||
|
||||
return parseHashKey(rtm, aHash, true);
|
||||
}
|
||||
|
@ -489,8 +501,9 @@ bool nsNetworkLinkService::IPv4NetworkId(SHA1Sum* aSHA1) {
|
|||
//
|
||||
void nsNetworkLinkService::HashSortedPrefixesAndNetmasks(
|
||||
std::vector<prefix_and_netmask> prefixAndNetmaskStore, SHA1Sum* sha1) {
|
||||
// getifaddrs does not guarantee the interfaces will always be in the same order.
|
||||
// We want to make sure the hash remains consistent Regardless of the interface order.
|
||||
// getifaddrs does not guarantee the interfaces will always be in the same
|
||||
// order. We want to make sure the hash remains consistent Regardless of the
|
||||
// interface order.
|
||||
std::sort(prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(),
|
||||
[](prefix_and_netmask a, prefix_and_netmask b) {
|
||||
// compare prefixStore
|
||||
|
@ -521,7 +534,8 @@ bool nsNetworkLinkService::IPv6NetworkId(SHA1Sum* sha1) {
|
|||
if ((AF_INET6 == ifa->ifa_addr->sa_family) &&
|
||||
!(ifa->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))) {
|
||||
// only IPv6 interfaces that aren't pointtopoint or loopback
|
||||
struct sockaddr_in6* sin_netmask = (struct sockaddr_in6*)ifa->ifa_netmask;
|
||||
struct sockaddr_in6* sin_netmask =
|
||||
(struct sockaddr_in6*)ifa->ifa_netmask;
|
||||
if (sin_netmask) {
|
||||
struct sockaddr_in6* sin_addr = (struct sockaddr_in6*)ifa->ifa_addr;
|
||||
int scope = net::utils::ipv6_scope(sin_addr->sin6_addr.s6_addr);
|
||||
|
@ -530,17 +544,20 @@ bool nsNetworkLinkService::IPv6NetworkId(SHA1Sum* sha1) {
|
|||
memset(&prefix, 0, sizeof(prefix));
|
||||
// Get the prefix by combining the address and netmask.
|
||||
for (size_t i = 0; i < sizeof(prefix); ++i) {
|
||||
prefix.s6_addr[i] =
|
||||
sin_addr->sin6_addr.s6_addr[i] & sin_netmask->sin6_addr.s6_addr[i];
|
||||
prefix.s6_addr[i] = sin_addr->sin6_addr.s6_addr[i] &
|
||||
sin_netmask->sin6_addr.s6_addr[i];
|
||||
}
|
||||
|
||||
// check if prefix and netmask was already found
|
||||
auto prefixAndNetmask = std::make_pair(prefix, sin_netmask->sin6_addr);
|
||||
auto prefixAndNetmask =
|
||||
std::make_pair(prefix, sin_netmask->sin6_addr);
|
||||
auto foundPosition = std::find_if(
|
||||
prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(),
|
||||
[&prefixAndNetmask](prefix_and_netmask current) {
|
||||
return memcmp(&prefixAndNetmask.first, ¤t.first, sizeof(in6_addr)) == 0 &&
|
||||
memcmp(&prefixAndNetmask.second, ¤t.second, sizeof(in6_addr)) == 0;
|
||||
return memcmp(&prefixAndNetmask.first, ¤t.first,
|
||||
sizeof(in6_addr)) == 0 &&
|
||||
memcmp(&prefixAndNetmask.second, ¤t.second,
|
||||
sizeof(in6_addr)) == 0;
|
||||
});
|
||||
if (foundPosition != prefixAndNetmaskStore.end()) {
|
||||
continue;
|
||||
|
@ -557,7 +574,8 @@ bool nsNetworkLinkService::IPv6NetworkId(SHA1Sum* sha1) {
|
|||
return false;
|
||||
}
|
||||
|
||||
nsNetworkLinkService::HashSortedPrefixesAndNetmasks(prefixAndNetmaskStore, sha1);
|
||||
nsNetworkLinkService::HashSortedPrefixesAndNetmasks(prefixAndNetmaskStore,
|
||||
sha1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -577,15 +595,17 @@ void nsNetworkLinkService::calculateNetworkIdWithDelay(uint32_t aDelay) {
|
|||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
nsCOMPtr<nsIEventTarget> target =
|
||||
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
target->Dispatch(NewRunnableMethod("nsNetworkLinkService::calculateNetworkIdInternal", this,
|
||||
&nsNetworkLinkService::calculateNetworkIdInternal),
|
||||
NS_DISPATCH_NORMAL));
|
||||
MOZ_ALWAYS_SUCCEEDS(target->Dispatch(
|
||||
NewRunnableMethod("nsNetworkLinkService::calculateNetworkIdInternal",
|
||||
this,
|
||||
&nsNetworkLinkService::calculateNetworkIdInternal),
|
||||
NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -615,7 +635,8 @@ void nsNetworkLinkService::calculateNetworkIdInternal(void) {
|
|||
SeedNetworkId(sha1);
|
||||
uint8_t digest[SHA1Sum::kHashSize];
|
||||
sha1.finish(digest);
|
||||
nsAutoCString newString(reinterpret_cast<char*>(digest), SHA1Sum::kHashSize);
|
||||
nsAutoCString newString(reinterpret_cast<char*>(digest),
|
||||
SHA1Sum::kHashSize);
|
||||
nsresult rv = Base64Encode(newString, output);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
LOG(("networkid: id %s\n", output.get()));
|
||||
|
@ -652,16 +673,17 @@ void nsNetworkLinkService::calculateNetworkIdInternal(void) {
|
|||
if (idChanged && !initialIDCalculation) {
|
||||
RefPtr<nsNetworkLinkService> self = this;
|
||||
|
||||
NS_DispatchToMainThread(
|
||||
NS_NewRunnableFunction("nsNetworkLinkService::calculateNetworkIdInternal",
|
||||
[self]() { self->OnNetworkIdChanged(); }));
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"nsNetworkLinkService::calculateNetworkIdInternal",
|
||||
[self]() { self->OnNetworkIdChanged(); }));
|
||||
}
|
||||
|
||||
initialIDCalculation = false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetworkLinkService::Observe(nsISupports* subject, const char* topic, const char16_t* data) {
|
||||
nsNetworkLinkService::Observe(nsISupports* subject, const char* topic,
|
||||
const char16_t* data) {
|
||||
if (!strcmp(topic, "xpcom-shutdown")) {
|
||||
Shutdown();
|
||||
}
|
||||
|
@ -671,14 +693,17 @@ nsNetworkLinkService::Observe(nsISupports* subject, const char* topic, const cha
|
|||
|
||||
/* static */
|
||||
void nsNetworkLinkService::NetworkConfigChanged(SCDynamicStoreRef aStoreREf,
|
||||
CFArrayRef aChangedKeys, void* aInfo) {
|
||||
CFArrayRef aChangedKeys,
|
||||
void* aInfo) {
|
||||
LOG(("nsNetworkLinkService::NetworkConfigChanged"));
|
||||
|
||||
bool ipConfigChanged = false;
|
||||
bool dnsConfigChanged = false;
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(aChangedKeys); ++i) {
|
||||
CFStringRef key = static_cast<CFStringRef>(CFArrayGetValueAtIndex(aChangedKeys, i));
|
||||
if (CFStringHasSuffix(key, kSCEntNetIPv4) || CFStringHasSuffix(key, kSCEntNetIPv6)) {
|
||||
CFStringRef key =
|
||||
static_cast<CFStringRef>(CFArrayGetValueAtIndex(aChangedKeys, i));
|
||||
if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
|
||||
CFStringHasSuffix(key, kSCEntNetIPv6)) {
|
||||
ipConfigChanged = true;
|
||||
}
|
||||
if (CFStringHasSuffix(key, kSCEntNetDNS)) {
|
||||
|
@ -698,7 +723,8 @@ void nsNetworkLinkService::NetworkConfigChanged(SCDynamicStoreRef aStoreREf,
|
|||
|
||||
void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) {
|
||||
LOG(("nsNetworkLinkService::DNSConfigChanged"));
|
||||
nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
nsCOMPtr<nsIEventTarget> target =
|
||||
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
@ -717,9 +743,9 @@ void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) {
|
|||
"nsNetworkLinkService::GetDnsSuffixListInternal", target));
|
||||
mDNSConfigChangedTimers.AppendElement(timer);
|
||||
} else {
|
||||
MOZ_ALWAYS_SUCCEEDS(target->Dispatch(
|
||||
NS_NewRunnableFunction("nsNetworkLinkService::GetDnsSuffixListInternal",
|
||||
[self = RefPtr{this}]() { self->GetDnsSuffixListInternal(); })));
|
||||
MOZ_ALWAYS_SUCCEEDS(target->Dispatch(NS_NewRunnableFunction(
|
||||
"nsNetworkLinkService::GetDnsSuffixListInternal",
|
||||
[self = RefPtr{this}]() { self->GetDnsSuffixListInternal(); })));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,13 +771,15 @@ nsresult nsNetworkLinkService::Init(void) {
|
|||
bzero(&addr, sizeof(addr));
|
||||
addr.sin_len = sizeof(addr);
|
||||
addr.sin_family = AF_INET;
|
||||
mReachability = ::SCNetworkReachabilityCreateWithAddress(nullptr, (struct sockaddr*)&addr);
|
||||
mReachability = ::SCNetworkReachabilityCreateWithAddress(
|
||||
nullptr, (struct sockaddr*)&addr);
|
||||
if (!mReachability) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
SCNetworkReachabilityContext context = {0, this, nullptr, nullptr, nullptr};
|
||||
if (!::SCNetworkReachabilitySetCallback(mReachability, ReachabilityChanged, &context)) {
|
||||
if (!::SCNetworkReachabilitySetCallback(mReachability, ReachabilityChanged,
|
||||
&context)) {
|
||||
NS_WARNING("SCNetworkReachabilitySetCallback failed.");
|
||||
::CFRelease(mReachability);
|
||||
mReachability = nullptr;
|
||||
|
@ -759,24 +787,25 @@ nsresult nsNetworkLinkService::Init(void) {
|
|||
}
|
||||
|
||||
SCDynamicStoreContext storeContext = {0, this, nullptr, nullptr, nullptr};
|
||||
mStoreRef = ::SCDynamicStoreCreate(nullptr, CFSTR("IPAndDNSChangeCallbackSCF"),
|
||||
NetworkConfigChanged, &storeContext);
|
||||
mStoreRef =
|
||||
::SCDynamicStoreCreate(nullptr, CFSTR("IPAndDNSChangeCallbackSCF"),
|
||||
NetworkConfigChanged, &storeContext);
|
||||
|
||||
CFStringRef patterns[4] = {nullptr, nullptr, nullptr, nullptr};
|
||||
OSStatus err = getErrorCodePtr(mStoreRef);
|
||||
if (err == noErr) {
|
||||
// This pattern is "State:/Network/Service/[^/]+/IPv4".
|
||||
patterns[0] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState,
|
||||
kSCCompAnyRegex, kSCEntNetIPv4);
|
||||
patterns[0] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
|
||||
nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
|
||||
// This pattern is "State:/Network/Service/[^/]+/IPv6".
|
||||
patterns[1] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState,
|
||||
kSCCompAnyRegex, kSCEntNetIPv6);
|
||||
patterns[1] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
|
||||
nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
|
||||
// This pattern is "State:/Network/Service/[^/]+/DNS".
|
||||
patterns[2] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState,
|
||||
kSCCompAnyRegex, kSCEntNetDNS);
|
||||
patterns[2] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
|
||||
nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetDNS);
|
||||
// This pattern is "Setup:/Network/Service/[^/]+/DNS".
|
||||
patterns[3] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainSetup,
|
||||
kSCCompAnyRegex, kSCEntNetDNS);
|
||||
patterns[3] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
|
||||
nullptr, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetDNS);
|
||||
if (!patterns[0] || !patterns[1] || !patterns[2] || !patterns[3]) {
|
||||
err = -1;
|
||||
}
|
||||
|
@ -788,13 +817,15 @@ nsresult nsNetworkLinkService::Init(void) {
|
|||
// that match that pattern list, then create our run loop
|
||||
// source.
|
||||
if (err == noErr) {
|
||||
patternList = ::CFArrayCreate(nullptr, (const void**)patterns, 4, &kCFTypeArrayCallBacks);
|
||||
patternList = ::CFArrayCreate(nullptr, (const void**)patterns, 4,
|
||||
&kCFTypeArrayCallBacks);
|
||||
if (!patternList) {
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
if (err == noErr) {
|
||||
err = getErrorCodeBool(::SCDynamicStoreSetNotificationKeys(mStoreRef, nullptr, patternList));
|
||||
err = getErrorCodeBool(
|
||||
::SCDynamicStoreSetNotificationKeys(mStoreRef, nullptr, patternList));
|
||||
}
|
||||
|
||||
if (err == noErr) {
|
||||
|
@ -925,26 +956,31 @@ void nsNetworkLinkService::OnReachabilityChanged() {
|
|||
return;
|
||||
}
|
||||
|
||||
NotifyObservers(NS_NETWORK_LINK_TOPIC,
|
||||
mLinkUp ? NS_NETWORK_LINK_DATA_UP : NS_NETWORK_LINK_DATA_DOWN);
|
||||
NotifyObservers(NS_NETWORK_LINK_TOPIC, mLinkUp ? NS_NETWORK_LINK_DATA_UP
|
||||
: NS_NETWORK_LINK_DATA_DOWN);
|
||||
}
|
||||
|
||||
void nsNetworkLinkService::NotifyObservers(const char* aTopic, const char* aData) {
|
||||
void nsNetworkLinkService::NotifyObservers(const char* aTopic,
|
||||
const char* aData) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
LOG(("nsNetworkLinkService::NotifyObservers: topic:%s data:%s\n", aTopic, aData ? aData : ""));
|
||||
LOG(("nsNetworkLinkService::NotifyObservers: topic:%s data:%s\n", aTopic,
|
||||
aData ? aData : ""));
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
if (observerService) {
|
||||
observerService->NotifyObservers(static_cast<nsINetworkLinkService*>(this), aTopic,
|
||||
aData ? NS_ConvertASCIItoUTF16(aData).get() : nullptr);
|
||||
observerService->NotifyObservers(
|
||||
static_cast<nsINetworkLinkService*>(this), aTopic,
|
||||
aData ? NS_ConvertASCIItoUTF16(aData).get() : nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target,
|
||||
SCNetworkConnectionFlags flags, void* info) {
|
||||
SCNetworkConnectionFlags flags,
|
||||
void* info) {
|
||||
LOG(("nsNetworkLinkService::ReachabilityChanged"));
|
||||
nsNetworkLinkService* service = static_cast<nsNetworkLinkService*>(info);
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
|
|||
|
||||
@try {
|
||||
NSBundle* bundle = [[[NSBundle alloc]
|
||||
initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"] autorelease];
|
||||
initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"]
|
||||
autorelease];
|
||||
if (!bundle) {
|
||||
[pool release];
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
@ -41,7 +42,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
id scanResult = [[CWI_class interface] scanForNetworksWithSSID:nil error:nil];
|
||||
id scanResult = [[CWI_class interface] scanForNetworksWithSSID:nil
|
||||
error:nil];
|
||||
if (!scanResult) {
|
||||
[pool release];
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
@ -73,7 +75,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
|
|||
NSString* macString = [anObject bssid];
|
||||
if (macString && ([macString length] == 17)) {
|
||||
for (NSUInteger i = 0; i < 6; ++i) {
|
||||
NSString* part = [macString substringWithRange:NSMakeRange(i * 3, 2)];
|
||||
NSString* part =
|
||||
[macString substringWithRange:NSMakeRange(i * 3, 2)];
|
||||
NSScanner* scanner = [NSScanner scannerWithString:part];
|
||||
unsigned int data = 0;
|
||||
if (![scanner scanHexInt:&data]) {
|
||||
|
|
|
@ -35,12 +35,15 @@ nsresult ReauthenticateUserMacOS(const nsAString& aPrompt,
|
|||
localizedReason:prompt
|
||||
reply:^(BOOL success, NSError* error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// error is not particularly useful in this context, and we have no
|
||||
// mechanism to really return it. We could use it to set the nsresult,
|
||||
// but this is a best-effort mechanism and there's no particular case for
|
||||
// propagating up XPCOM. The one exception being a user account that
|
||||
// has no passcode set, which we handle below.
|
||||
errorPasswordNotSet = error && [error code] == kPasswordNotSetErrorCode;
|
||||
// error is not particularly useful in this context, and
|
||||
// we have no mechanism to really return it. We could
|
||||
// use it to set the nsresult, but this is a best-effort
|
||||
// mechanism and there's no particular case for
|
||||
// propagating up XPCOM. The one exception being a user
|
||||
// account that has no passcode set, which we handle
|
||||
// below.
|
||||
errorPasswordNotSet =
|
||||
error && [error code] == kPasswordNotSetErrorCode;
|
||||
biometricSuccess = success || errorPasswordNotSet;
|
||||
dispatch_semaphore_signal(sema);
|
||||
});
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
|
||||
// Undocumented sandbox setup routines.
|
||||
extern "C" int sandbox_init_with_parameters(const char* profile, uint64_t flags,
|
||||
const char* const parameters[], char** errorbuf);
|
||||
const char* const parameters[],
|
||||
char** errorbuf);
|
||||
extern "C" void sandbox_free_error(char* errorbuf);
|
||||
extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...);
|
||||
|
||||
|
@ -50,7 +51,8 @@ class OSXVersion {
|
|||
static void Get(int32_t& aMajor, int32_t& aMinor);
|
||||
|
||||
private:
|
||||
static void GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix);
|
||||
static void GetSystemVersion(int32_t& aMajor, int32_t& aMinor,
|
||||
int32_t& aBugFix);
|
||||
static bool mCached;
|
||||
static int32_t mOSXVersionMajor;
|
||||
static int32_t mOSXVersionMinor;
|
||||
|
@ -72,23 +74,26 @@ void OSXVersion::Get(int32_t& aMajor, int32_t& aMinor) {
|
|||
aMinor = mOSXVersionMinor;
|
||||
}
|
||||
|
||||
void OSXVersion::GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix) {
|
||||
void OSXVersion::GetSystemVersion(int32_t& aMajor, int32_t& aMinor,
|
||||
int32_t& aBugFix) {
|
||||
SInt32 major = 0, minor = 0, bugfix = 0;
|
||||
|
||||
CFURLRef url = CFURLCreateWithString(
|
||||
kCFAllocatorDefault, CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), NULL);
|
||||
kCFAllocatorDefault,
|
||||
CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"), NULL);
|
||||
CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
|
||||
CFReadStreamOpen(stream);
|
||||
CFDictionaryRef sysVersionPlist = (CFDictionaryRef)CFPropertyListCreateWithStream(
|
||||
kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL);
|
||||
CFDictionaryRef sysVersionPlist =
|
||||
(CFDictionaryRef)CFPropertyListCreateWithStream(
|
||||
kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL);
|
||||
CFReadStreamClose(stream);
|
||||
CFRelease(stream);
|
||||
CFRelease(url);
|
||||
|
||||
CFStringRef versionString =
|
||||
(CFStringRef)CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion"));
|
||||
CFArrayRef versions =
|
||||
CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, versionString, CFSTR("."));
|
||||
CFStringRef versionString = (CFStringRef)CFDictionaryGetValue(
|
||||
sysVersionPlist, CFSTR("ProductVersion"));
|
||||
CFArrayRef versions = CFStringCreateArrayBySeparatingStrings(
|
||||
kCFAllocatorDefault, versionString, CFSTR("."));
|
||||
CFIndex count = CFArrayGetCount(versions);
|
||||
if (count > 0) {
|
||||
CFStringRef component = (CFStringRef)CFArrayGetValueAtIndex(versions, 0);
|
||||
|
@ -188,22 +193,26 @@ void MacSandboxInfo::AppendAsParams(std::vector<std::string>& aParams) const {
|
|||
}
|
||||
}
|
||||
|
||||
void MacSandboxInfo::AppendStartupParam(std::vector<std::string>& aParams) const {
|
||||
void MacSandboxInfo::AppendStartupParam(
|
||||
std::vector<std::string>& aParams) const {
|
||||
aParams.push_back("-sbStartup");
|
||||
}
|
||||
|
||||
void MacSandboxInfo::AppendLoggingParam(std::vector<std::string>& aParams) const {
|
||||
void MacSandboxInfo::AppendLoggingParam(
|
||||
std::vector<std::string>& aParams) const {
|
||||
if (this->shouldLog) {
|
||||
aParams.push_back("-sbLogging");
|
||||
}
|
||||
}
|
||||
|
||||
void MacSandboxInfo::AppendAppPathParam(std::vector<std::string>& aParams) const {
|
||||
void MacSandboxInfo::AppendAppPathParam(
|
||||
std::vector<std::string>& aParams) const {
|
||||
aParams.push_back("-sbAppPath");
|
||||
aParams.push_back(this->appPath);
|
||||
}
|
||||
|
||||
void MacSandboxInfo::AppendPluginPathParam(std::vector<std::string>& aParams) const {
|
||||
void MacSandboxInfo::AppendPluginPathParam(
|
||||
std::vector<std::string>& aParams) const {
|
||||
aParams.push_back("-sbPluginPath");
|
||||
aParams.push_back(this->pluginPath);
|
||||
}
|
||||
|
@ -230,13 +239,15 @@ void MacSandboxInfo::AppendAudioParam(std::vector<std::string>& aParams) const {
|
|||
}
|
||||
}
|
||||
|
||||
void MacSandboxInfo::AppendWindowServerParam(std::vector<std::string>& aParams) const {
|
||||
void MacSandboxInfo::AppendWindowServerParam(
|
||||
std::vector<std::string>& aParams) const {
|
||||
if (this->hasWindowServer) {
|
||||
aParams.push_back("-sbAllowWindowServer");
|
||||
}
|
||||
}
|
||||
|
||||
void MacSandboxInfo::AppendReadPathParams(std::vector<std::string>& aParams) const {
|
||||
void MacSandboxInfo::AppendReadPathParams(
|
||||
std::vector<std::string>& aParams) const {
|
||||
if (!this->testingReadPath1.empty()) {
|
||||
aParams.push_back("-sbTestingReadPath");
|
||||
aParams.push_back(this->testingReadPath1.c_str());
|
||||
|
@ -256,7 +267,8 @@ void MacSandboxInfo::AppendReadPathParams(std::vector<std::string>& aParams) con
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void MacSandboxInfo::AppendDebugWriteDirParam(std::vector<std::string>& aParams) const {
|
||||
void MacSandboxInfo::AppendDebugWriteDirParam(
|
||||
std::vector<std::string>& aParams) const {
|
||||
if (!this->debugWriteDir.empty()) {
|
||||
aParams.push_back("-sbDebugWriteDir");
|
||||
aParams.push_back(this->debugWriteDir.c_str());
|
||||
|
@ -430,7 +442,8 @@ bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
|
|||
profile.append(SandboxPolicyContentAudioAddend);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Content sandbox disabled due to sandbox level setting\n");
|
||||
fprintf(stderr,
|
||||
"Content sandbox disabled due to sandbox level setting\n");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -465,7 +478,8 @@ bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
|
|||
params.push_back(nullptr);
|
||||
|
||||
char* errorbuf = NULL;
|
||||
int rv = sandbox_init_with_parameters(profile.c_str(), 0, params.data(), &errorbuf);
|
||||
int rv = sandbox_init_with_parameters(profile.c_str(), 0, params.data(),
|
||||
&errorbuf);
|
||||
if (rv) {
|
||||
if (errorbuf) {
|
||||
char* msg = NULL;
|
||||
|
@ -490,7 +504,8 @@ bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
|
|||
* command line arguments. Return false if any sandbox parameters needed
|
||||
* for early startup of the sandbox are not present in the arguments.
|
||||
*/
|
||||
bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) {
|
||||
bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv,
|
||||
MacSandboxInfo& aInfo) {
|
||||
// Ensure we find these paramaters in the command
|
||||
// line arguments. Return false if any are missing.
|
||||
bool foundSandboxLevel = false;
|
||||
|
@ -604,7 +619,8 @@ bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aI
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo,
|
||||
bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv,
|
||||
MacSandboxInfo& aInfo,
|
||||
bool aSandboxingKindRequired = true) {
|
||||
// Ensure we find these paramaters in the command
|
||||
// line arguments. Return false if any are missing.
|
||||
|
@ -650,11 +666,13 @@ bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aI
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) {
|
||||
bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv,
|
||||
MacSandboxInfo& aInfo) {
|
||||
return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
|
||||
}
|
||||
|
||||
bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) {
|
||||
bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv,
|
||||
MacSandboxInfo& aInfo) {
|
||||
// Ensure we find these paramaters in the command
|
||||
// line arguments. Return false if any are missing.
|
||||
bool foundAppPath = false;
|
||||
|
@ -725,7 +743,8 @@ bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aIn
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) {
|
||||
bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv,
|
||||
MacSandboxInfo& aInfo) {
|
||||
return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
|
||||
}
|
||||
|
||||
|
@ -733,8 +752,8 @@ bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo)
|
|||
* Returns true if no errors were encountered or if early sandbox startup is
|
||||
* not enabled for this process. Returns false if an error was encountered.
|
||||
*/
|
||||
bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc, char** aArgv,
|
||||
std::string& aErrorMessage) {
|
||||
bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc,
|
||||
char** aArgv, std::string& aErrorMessage) {
|
||||
bool earlyStartupEnabled = false;
|
||||
|
||||
// Check for the -sbStartup CLI parameter which
|
||||
|
@ -796,7 +815,9 @@ bool IsMacSandboxStarted() { return sandbox_check(getpid(), NULL, 0) == 1; }
|
|||
|
||||
#ifdef DEBUG
|
||||
// sandbox_check returns 1 if the specified process is sandboxed
|
||||
void AssertMacSandboxEnabled() { MOZ_ASSERT(sandbox_check(getpid(), NULL, 0) == 1); }
|
||||
void AssertMacSandboxEnabled() {
|
||||
MOZ_ASSERT(sandbox_check(getpid(), NULL, 0) == 1);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService)
|
||||
|
||||
nsParentalControlsService::nsParentalControlsService() : mEnabled(false) {
|
||||
mEnabled = CFPreferencesAppValueIsForced(CFSTR("restrictWeb"),
|
||||
CFSTR("com.apple.familycontrols.contentfilter"));
|
||||
mEnabled = CFPreferencesAppValueIsForced(
|
||||
CFSTR("restrictWeb"), CFSTR("com.apple.familycontrols.contentfilter"));
|
||||
}
|
||||
|
||||
nsParentalControlsService::~nsParentalControlsService() {}
|
||||
|
@ -37,13 +37,14 @@ nsParentalControlsService::GetLoggingEnabled(bool* aResult) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParentalControlsService::Log(int16_t aEntryType, bool blocked, nsIURI* aSource,
|
||||
nsIFile* aTarget) {
|
||||
nsParentalControlsService::Log(int16_t aEntryType, bool blocked,
|
||||
nsIURI* aSource, nsIFile* aTarget) {
|
||||
// silently drop on the floor
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParentalControlsService::IsAllowed(int16_t aAction, nsIURI* aUri, bool* _retval) {
|
||||
nsParentalControlsService::IsAllowed(int16_t aAction, nsIURI* aUri,
|
||||
bool* _retval) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ namespace mozilla {
|
|||
|
||||
nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
||||
struct proc_taskinfo pti;
|
||||
if ((unsigned long)proc_pidinfo(getpid(), PROC_PIDTASKINFO, 0, &pti, PROC_PIDTASKINFO_SIZE) <
|
||||
if ((unsigned long)proc_pidinfo(getpid(), PROC_PIDTASKINFO, 0, &pti,
|
||||
PROC_PIDTASKINFO_SIZE) <
|
||||
PROC_PIDTASKINFO_SIZE) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -39,16 +40,16 @@ nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
|||
mach_timebase_info_data_t timebase;
|
||||
GetTimeBase(&timebase);
|
||||
|
||||
*aResult = (pti.pti_total_user + pti.pti_total_system) * timebase.numer / timebase.denom /
|
||||
PR_NSEC_PER_MSEC;
|
||||
*aResult = (pti.pti_total_user + pti.pti_total_system) * timebase.numer /
|
||||
timebase.denom / PR_NSEC_PER_MSEC;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
||||
task_power_info_v2_data_t task_power_info;
|
||||
mach_msg_type_number_t count = TASK_POWER_INFO_V2_COUNT;
|
||||
kern_return_t kr =
|
||||
task_info(mach_task_self(), TASK_POWER_INFO_V2, (task_info_t)&task_power_info, &count);
|
||||
kern_return_t kr = task_info(mach_task_self(), TASK_POWER_INFO_V2,
|
||||
(task_info_t)&task_power_info, &count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -59,7 +60,8 @@ nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
|||
|
||||
int GetCycleTimeFrequencyMHz() { return 0; }
|
||||
|
||||
ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&& aRequests) {
|
||||
ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(
|
||||
nsTArray<ProcInfoRequest>&& aRequests) {
|
||||
ProcInfoPromise::ResolveOrRejectValue result;
|
||||
|
||||
HashMap<base::ProcessId, ProcInfo> gathered;
|
||||
|
@ -81,14 +83,16 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
|||
info.utilityActors = std::move(request.utilityInfo);
|
||||
|
||||
struct proc_taskinfo pti;
|
||||
if ((unsigned long)proc_pidinfo(request.pid, PROC_PIDTASKINFO, 0, &pti, PROC_PIDTASKINFO_SIZE) <
|
||||
if ((unsigned long)proc_pidinfo(request.pid, PROC_PIDTASKINFO, 0, &pti,
|
||||
PROC_PIDTASKINFO_SIZE) <
|
||||
PROC_PIDTASKINFO_SIZE) {
|
||||
// Can't read data for this process.
|
||||
// Probably either a sandboxing issue or a race condition, e.g.
|
||||
// the process has been just been killed. Regardless, skip process.
|
||||
continue;
|
||||
}
|
||||
info.cpuTime = (pti.pti_total_user + pti.pti_total_system) * timebase.numer / timebase.denom;
|
||||
info.cpuTime = (pti.pti_total_user + pti.pti_total_system) *
|
||||
timebase.numer / timebase.denom;
|
||||
|
||||
mach_port_t selectedTask;
|
||||
// If we did not get a task from a child process, we use mach_task_self()
|
||||
|
@ -102,7 +106,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
|||
// matches the value in the 'Memory' column of the Activity Monitor.
|
||||
task_vm_info_data_t task_vm_info;
|
||||
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
|
||||
kern_return_t kr = task_info(selectedTask, TASK_VM_INFO, (task_info_t)&task_vm_info, &count);
|
||||
kern_return_t kr = task_info(selectedTask, TASK_VM_INFO,
|
||||
(task_info_t)&task_vm_info, &count);
|
||||
info.memory = kr == KERN_SUCCESS ? task_vm_info.phys_footprint : 0;
|
||||
|
||||
// Now getting threads info
|
||||
|
@ -123,8 +128,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
|||
}
|
||||
|
||||
// Deallocate the thread list.
|
||||
// Note that this deallocation is entirely undocumented, so the following code is based
|
||||
// on guesswork and random examples found on the web.
|
||||
// Note that this deallocation is entirely undocumented, so the following
|
||||
// code is based on guesswork and random examples found on the web.
|
||||
auto guardThreadCount = MakeScopeExit([&] {
|
||||
if (threadList == nullptr) {
|
||||
return;
|
||||
|
@ -141,8 +146,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
|||
// Basic thread info.
|
||||
thread_extended_info_data_t threadInfoData;
|
||||
count = THREAD_EXTENDED_INFO_COUNT;
|
||||
kret =
|
||||
thread_info(threadList[i], THREAD_EXTENDED_INFO, (thread_info_t)&threadInfoData, &count);
|
||||
kret = thread_info(threadList[i], THREAD_EXTENDED_INFO,
|
||||
(thread_info_t)&threadInfoData, &count);
|
||||
if (kret != KERN_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
@ -150,8 +155,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
|||
// Getting the thread id.
|
||||
thread_identifier_info identifierInfo;
|
||||
count = THREAD_IDENTIFIER_INFO_COUNT;
|
||||
kret = thread_info(threadList[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&identifierInfo,
|
||||
&count);
|
||||
kret = thread_info(threadList[i], THREAD_IDENTIFIER_INFO,
|
||||
(thread_info_t)&identifierInfo, &count);
|
||||
if (kret != KERN_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
@ -162,7 +167,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
|||
result.SetReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return result;
|
||||
}
|
||||
thread->cpuTime = threadInfoData.pth_user_time + threadInfoData.pth_system_time;
|
||||
thread->cpuTime =
|
||||
threadInfoData.pth_user_time + threadInfoData.pth_system_time;
|
||||
thread->name.AssignASCII(threadInfoData.pth_name);
|
||||
thread->tid = identifierInfo.thread_id;
|
||||
}
|
||||
|
|
|
@ -18,21 +18,21 @@ using namespace mozilla;
|
|||
|
||||
nsresult nsMacRemoteClient::Init() { return NS_OK; }
|
||||
|
||||
nsresult nsMacRemoteClient::SendCommandLine(const char* aProgram, const char* aProfile,
|
||||
int32_t argc, char** argv,
|
||||
const char* aDesktopStartupID, char** aResponse,
|
||||
bool* aSucceeded) {
|
||||
nsresult nsMacRemoteClient::SendCommandLine(
|
||||
const char* aProgram, const char* aProfile, int32_t argc, char** argv,
|
||||
const char* aDesktopStartupID, char** aResponse, bool* aSucceeded) {
|
||||
mozilla::MacAutoreleasePool pool;
|
||||
|
||||
*aSucceeded = false;
|
||||
|
||||
nsString className;
|
||||
BuildClassName(aProgram, aProfile, className);
|
||||
NSString* serverNameString =
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
||||
length:className.Length()];
|
||||
NSString* serverNameString = [NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
||||
length:className.Length()];
|
||||
|
||||
CFMessagePortRef messageServer = CFMessagePortCreateRemote(0, (CFStringRef)serverNameString);
|
||||
CFMessagePortRef messageServer =
|
||||
CFMessagePortCreateRemote(0, (CFStringRef)serverNameString);
|
||||
|
||||
if (messageServer) {
|
||||
// Getting current process directory
|
||||
|
@ -48,7 +48,8 @@ nsresult nsMacRemoteClient::SendCommandLine(const char* aProgram, const char* aP
|
|||
|
||||
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:dict];
|
||||
|
||||
CFMessagePortSendRequest(messageServer, 0, (CFDataRef)data, 10.0, 0.0, NULL, NULL);
|
||||
CFMessagePortSendRequest(messageServer, 0, (CFDataRef)data, 10.0, 0.0, NULL,
|
||||
NULL);
|
||||
|
||||
CFMessagePortInvalidate(messageServer);
|
||||
CFRelease(messageServer);
|
||||
|
|
|
@ -22,20 +22,22 @@
|
|||
#include "nsXPCOM.h"
|
||||
#include "RemoteUtils.h"
|
||||
|
||||
CFDataRef messageServerCallback(CFMessagePortRef aLocal, int32_t aMsgid, CFDataRef aData,
|
||||
void* aInfo) {
|
||||
CFDataRef messageServerCallback(CFMessagePortRef aLocal, int32_t aMsgid,
|
||||
CFDataRef aData, void* aInfo) {
|
||||
// One of the clients submitted a structure.
|
||||
static_cast<nsMacRemoteServer*>(aInfo)->HandleCommandLine(aData);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// aData contains serialized Dictionary, which in turn contains command line arguments
|
||||
// aData contains serialized Dictionary, which in turn contains command line
|
||||
// arguments
|
||||
void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
|
||||
mozilla::MacAutoreleasePool pool;
|
||||
|
||||
if (aData) {
|
||||
NSDictionary* dict = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData];
|
||||
NSDictionary* dict =
|
||||
[NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData];
|
||||
if (dict && [dict isKindOfClass:[NSDictionary class]]) {
|
||||
NSArray* args = dict[@"args"];
|
||||
if (!args) {
|
||||
|
@ -54,7 +56,8 @@ void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
|
|||
argv[i] = arg;
|
||||
}
|
||||
|
||||
nsresult rv = cmdLine->Init(argc, argv, nullptr, nsICommandLine::STATE_REMOTE_AUTO);
|
||||
nsresult rv =
|
||||
cmdLine->Init(argc, argv, nullptr, nsICommandLine::STATE_REMOTE_AUTO);
|
||||
|
||||
// Cleaning up C array.
|
||||
delete[] argv;
|
||||
|
@ -75,21 +78,22 @@ void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
|
|||
}
|
||||
}
|
||||
|
||||
nsresult nsMacRemoteServer::Startup(const char* aAppName, const char* aProfileName) {
|
||||
nsresult nsMacRemoteServer::Startup(const char* aAppName,
|
||||
const char* aProfileName) {
|
||||
// This is the first instance ever.
|
||||
// Let's register a notification listener here,
|
||||
// In case future instances would want to notify us about command line arguments
|
||||
// passed to them. Note, that if mozilla process is restarting, we still need to
|
||||
// register for notifications.
|
||||
// In case future instances would want to notify us about command line
|
||||
// arguments passed to them. Note, that if mozilla process is restarting, we
|
||||
// still need to register for notifications.
|
||||
|
||||
mozilla::MacAutoreleasePool pool;
|
||||
|
||||
nsString className;
|
||||
BuildClassName(aAppName, aProfileName, className);
|
||||
|
||||
NSString* serverNameString =
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
||||
length:className.Length()];
|
||||
NSString* serverNameString = [NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
||||
length:className.Length()];
|
||||
|
||||
CFMessagePortContext context;
|
||||
context.copyDescription = NULL;
|
||||
|
@ -97,8 +101,9 @@ nsresult nsMacRemoteServer::Startup(const char* aAppName, const char* aProfileNa
|
|||
context.release = NULL;
|
||||
context.retain = NULL;
|
||||
context.version = NULL;
|
||||
mMessageServer = CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString,
|
||||
messageServerCallback, &context, NULL);
|
||||
mMessageServer =
|
||||
CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString,
|
||||
messageServerCallback, &context, NULL);
|
||||
if (!mMessageServer) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ static bool RestartApplication() {
|
|||
// Set spawn attributes.
|
||||
size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]);
|
||||
size_t attr_ocount = 0;
|
||||
if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types, &attr_ocount) != 0 ||
|
||||
if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types,
|
||||
&attr_ocount) != 0 ||
|
||||
attr_ocount != attr_count) {
|
||||
posix_spawnattr_destroy(&spawnattr);
|
||||
return false;
|
||||
|
@ -89,7 +90,8 @@ static bool RestartApplication() {
|
|||
gUI = self;
|
||||
[mWindow center];
|
||||
|
||||
[mWindow setTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]];
|
||||
[mWindow setTitle:[[NSBundle mainBundle]
|
||||
objectForInfoDictionaryKey:@"CFBundleName"]];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
|
@ -189,7 +191,9 @@ static bool RestartApplication() {
|
|||
[self setView:mErrorView animate:NO];
|
||||
|
||||
[mErrorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
|
||||
[self setStringFitVertically:mErrorLabel string:NSSTR(message) resizeWindow:YES];
|
||||
[self setStringFitVertically:mErrorLabel
|
||||
string:NSSTR(message)
|
||||
resizeWindow:YES];
|
||||
[mErrorCloseButton setTitle:Str(ST_OK)];
|
||||
|
||||
[mErrorCloseButton setKeyEquivalent:@"\r"];
|
||||
|
@ -199,19 +203,22 @@ static bool RestartApplication() {
|
|||
|
||||
- (void)showReportInfo {
|
||||
NSDictionary* boldAttr = @{
|
||||
NSFontAttributeName : [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]],
|
||||
NSFontAttributeName :
|
||||
[NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]],
|
||||
NSForegroundColorAttributeName : NSColor.textColor,
|
||||
};
|
||||
NSDictionary* normalAttr = @{
|
||||
NSFontAttributeName : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]],
|
||||
NSFontAttributeName :
|
||||
[NSFont systemFontOfSize:[NSFont smallSystemFontSize]],
|
||||
NSForegroundColorAttributeName : NSColor.textColor,
|
||||
};
|
||||
|
||||
[mViewReportTextView setString:@""];
|
||||
for (Json::ValueConstIterator iter = gQueryParameters.begin(); iter != gQueryParameters.end();
|
||||
++iter) {
|
||||
NSAttributedString* key = [[NSAttributedString alloc] initWithString:NSSTR(iter.name() + ": ")
|
||||
attributes:boldAttr];
|
||||
for (Json::ValueConstIterator iter = gQueryParameters.begin();
|
||||
iter != gQueryParameters.end(); ++iter) {
|
||||
NSAttributedString* key =
|
||||
[[NSAttributedString alloc] initWithString:NSSTR(iter.name() + ": ")
|
||||
attributes:boldAttr];
|
||||
string str;
|
||||
if (iter->isString()) {
|
||||
str = iter->asString();
|
||||
|
@ -220,24 +227,27 @@ static bool RestartApplication() {
|
|||
builder["indentation"] = "";
|
||||
str = writeString(builder, *iter);
|
||||
}
|
||||
NSAttributedString* value = [[NSAttributedString alloc] initWithString:NSSTR(str + "\n")
|
||||
attributes:normalAttr];
|
||||
NSAttributedString* value =
|
||||
[[NSAttributedString alloc] initWithString:NSSTR(str + "\n")
|
||||
attributes:normalAttr];
|
||||
[[mViewReportTextView textStorage] appendAttributedString:key];
|
||||
[[mViewReportTextView textStorage] appendAttributedString:value];
|
||||
[key release];
|
||||
[value release];
|
||||
}
|
||||
|
||||
NSAttributedString* extra =
|
||||
[[NSAttributedString alloc] initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
|
||||
attributes:normalAttr];
|
||||
NSAttributedString* extra = [[NSAttributedString alloc]
|
||||
initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
|
||||
attributes:normalAttr];
|
||||
[[mViewReportTextView textStorage] appendAttributedString:extra];
|
||||
[extra release];
|
||||
}
|
||||
|
||||
- (void)maybeSubmitReport {
|
||||
if ([mSubmitReportButton state] == NSOnState) {
|
||||
[self setStringFitVertically:mProgressText string:Str(ST_REPORTDURINGSUBMIT) resizeWindow:YES];
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_REPORTDURINGSUBMIT)
|
||||
resizeWindow:YES];
|
||||
// disable all the controls
|
||||
[self enableControls:NO];
|
||||
[mSubmitReportButton setEnabled:NO];
|
||||
|
@ -258,7 +268,8 @@ static bool RestartApplication() {
|
|||
- (IBAction)submitReportClicked:(id)sender {
|
||||
[self updateSubmit];
|
||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
[userDefaults setBool:([mSubmitReportButton state] == NSOnState) forKey:@"submitReport"];
|
||||
[userDefaults setBool:([mSubmitReportButton state] == NSOnState)
|
||||
forKey:@"submitReport"];
|
||||
[userDefaults synchronize];
|
||||
}
|
||||
|
||||
|
@ -288,14 +299,16 @@ static bool RestartApplication() {
|
|||
- (IBAction)includeURLClicked:(id)sender {
|
||||
[self updateURL];
|
||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
||||
[userDefaults setBool:([mIncludeURLButton state] == NSOnState) forKey:@"IncludeURL"];
|
||||
[userDefaults setBool:([mIncludeURLButton state] == NSOnState)
|
||||
forKey:@"IncludeURL"];
|
||||
[userDefaults synchronize];
|
||||
}
|
||||
|
||||
- (void)textDidChange:(NSNotification*)aNotification {
|
||||
// update comment parameter
|
||||
if ([[[mCommentText textStorage] mutableString] length] > 0)
|
||||
gQueryParameters["Comments"] = [[[mCommentText textStorage] mutableString] UTF8String];
|
||||
gQueryParameters["Comments"] =
|
||||
[[[mCommentText textStorage] mutableString] UTF8String];
|
||||
else
|
||||
gQueryParameters.removeMember("Comments");
|
||||
}
|
||||
|
@ -308,7 +321,8 @@ static bool RestartApplication() {
|
|||
if (([[aTextView string] lengthOfBytesUsingEncoding:NSUTF8StringEncoding] +
|
||||
[replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] -
|
||||
[[[aTextView string] substringWithRange:affectedCharRange]
|
||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) > MAX_COMMENT_LENGTH) {
|
||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) >
|
||||
MAX_COMMENT_LENGTH) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
|
@ -331,8 +345,8 @@ static bool RestartApplication() {
|
|||
if (gRestartArgs.size() == 0) {
|
||||
[mRestartButton removeFromSuperview];
|
||||
if (!gRTLlayout) {
|
||||
closeFrame.origin.x =
|
||||
restartFrame.origin.x + (restartFrame.size.width - closeFrame.size.width);
|
||||
closeFrame.origin.x = restartFrame.origin.x +
|
||||
(restartFrame.size.width - closeFrame.size.width);
|
||||
} else {
|
||||
closeFrame.origin.x = restartFrame.origin.x;
|
||||
}
|
||||
|
@ -357,7 +371,8 @@ static bool RestartApplication() {
|
|||
// possibly resize window if both buttons no longer fit
|
||||
// leave 20 px from either side of the window, and 12 px
|
||||
// between the buttons
|
||||
float neededWidth = closeFrame.size.width + restartFrame.size.width + 2 * 20 + 12;
|
||||
float neededWidth =
|
||||
closeFrame.size.width + restartFrame.size.width + 2 * 20 + 12;
|
||||
|
||||
if (neededWidth > windowFrame.size.width) {
|
||||
windowFrame.size.width = neededWidth;
|
||||
|
@ -379,7 +394,8 @@ static bool RestartApplication() {
|
|||
[checkbox setFrame:frame];
|
||||
}
|
||||
// keep existing spacing on left side, + 20 px spare on right
|
||||
float neededWidth = frame.origin.x + checkbox.intrinsicContentSize.width + 20;
|
||||
float neededWidth =
|
||||
frame.origin.x + checkbox.intrinsicContentSize.width + 20;
|
||||
if (neededWidth > windowFrame.size.width) {
|
||||
windowFrame.size.width = neededWidth;
|
||||
[mWindow setFrame:windowFrame display:true animate:NO];
|
||||
|
@ -395,8 +411,9 @@ static bool RestartApplication() {
|
|||
// now pin all the controls (except quit/submit) in place,
|
||||
// if we lengthen the window after this, it's just to lengthen
|
||||
// the progress text, so nothing above that text should move.
|
||||
NSView* views[] = {mSubmitReportButton, mViewReportButton, mCommentScrollView,
|
||||
mIncludeURLButton, mProgressIndicator, mProgressText};
|
||||
NSView* views[] = {mSubmitReportButton, mViewReportButton,
|
||||
mCommentScrollView, mIncludeURLButton,
|
||||
mProgressIndicator, mProgressText};
|
||||
for (auto view : views) {
|
||||
[view setAutoresizingMask:NSViewMinYMargin];
|
||||
}
|
||||
|
@ -454,7 +471,9 @@ static bool RestartApplication() {
|
|||
|
||||
- (void)updateSubmit {
|
||||
if ([mSubmitReportButton state] == NSOnState) {
|
||||
[self setStringFitVertically:mProgressText string:Str(ST_REPORTPRESUBMIT) resizeWindow:YES];
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_REPORTPRESUBMIT)
|
||||
resizeWindow:YES];
|
||||
[mProgressText setHidden:NO];
|
||||
// enable all the controls
|
||||
[self enableControls:YES];
|
||||
|
@ -490,18 +509,24 @@ static bool RestartApplication() {
|
|||
[NSApp terminate:self];
|
||||
}
|
||||
|
||||
[self setStringFitVertically:mProgressText string:Str(ST_SUBMITFAILED) resizeWindow:YES];
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_SUBMITFAILED)
|
||||
resizeWindow:YES];
|
||||
// quit after 5 seconds
|
||||
[self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0];
|
||||
[self performSelector:@selector(closeMeDown:)
|
||||
withObject:nil
|
||||
afterDelay:5.0];
|
||||
}
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(uploadThread:) toTarget:self withObject:mPost];
|
||||
[NSThread detachNewThreadSelector:@selector(uploadThread:)
|
||||
toTarget:self
|
||||
withObject:mPost];
|
||||
}
|
||||
|
||||
- (bool)setupPost {
|
||||
NSURL* url =
|
||||
[NSURL URLWithString:[NSSTR(gSendURL)
|
||||
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
NSURL* url = [NSURL
|
||||
URLWithString:[NSSTR(gSendURL) stringByAddingPercentEscapesUsingEncoding:
|
||||
NSUTF8StringEncoding]];
|
||||
if (!url) return false;
|
||||
|
||||
mPost = [[HTTPMultipartUpload alloc] initWithURL:url];
|
||||
|
@ -514,7 +539,8 @@ static bool RestartApplication() {
|
|||
Json::StreamWriterBuilder builder;
|
||||
builder["indentation"] = "";
|
||||
string output = writeString(builder, gQueryParameters).append("\r\n");
|
||||
NSMutableString* parameters = [[NSMutableString alloc] initWithUTF8String:output.c_str()];
|
||||
NSMutableString* parameters =
|
||||
[[NSMutableString alloc] initWithUTF8String:output.c_str()];
|
||||
|
||||
[mPost setParameters:parameters];
|
||||
[parameters release];
|
||||
|
@ -535,7 +561,8 @@ static bool RestartApplication() {
|
|||
// if data is nil, we probably logged an error in uploadThread
|
||||
if (data != nil && response != nil) {
|
||||
ostringstream message;
|
||||
message << "Crash report submission failed: server returned status " << [response statusCode];
|
||||
message << "Crash report submission failed: server returned status "
|
||||
<< [response statusCode];
|
||||
LogMessage(message.str());
|
||||
}
|
||||
} else {
|
||||
|
@ -563,9 +590,13 @@ static bool RestartApplication() {
|
|||
|
||||
[mProgressIndicator stopAnimation:self];
|
||||
if (success) {
|
||||
[self setStringFitVertically:mProgressText string:Str(ST_REPORTSUBMITSUCCESS) resizeWindow:YES];
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_REPORTSUBMITSUCCESS)
|
||||
resizeWindow:YES];
|
||||
} else {
|
||||
[self setStringFitVertically:mProgressText string:Str(ST_SUBMITFAILED) resizeWindow:YES];
|
||||
[self setStringFitVertically:mProgressText
|
||||
string:Str(ST_SUBMITFAILED)
|
||||
resizeWindow:YES];
|
||||
}
|
||||
// quit after 5 seconds
|
||||
[self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0];
|
||||
|
@ -582,13 +613,16 @@ static bool RestartApplication() {
|
|||
LogMessage("Crash report submission failed: " + message);
|
||||
}
|
||||
|
||||
[self performSelectorOnMainThread:@selector(uploadComplete:) withObject:data waitUntilDone:YES];
|
||||
[self performSelectorOnMainThread:@selector(uploadComplete:)
|
||||
withObject:data
|
||||
waitUntilDone:YES];
|
||||
|
||||
[autoreleasepool release];
|
||||
}
|
||||
|
||||
// to get auto-quit when we close the window
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication {
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:
|
||||
(NSApplication*)theApplication {
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -621,10 +655,12 @@ static bool RestartApplication() {
|
|||
|
||||
- (void)setPlaceholder:(NSString*)placeholder {
|
||||
NSColor* txtColor = [NSColor disabledControlTextColor];
|
||||
NSDictionary* txtDict =
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, nil];
|
||||
mPlaceHolderString = [[NSMutableAttributedString alloc] initWithString:placeholder
|
||||
attributes:txtDict];
|
||||
NSDictionary* txtDict = [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName,
|
||||
nil];
|
||||
mPlaceHolderString =
|
||||
[[NSMutableAttributedString alloc] initWithString:placeholder
|
||||
attributes:txtDict];
|
||||
if (gRTLlayout)
|
||||
[mPlaceHolderString setAlignment:NSTextAlignmentRight
|
||||
range:NSMakeRange(0, [placeholder length])];
|
||||
|
@ -649,9 +685,11 @@ static bool RestartApplication() {
|
|||
txtColor = [NSColor textColor];
|
||||
else
|
||||
txtColor = [NSColor disabledControlTextColor];
|
||||
NSDictionary* txtDict =
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, nil];
|
||||
colorString = [[NSAttributedString alloc] initWithString:[self string] attributes:txtDict];
|
||||
NSDictionary* txtDict = [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName,
|
||||
nil];
|
||||
colorString = [[NSAttributedString alloc] initWithString:[self string]
|
||||
attributes:txtDict];
|
||||
[[self textStorage] setAttributedString:colorString];
|
||||
[self setInsertionPointColor:txtColor];
|
||||
[colorString release];
|
||||
|
@ -671,14 +709,16 @@ bool UIInit() {
|
|||
gMainPool = [[NSAutoreleasePool alloc] init];
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes") gRTLlayout = true;
|
||||
if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes")
|
||||
gRTLlayout = true;
|
||||
|
||||
if (gAutoSubmit) {
|
||||
gUI = [[CrashReporterUI alloc] init];
|
||||
} else {
|
||||
[[NSBundle mainBundle] loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
|
||||
owner:NSApp
|
||||
topLevelObjects:nil];
|
||||
[[NSBundle mainBundle]
|
||||
loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
|
||||
owner:NSApp
|
||||
topLevelObjects:nil];
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -724,9 +764,10 @@ bool UIGetIniPath(string& path) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool UIGetSettingsPath(const string& vendor, const string& product, string& settingsPath) {
|
||||
NSArray* paths =
|
||||
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
bool UIGetSettingsPath(const string& vendor, const string& product,
|
||||
string& settingsPath) {
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(
|
||||
NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
NSString* destPath = [paths firstObject];
|
||||
|
||||
// Note that MacOS ignores the vendor when creating the profile hierarchy -
|
||||
|
@ -751,10 +792,12 @@ bool UIMoveFile(const string& file, const string& newfile) {
|
|||
if (errno != EXDEV) return false;
|
||||
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
NSString* source = [fileManager stringWithFileSystemRepresentation:file.c_str()
|
||||
length:file.length()];
|
||||
NSString* dest = [fileManager stringWithFileSystemRepresentation:newfile.c_str()
|
||||
length:newfile.length()];
|
||||
NSString* source =
|
||||
[fileManager stringWithFileSystemRepresentation:file.c_str()
|
||||
length:file.length()];
|
||||
NSString* dest =
|
||||
[fileManager stringWithFileSystemRepresentation:newfile.c_str()
|
||||
length:newfile.length()];
|
||||
if (!source || !dest) return false;
|
||||
|
||||
[fileManager moveItemAtPath:source toPath:dest error:NULL];
|
||||
|
|
|
@ -55,7 +55,8 @@ bool IsBinaryArmExecutable(const char* executablePath) {
|
|||
bool isArmExecutable = false;
|
||||
|
||||
CFURLRef url = ::CFURLCreateFromFileSystemRepresentation(
|
||||
kCFAllocatorDefault, (const UInt8*)executablePath, strlen(executablePath), false);
|
||||
kCFAllocatorDefault, (const UInt8*)executablePath, strlen(executablePath),
|
||||
false);
|
||||
if (!url) {
|
||||
return false;
|
||||
}
|
||||
|
@ -68,7 +69,8 @@ bool IsBinaryArmExecutable(const char* executablePath) {
|
|||
|
||||
CFIndex archCount = ::CFArrayGetCount(archs);
|
||||
for (CFIndex i = 0; i < archCount; i++) {
|
||||
CFNumberRef currentArch = static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(archs, i));
|
||||
CFNumberRef currentArch =
|
||||
static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(archs, i));
|
||||
int currentArchInt = 0;
|
||||
if (!::CFNumberGetValue(currentArch, kCFNumberIntType, ¤tArchInt)) {
|
||||
continue;
|
||||
|
@ -161,7 +163,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
|
|||
// Launch helper to perform post processing for the update; this is the Mac
|
||||
// analogue of LaunchWinPostProcess (PostUpdateWin).
|
||||
NSString* iniPath = [NSString stringWithUTF8String:aAppBundle];
|
||||
iniPath = [iniPath stringByAppendingPathComponent:@"Contents/Resources/updater.ini"];
|
||||
iniPath = [iniPath
|
||||
stringByAppendingPathComponent:@"Contents/Resources/updater.ini"];
|
||||
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
if (![fileManager fileExistsAtPath:iniPath]) {
|
||||
|
@ -171,8 +174,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
|
|||
|
||||
int readResult;
|
||||
mozilla::UniquePtr<char[]> values[2];
|
||||
readResult =
|
||||
ReadStrings([iniPath UTF8String], "ExeRelPath\0ExeArg\0", 2, values, "PostUpdateMac");
|
||||
readResult = ReadStrings([iniPath UTF8String], "ExeRelPath\0ExeArg\0", 2,
|
||||
values, "PostUpdateMac");
|
||||
if (readResult) {
|
||||
return;
|
||||
}
|
||||
|
@ -194,7 +197,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
|
|||
exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath];
|
||||
|
||||
mozilla::UniquePtr<char[]> optVal;
|
||||
readResult = ReadStrings([iniPath UTF8String], "ExeAsync\0", 1, &optVal, "PostUpdateMac");
|
||||
readResult = ReadStrings([iniPath UTF8String], "ExeAsync\0", 1, &optVal,
|
||||
"PostUpdateMac");
|
||||
|
||||
NSTask* task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:exeFullPath];
|
||||
|
@ -223,8 +227,10 @@ id ConnectToUpdateServer() {
|
|||
updateServer = (id)[NSConnection
|
||||
rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server"
|
||||
host:nil
|
||||
usingNameServer:[NSSocketPortNameServer sharedInstance]];
|
||||
if (!updateServer || ![updateServer respondsToSelector:@selector(abort)] ||
|
||||
usingNameServer:[NSSocketPortNameServer
|
||||
sharedInstance]];
|
||||
if (!updateServer ||
|
||||
![updateServer respondsToSelector:@selector(abort)] ||
|
||||
![updateServer respondsToSelector:@selector(getArguments)] ||
|
||||
![updateServer respondsToSelector:@selector(shutdown)]) {
|
||||
NSLog(@"Server doesn't exist or doesn't provide correct selectors.");
|
||||
|
@ -262,9 +268,13 @@ void CleanupElevatedMacUpdate(bool aFailureOccurred) {
|
|||
}
|
||||
|
||||
NSFileManager* manager = [NSFileManager defaultManager];
|
||||
[manager removeItemAtPath:@"/Library/PrivilegedHelperTools/org.mozilla.updater" error:nil];
|
||||
[manager removeItemAtPath:@"/Library/LaunchDaemons/org.mozilla.updater.plist" error:nil];
|
||||
const char* launchctlArgs[] = {"/bin/launchctl", "remove", "org.mozilla.updater"};
|
||||
[manager
|
||||
removeItemAtPath:@"/Library/PrivilegedHelperTools/org.mozilla.updater"
|
||||
error:nil];
|
||||
[manager removeItemAtPath:@"/Library/LaunchDaemons/org.mozilla.updater.plist"
|
||||
error:nil];
|
||||
const char* launchctlArgs[] = {"/bin/launchctl", "remove",
|
||||
"org.mozilla.updater"};
|
||||
// The following call will terminate the current process due to the "remove"
|
||||
// argument in launchctlArgs.
|
||||
LaunchChild(3, launchctlArgs);
|
||||
|
@ -282,13 +292,15 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
|
|||
}
|
||||
|
||||
@try {
|
||||
NSArray* updaterArguments = [updateServer performSelector:@selector(getArguments)];
|
||||
NSArray* updaterArguments =
|
||||
[updateServer performSelector:@selector(getArguments)];
|
||||
*argc = [updaterArguments count];
|
||||
char** tempArgv = (char**)malloc(sizeof(char*) * (*argc));
|
||||
for (int i = 0; i < *argc; i++) {
|
||||
int argLen = [[updaterArguments objectAtIndex:i] length] + 1;
|
||||
tempArgv[i] = (char*)malloc(argLen);
|
||||
strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String], argLen);
|
||||
strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String],
|
||||
argLen);
|
||||
}
|
||||
*argv = tempArgv;
|
||||
} @catch (NSException* e) {
|
||||
|
@ -334,7 +346,8 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
|
|||
|
||||
- (BOOL)runServer {
|
||||
NSPort* serverPort = [NSSocketPort port];
|
||||
NSConnection* server = [NSConnection connectionWithReceivePort:serverPort sendPort:serverPort];
|
||||
NSConnection* server = [NSConnection connectionWithReceivePort:serverPort
|
||||
sendPort:serverPort];
|
||||
[server setRootObject:self];
|
||||
if ([server registerName:@"org.mozilla.updater.server"
|
||||
withNameServer:[NSSocketPortNameServer sharedInstance]] == NO) {
|
||||
|
@ -343,8 +356,9 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
|
|||
return NO;
|
||||
}
|
||||
|
||||
while ([self shouldKeepRunning] && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate distantFuture]])
|
||||
while ([self shouldKeepRunning] &&
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate distantFuture]])
|
||||
;
|
||||
return ![self wasAborted];
|
||||
}
|
||||
|
@ -394,9 +408,11 @@ bool IsOwnedByGroupAdmin(const char* aAppBundle) {
|
|||
NSString* appDir = [NSString stringWithUTF8String:aAppBundle];
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSDictionary* attributes = [fileManager attributesOfItemAtPath:appDir error:nil];
|
||||
NSDictionary* attributes = [fileManager attributesOfItemAtPath:appDir
|
||||
error:nil];
|
||||
bool isOwnedByAdmin = false;
|
||||
if (attributes && [[attributes valueForKey:NSFileGroupOwnerAccountID] intValue] == 80) {
|
||||
if (attributes &&
|
||||
[[attributes valueForKey:NSFileGroupOwnerAccountID] intValue] == 80) {
|
||||
isOwnedByAdmin = true;
|
||||
}
|
||||
return isOwnedByAdmin;
|
||||
|
@ -425,13 +441,14 @@ void SetGroupOwnershipAndPermissions(const char* aAppBundle) {
|
|||
return;
|
||||
}
|
||||
|
||||
NSArray* permKeys =
|
||||
[NSArray arrayWithObjects:NSFileGroupOwnerAccountID, NSFilePosixPermissions, nil];
|
||||
NSArray* permKeys = [NSArray
|
||||
arrayWithObjects:NSFileGroupOwnerAccountID, NSFilePosixPermissions, nil];
|
||||
// For all descendants of Firefox.app, set group ownership to 80 ("admin") and
|
||||
// ensure write permission for the group.
|
||||
for (NSString* currPath in paths) {
|
||||
NSString* child = [appDir stringByAppendingPathComponent:currPath];
|
||||
NSDictionary* oldAttributes = [fileManager attributesOfItemAtPath:child error:&error];
|
||||
NSDictionary* oldAttributes = [fileManager attributesOfItemAtPath:child
|
||||
error:&error];
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
@ -440,12 +457,20 @@ void SetGroupOwnershipAndPermissions(const char* aAppBundle) {
|
|||
if ([oldAttributes fileType] == NSFileTypeSymbolicLink) {
|
||||
continue;
|
||||
}
|
||||
NSNumber* oldPerms = (NSNumber*)[oldAttributes valueForKey:NSFilePosixPermissions];
|
||||
NSNumber* oldPerms =
|
||||
(NSNumber*)[oldAttributes valueForKey:NSFilePosixPermissions];
|
||||
NSArray* permObjects = [NSArray
|
||||
arrayWithObjects:[NSNumber numberWithUnsignedLong:80],
|
||||
[NSNumber numberWithUnsignedLong:[oldPerms shortValue] | 020], nil];
|
||||
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:permObjects forKeys:permKeys];
|
||||
if (![fileManager setAttributes:attributes ofItemAtPath:child error:&error] || error) {
|
||||
[NSNumber
|
||||
numberWithUnsignedLong:[oldPerms shortValue] |
|
||||
020],
|
||||
nil];
|
||||
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:permObjects
|
||||
forKeys:permKeys];
|
||||
if (![fileManager setAttributes:attributes
|
||||
ofItemAtPath:child
|
||||
error:&error] ||
|
||||
error) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -483,7 +508,9 @@ bool PerformInstallationFromDMG(int argc, char** argv) {
|
|||
}
|
||||
NSString* bundlePath = [NSString stringWithUTF8String:argv[2]];
|
||||
NSString* destPath = [NSString stringWithUTF8String:argv[3]];
|
||||
if ([[NSFileManager defaultManager] copyItemAtPath:bundlePath toPath:destPath error:nil]) {
|
||||
if ([[NSFileManager defaultManager] copyItemAtPath:bundlePath
|
||||
toPath:destPath
|
||||
error:nil]) {
|
||||
RegisterAppWithLaunchServices(destPath);
|
||||
StripQuarantineBit(destPath);
|
||||
return true;
|
||||
|
|
|
@ -32,12 +32,14 @@ static const char* sUpdatePath;
|
|||
NSWindow* w = [progressBar window];
|
||||
|
||||
[w setTitle:[NSString stringWithUTF8String:sLabels.title.get()]];
|
||||
[progressTextField setStringValue:[NSString stringWithUTF8String:sLabels.info.get()]];
|
||||
[progressTextField
|
||||
setStringValue:[NSString stringWithUTF8String:sLabels.info.get()]];
|
||||
|
||||
NSRect origTextFrame = [progressTextField frame];
|
||||
[progressTextField sizeToFit];
|
||||
|
||||
int widthAdjust = progressTextField.frame.size.width - origTextFrame.size.width;
|
||||
int widthAdjust =
|
||||
progressTextField.frame.size.width - origTextFrame.size.width;
|
||||
|
||||
if (widthAdjust > 0) {
|
||||
NSRect f;
|
||||
|
@ -118,7 +120,9 @@ int ShowProgressUI(bool indeterminate) {
|
|||
|
||||
sIndeterminate = indeterminate;
|
||||
[NSApplication sharedApplication];
|
||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:nil];
|
||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
|
||||
owner:NSApp
|
||||
topLevelObjects:nil];
|
||||
[NSApp run];
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -34,8 +34,8 @@ class nsOSXSystemProxySettings : public nsISystemProxySettings {
|
|||
nsresult GetAutoconfigURL(nsAutoCString& aResult) const;
|
||||
|
||||
// Find the SystemConfiguration proxy & port for a given URI
|
||||
nsresult FindSCProxyPort(const nsACString& aScheme, nsACString& aResultHost, int32_t& aResultPort,
|
||||
bool& aResultSocksProxy);
|
||||
nsresult FindSCProxyPort(const nsACString& aScheme, nsACString& aResultHost,
|
||||
int32_t& aResultPort, bool& aResultSocksProxy);
|
||||
|
||||
// is host:port on the proxy exception list?
|
||||
bool IsInExceptionList(const nsACString& aHost) const;
|
||||
|
@ -69,22 +69,26 @@ nsOSXSystemProxySettings::GetMainThreadOnly(bool* aMainThreadOnly) {
|
|||
}
|
||||
|
||||
// Mapping of URI schemes to SystemConfiguration keys
|
||||
const nsOSXSystemProxySettings::SchemeMapping nsOSXSystemProxySettings::gSchemeMappingList[] = {
|
||||
{"http", kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort,
|
||||
false},
|
||||
{"https", kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort,
|
||||
false},
|
||||
{"ftp", kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy, kSCPropNetProxiesFTPPort, false},
|
||||
{"socks", kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort,
|
||||
true},
|
||||
{NULL, NULL, NULL, NULL, false},
|
||||
const nsOSXSystemProxySettings::SchemeMapping
|
||||
nsOSXSystemProxySettings::gSchemeMappingList[] = {
|
||||
{"http", kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy,
|
||||
kSCPropNetProxiesHTTPPort, false},
|
||||
{"https", kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy,
|
||||
kSCPropNetProxiesHTTPSPort, false},
|
||||
{"ftp", kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy,
|
||||
kSCPropNetProxiesFTPPort, false},
|
||||
{"socks", kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy,
|
||||
kSCPropNetProxiesSOCKSPort, true},
|
||||
{NULL, NULL, NULL, NULL, false},
|
||||
};
|
||||
|
||||
static void ProxyHasChangedWrapper(SCDynamicStoreRef aStore, CFArrayRef aChangedKeys, void* aInfo) {
|
||||
static void ProxyHasChangedWrapper(SCDynamicStoreRef aStore,
|
||||
CFArrayRef aChangedKeys, void* aInfo) {
|
||||
static_cast<nsOSXSystemProxySettings*>(aInfo)->ProxyHasChanged();
|
||||
}
|
||||
|
||||
nsOSXSystemProxySettings::nsOSXSystemProxySettings() : mSystemDynamicStore(NULL), mProxyDict(NULL) {
|
||||
nsOSXSystemProxySettings::nsOSXSystemProxySettings()
|
||||
: mSystemDynamicStore(NULL), mProxyDict(NULL) {
|
||||
mContext = (SCDynamicStoreContext){0, this, NULL, NULL, NULL};
|
||||
}
|
||||
|
||||
|
@ -94,15 +98,16 @@ nsresult nsOSXSystemProxySettings::Init() {
|
|||
// Register for notification of proxy setting changes
|
||||
// See:
|
||||
// http://developer.apple.com/documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/chapter_4_section_5.html
|
||||
mSystemDynamicStore =
|
||||
SCDynamicStoreCreate(NULL, CFSTR("Mozilla"), ProxyHasChangedWrapper, &mContext);
|
||||
mSystemDynamicStore = SCDynamicStoreCreate(NULL, CFSTR("Mozilla"),
|
||||
ProxyHasChangedWrapper, &mContext);
|
||||
if (!mSystemDynamicStore) return NS_ERROR_FAILURE;
|
||||
|
||||
// Set up the store to monitor any changes to the proxies
|
||||
CFStringRef proxiesKey = SCDynamicStoreKeyCreateProxies(NULL);
|
||||
if (!proxiesKey) return NS_ERROR_FAILURE;
|
||||
|
||||
CFArrayRef keyArray = CFArrayCreate(NULL, (const void**)(&proxiesKey), 1, &kCFTypeArrayCallBacks);
|
||||
CFArrayRef keyArray = CFArrayCreate(NULL, (const void**)(&proxiesKey), 1,
|
||||
&kCFTypeArrayCallBacks);
|
||||
CFRelease(proxiesKey);
|
||||
if (!keyArray) return NS_ERROR_FAILURE;
|
||||
|
||||
|
@ -113,7 +118,8 @@ nsresult nsOSXSystemProxySettings::Init() {
|
|||
CFRunLoopSourceRef storeRLSource =
|
||||
SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
|
||||
if (!storeRLSource) return NS_ERROR_FAILURE;
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLSource,
|
||||
kCFRunLoopCommonModes);
|
||||
CFRelease(storeRLSource);
|
||||
|
||||
// Load the initial copy of proxy info
|
||||
|
@ -135,7 +141,8 @@ nsOSXSystemProxySettings::~nsOSXSystemProxySettings() {
|
|||
if (mSystemDynamicStore) {
|
||||
// Invalidate the dynamic store's run loop source
|
||||
// to get the store out of the run loop
|
||||
CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
|
||||
CFRunLoopSourceRef rls =
|
||||
SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
|
||||
if (rls) {
|
||||
CFRunLoopSourceInvalidate(rls);
|
||||
CFRelease(rls);
|
||||
|
@ -158,20 +165,24 @@ void nsOSXSystemProxySettings::ProxyHasChanged() {
|
|||
}
|
||||
|
||||
nsresult nsOSXSystemProxySettings::FindSCProxyPort(const nsACString& aScheme,
|
||||
nsACString& aResultHost, int32_t& aResultPort,
|
||||
nsACString& aResultHost,
|
||||
int32_t& aResultPort,
|
||||
bool& aResultSocksProxy) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NS_ENSURE_TRUE(mProxyDict != NULL, NS_ERROR_FAILURE);
|
||||
|
||||
for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL; ++keys) {
|
||||
for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL;
|
||||
++keys) {
|
||||
// Check for matching scheme (when appropriate)
|
||||
if (strcasecmp(keys->mScheme, PromiseFlatCString(aScheme).get()) && !keys->mIsSocksProxy)
|
||||
if (strcasecmp(keys->mScheme, PromiseFlatCString(aScheme).get()) &&
|
||||
!keys->mIsSocksProxy)
|
||||
continue;
|
||||
|
||||
// Check the proxy is enabled
|
||||
NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled];
|
||||
NS_ENSURE_TRUE(enabled == NULL || [enabled isKindOfClass:[NSNumber class]], NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(enabled == NULL || [enabled isKindOfClass:[NSNumber class]],
|
||||
NS_ERROR_FAILURE);
|
||||
if ([enabled intValue] == 0) continue;
|
||||
|
||||
// Get the proxy host
|
||||
|
@ -198,17 +209,21 @@ nsresult nsOSXSystemProxySettings::FindSCProxyPort(const nsACString& aScheme,
|
|||
bool nsOSXSystemProxySettings::IsAutoconfigEnabled() const {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSNumber* value = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigEnable];
|
||||
NS_ENSURE_TRUE(value == NULL || [value isKindOfClass:[NSNumber class]], false);
|
||||
NSNumber* value = [mProxyDict
|
||||
objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigEnable];
|
||||
NS_ENSURE_TRUE(value == NULL || [value isKindOfClass:[NSNumber class]],
|
||||
false);
|
||||
return ([value intValue] != 0);
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(false);
|
||||
}
|
||||
|
||||
nsresult nsOSXSystemProxySettings::GetAutoconfigURL(nsAutoCString& aResult) const {
|
||||
nsresult nsOSXSystemProxySettings::GetAutoconfigURL(
|
||||
nsAutoCString& aResult) const {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSString* value = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigURLString];
|
||||
NSString* value = [mProxyDict
|
||||
objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigURLString];
|
||||
if (value != NULL) {
|
||||
NS_ENSURE_TRUE([value isKindOfClass:[NSString class]], NS_ERROR_FAILURE);
|
||||
aResult.Assign([value UTF8String]);
|
||||
|
@ -220,20 +235,25 @@ nsresult nsOSXSystemProxySettings::GetAutoconfigURL(nsAutoCString& aResult) cons
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
bool nsOSXSystemProxySettings::IsInExceptionList(const nsACString& aHost) const {
|
||||
bool nsOSXSystemProxySettings::IsInExceptionList(
|
||||
const nsACString& aHost) const {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NS_ENSURE_TRUE(mProxyDict != NULL, false);
|
||||
|
||||
NSArray* exceptionList = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
|
||||
NS_ENSURE_TRUE(exceptionList == NULL || [exceptionList isKindOfClass:[NSArray class]], false);
|
||||
NSArray* exceptionList =
|
||||
[mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
|
||||
NS_ENSURE_TRUE(
|
||||
exceptionList == NULL || [exceptionList isKindOfClass:[NSArray class]],
|
||||
false);
|
||||
|
||||
NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator];
|
||||
NSString* currentValue = NULL;
|
||||
while ((currentValue = [exceptionEnumerator nextObject])) {
|
||||
NS_ENSURE_TRUE([currentValue isKindOfClass:[NSString class]], false);
|
||||
nsAutoCString overrideStr([currentValue UTF8String]);
|
||||
if (mozilla::toolkit::system::IsHostProxyEntry(aHost, overrideStr)) return true;
|
||||
if (mozilla::toolkit::system::IsHostProxyEntry(aHost, overrideStr))
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(false);
|
||||
|
@ -257,7 +277,8 @@ nsresult nsOSXSystemProxySettings::GetPACURI(nsACString& aResult) {
|
|||
|
||||
nsresult nsOSXSystemProxySettings::GetProxyForURI(const nsACString& aSpec,
|
||||
const nsACString& aScheme,
|
||||
const nsACString& aHost, const int32_t aPort,
|
||||
const nsACString& aHost,
|
||||
const int32_t aPort,
|
||||
nsACString& aResult) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
|
@ -283,7 +304,8 @@ using namespace mozilla::net;
|
|||
|
||||
class OSXSystemProxySettingsAsync final : public nsOSXSystemProxySettings {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING_INHERITED(OSXSystemProxySettingsAsync, nsOSXSystemProxySettings)
|
||||
NS_INLINE_DECL_REFCOUNTING_INHERITED(OSXSystemProxySettingsAsync,
|
||||
nsOSXSystemProxySettings)
|
||||
NS_DECL_NSISYSTEMPROXYSETTINGS
|
||||
|
||||
OSXSystemProxySettingsAsync();
|
||||
|
@ -314,7 +336,8 @@ void OSXSystemProxySettingsAsync::OnProxyConfigChangedInternal() {
|
|||
}
|
||||
|
||||
// proxies (for now: PROXY and SOCKS)
|
||||
for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL; ++keys) {
|
||||
for (const SchemeMapping* keys = gSchemeMappingList; keys->mScheme != NULL;
|
||||
++keys) {
|
||||
// Check the proxy is enabled
|
||||
NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled];
|
||||
if (!(enabled == NULL || [enabled isKindOfClass:[NSNumber class]])) {
|
||||
|
@ -342,17 +365,20 @@ void OSXSystemProxySettingsAsync::OnProxyConfigChangedInternal() {
|
|||
}
|
||||
|
||||
int32_t resultPort = [port intValue];
|
||||
ProxyServer server(ProxyConfig::ToProxyType(keys->mScheme), resultHost, resultPort);
|
||||
ProxyServer server(ProxyConfig::ToProxyType(keys->mScheme), resultHost,
|
||||
resultPort);
|
||||
config.Rules().mProxyServers[server.Type()] = std::move(server);
|
||||
}
|
||||
|
||||
// exceptions
|
||||
NSArray* exceptionList = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
|
||||
NSArray* exceptionList =
|
||||
[mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
|
||||
if (exceptionList != NULL && [exceptionList isKindOfClass:[NSArray class]]) {
|
||||
NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator];
|
||||
NSString* currentValue = NULL;
|
||||
while ((currentValue = [exceptionEnumerator nextObject])) {
|
||||
if (currentValue != NULL && [currentValue isKindOfClass:[NSString class]]) {
|
||||
if (currentValue != NULL &&
|
||||
[currentValue isKindOfClass:[NSString class]]) {
|
||||
nsCString overrideStr([currentValue UTF8String]);
|
||||
config.ByPassRules().mExceptions.AppendElement(std::move(overrideStr));
|
||||
}
|
||||
|
@ -374,8 +400,10 @@ OSXSystemProxySettingsAsync::GetPACURI(nsACString& aResult) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec, const nsACString& aScheme,
|
||||
const nsACString& aHost, const int32_t aPort,
|
||||
OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec,
|
||||
const nsACString& aScheme,
|
||||
const nsACString& aHost,
|
||||
const int32_t aPort,
|
||||
nsACString& aResult) {
|
||||
for (const auto& bypassRule : mConfig.ByPassRules().mExceptions) {
|
||||
if (mozilla::toolkit::system::IsHostProxyEntry(aHost, bypassRule)) {
|
||||
|
@ -389,9 +417,10 @@ OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec, const nsACS
|
|||
}
|
||||
|
||||
NS_IMPL_COMPONENT_FACTORY(nsOSXSystemProxySettings) {
|
||||
auto settings = mozilla::StaticPrefs::network_proxy_detect_system_proxy_changes()
|
||||
? mozilla::MakeRefPtr<OSXSystemProxySettingsAsync>()
|
||||
: mozilla::MakeRefPtr<nsOSXSystemProxySettings>();
|
||||
auto settings =
|
||||
mozilla::StaticPrefs::network_proxy_detect_system_proxy_changes()
|
||||
? mozilla::MakeRefPtr<OSXSystemProxySettingsAsync>()
|
||||
: mozilla::MakeRefPtr<nsOSXSystemProxySettings>();
|
||||
if (NS_SUCCEEDED(settings->Init())) {
|
||||
return settings.forget().downcast<nsISupports>();
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
|
||||
// NSApplication delegate for Mac OS X Cocoa API.
|
||||
|
||||
// As of 10.4 Tiger, the system can send six kinds of Apple Events to an application;
|
||||
// a well-behaved XUL app should have some kind of handling for all of them.
|
||||
// As of 10.4 Tiger, the system can send six kinds of Apple Events to an
|
||||
// application; a well-behaved XUL app should have some kind of handling for all
|
||||
// of them.
|
||||
//
|
||||
// See
|
||||
// http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/SApps_handle_AEs/chapter_11_section_3.html
|
||||
|
@ -92,7 +93,9 @@ void SetupMacApplicationDelegate(bool* gRestartedByOS) {
|
|||
// This call makes it so that application:openFile: doesn't get bogus calls
|
||||
// from Cocoa doing its own parsing of the argument string. And yes, we need
|
||||
// to use a string with a boolean value in it. That's just how it works.
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
|
||||
[[NSUserDefaults standardUserDefaults]
|
||||
setObject:@"NO"
|
||||
forKey:@"NSTreatUnknownArgumentsAsOpen"];
|
||||
|
||||
// Create the delegate. This should be around for the lifetime of the app.
|
||||
id<NSApplicationDelegate> delegate = [[MacApplicationDelegate alloc] init];
|
||||
|
@ -164,9 +167,11 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
NSAppleEventManager* aeMgr = [NSAppleEventManager sharedAppleEventManager];
|
||||
[aeMgr removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
|
||||
[aeMgr removeEventHandlerForEventClass:kInternetEventClass
|
||||
andEventID:kAEGetURL];
|
||||
[aeMgr removeEventHandlerForEventClass:'WWW!' andEventID:'OURL'];
|
||||
[aeMgr removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
|
||||
[aeMgr removeEventHandlerForEventClass:kCoreEventClass
|
||||
andEventID:kAEOpenDocuments];
|
||||
[super dealloc];
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
|
@ -175,7 +180,8 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
// The method that NSApplication calls upon a request to reopen, such as when
|
||||
// the Dock icon is clicked and no windows are open. A "visible" window may be
|
||||
// miniaturized, so we can't skip nsCocoaNativeReOpen() if 'flag' is 'true'.
|
||||
- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApp hasVisibleWindows:(BOOL)flag {
|
||||
- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApp
|
||||
hasVisibleWindows:(BOOL)flag {
|
||||
nsCOMPtr<nsINativeAppSupport> nas = NS_GetNativeAppSupport();
|
||||
NS_ENSURE_TRUE(nas, NO);
|
||||
|
||||
|
@ -187,9 +193,10 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
return NO;
|
||||
}
|
||||
|
||||
// The method that NSApplication calls when documents are requested to be opened.
|
||||
// It will be called once for each selected document.
|
||||
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename {
|
||||
// The method that NSApplication calls when documents are requested to be
|
||||
// opened. It will be called once for each selected document.
|
||||
- (BOOL)application:(NSApplication*)theApplication
|
||||
openFile:(NSString*)filename {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSURL* url = [NSURL fileURLWithPath:filename];
|
||||
|
@ -199,10 +206,12 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
if (!urlString) return NO;
|
||||
|
||||
// Add the URL to any command line we're currently setting up.
|
||||
if (CommandLineServiceMac::AddURLToCurrentCommandLine([urlString UTF8String])) return YES;
|
||||
if (CommandLineServiceMac::AddURLToCurrentCommandLine([urlString UTF8String]))
|
||||
return YES;
|
||||
|
||||
nsCOMPtr<nsILocalFileMac> inFile;
|
||||
nsresult rv = NS_NewLocalFileWithCFURL((CFURLRef)url, true, getter_AddRefs(inFile));
|
||||
nsresult rv =
|
||||
NS_NewLocalFileWithCFURL((CFURLRef)url, true, getter_AddRefs(inFile));
|
||||
if (NS_FAILED(rv)) return NO;
|
||||
|
||||
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
||||
|
@ -212,14 +221,16 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
if (NS_FAILED(rv)) return NO;
|
||||
|
||||
nsCOMPtr<nsIFile> workingDir;
|
||||
rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
|
||||
rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
|
||||
getter_AddRefs(workingDir));
|
||||
if (NS_FAILED(rv)) {
|
||||
// Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope.
|
||||
workingDir = nullptr;
|
||||
}
|
||||
|
||||
const char* argv[3] = {nullptr, "-file", filePath.get()};
|
||||
rv = cmdLine->Init(3, argv, workingDir, nsICommandLine::STATE_REMOTE_EXPLICIT);
|
||||
rv =
|
||||
cmdLine->Init(3, argv, workingDir, nsICommandLine::STATE_REMOTE_EXPLICIT);
|
||||
if (NS_FAILED(rv)) return NO;
|
||||
|
||||
if (NS_SUCCEEDED(cmdLine->Run())) return YES;
|
||||
|
@ -229,10 +240,11 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NO);
|
||||
}
|
||||
|
||||
// The method that NSApplication calls when documents are requested to be printed
|
||||
// from the Finder (under the "File" menu).
|
||||
// It will be called once for each selected document.
|
||||
- (BOOL)application:(NSApplication*)theApplication printFile:(NSString*)filename {
|
||||
// The method that NSApplication calls when documents are requested to be
|
||||
// printed from the Finder (under the "File" menu). It will be called once for
|
||||
// each selected document.
|
||||
- (BOOL)application:(NSApplication*)theApplication
|
||||
printFile:(NSString*)filename {
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
@ -256,7 +268,8 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
if (NS_FAILED(rv) || !dockMenuInterface) return menu;
|
||||
|
||||
RefPtr<mozilla::widget::NativeMenuMac> dockMenu =
|
||||
static_cast<nsStandaloneNativeMenu*>(dockMenuInterface.get())->GetNativeMenu();
|
||||
static_cast<nsStandaloneNativeMenu*>(dockMenuInterface.get())
|
||||
->GetNativeMenu();
|
||||
|
||||
// Give the menu the opportunity to update itself before display.
|
||||
dockMenu->MenuWillOpen();
|
||||
|
@ -288,16 +301,21 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
- (void)applicationWillFinishLaunching:(NSNotification*)notification {
|
||||
// We provide our own full screen menu item, so we don't want the OS providing
|
||||
// one as well.
|
||||
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"];
|
||||
[[NSUserDefaults standardUserDefaults]
|
||||
setBool:NO
|
||||
forKey:@"NSFullScreenMenuItemEverywhere"];
|
||||
}
|
||||
|
||||
// If we don't handle applicationShouldTerminate:, a call to [NSApp terminate:]
|
||||
// (from the browser or from the OS) can result in an unclean shutdown.
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender {
|
||||
nsCOMPtr<nsIObserverService> obsServ = do_GetService("@mozilla.org/observer-service;1");
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:
|
||||
(NSApplication*)sender {
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
if (!obsServ) return NSTerminateNow;
|
||||
|
||||
nsCOMPtr<nsISupportsPRBool> cancelQuit = do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
|
||||
nsCOMPtr<nsISupportsPRBool> cancelQuit =
|
||||
do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
|
||||
if (!cancelQuit) return NSTerminateNow;
|
||||
|
||||
cancelQuit->SetData(false);
|
||||
|
@ -307,7 +325,8 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
cancelQuit->GetData(&abortQuit);
|
||||
if (abortQuit) return NSTerminateCancel;
|
||||
|
||||
nsCOMPtr<nsIAppStartup> appService = do_GetService("@mozilla.org/toolkit/app-startup;1");
|
||||
nsCOMPtr<nsIAppStartup> appService =
|
||||
do_GetService("@mozilla.org/toolkit/app-startup;1");
|
||||
if (appService) {
|
||||
bool userAllowedQuit = true;
|
||||
appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
|
||||
|
@ -325,22 +344,28 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
|
||||
AutoAutoreleasePool pool;
|
||||
|
||||
bool isGetURLEvent = ([event eventClass] == kInternetEventClass && [event eventID] == kAEGetURL);
|
||||
bool isGetURLEvent = ([event eventClass] == kInternetEventClass &&
|
||||
[event eventID] == kAEGetURL);
|
||||
if (isGetURLEvent) sProcessedGetURLEvent = true;
|
||||
|
||||
if (isGetURLEvent || ([event eventClass] == 'WWW!' && [event eventID] == 'OURL')) {
|
||||
NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
|
||||
if (isGetURLEvent ||
|
||||
([event eventClass] == 'WWW!' && [event eventID] == 'OURL')) {
|
||||
NSString* urlString =
|
||||
[[event paramDescriptorForKeyword:keyDirectObject] stringValue];
|
||||
NSURL* url = [NSURL URLWithString:urlString];
|
||||
|
||||
[self openURL:url];
|
||||
} else if ([event eventClass] == kCoreEventClass && [event eventID] == kAEOpenDocuments) {
|
||||
NSAppleEventDescriptor* fileListDescriptor = [event paramDescriptorForKeyword:keyDirectObject];
|
||||
} else if ([event eventClass] == kCoreEventClass &&
|
||||
[event eventID] == kAEOpenDocuments) {
|
||||
NSAppleEventDescriptor* fileListDescriptor =
|
||||
[event paramDescriptorForKeyword:keyDirectObject];
|
||||
if (!fileListDescriptor) return;
|
||||
|
||||
// Descriptor list indexing is one-based...
|
||||
NSInteger numberOfFiles = [fileListDescriptor numberOfItems];
|
||||
for (NSInteger i = 1; i <= numberOfFiles; i++) {
|
||||
NSString* urlString = [[fileListDescriptor descriptorAtIndex:i] stringValue];
|
||||
NSString* urlString =
|
||||
[[fileListDescriptor descriptorAtIndex:i] stringValue];
|
||||
if (!urlString) continue;
|
||||
|
||||
// We need a path, not a URL
|
||||
|
@ -359,12 +384,15 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
|
||||
- (BOOL)application:(NSApplication*)application
|
||||
continueUserActivity:(NSUserActivity*)userActivity
|
||||
#if defined(MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>>*))restorationHandler {
|
||||
#if defined(MAC_OS_X_VERSION_10_14) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
restorationHandler:
|
||||
(void (^)(NSArray<id<NSUserActivityRestoring>>*))restorationHandler {
|
||||
#else
|
||||
restorationHandler:(void (^)(NSArray*))restorationHandler {
|
||||
#endif
|
||||
if (![userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
||||
if (![userActivity.activityType
|
||||
isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
@ -378,7 +406,8 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
}
|
||||
|
||||
- (BOOL)openURL:(NSURL*)url {
|
||||
if (!url || !url.scheme || [url.scheme caseInsensitiveCompare:@"chrome"] == NSOrderedSame) {
|
||||
if (!url || !url.scheme ||
|
||||
[url.scheme caseInsensitiveCompare:@"chrome"] == NSOrderedSame) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
@ -390,14 +419,16 @@ void ProcessPendingGetURLAppleEvents() {
|
|||
|
||||
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
||||
nsCOMPtr<nsIFile> workingDir;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
|
||||
getter_AddRefs(workingDir));
|
||||
if (NS_FAILED(rv)) {
|
||||
// Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope.
|
||||
workingDir = nullptr;
|
||||
}
|
||||
|
||||
const char* argv[3] = {nullptr, "-url", urlString};
|
||||
rv = cmdLine->Init(3, argv, workingDir, nsICommandLine::STATE_REMOTE_EXPLICIT);
|
||||
rv =
|
||||
cmdLine->Init(3, argv, workingDir, nsICommandLine::STATE_REMOTE_EXPLICIT);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NO;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ void LaunchChildMac(int aArgc, char** aArgv, pid_t* aPid) {
|
|||
for (int i = 1; i < aArgc; i++) {
|
||||
[arguments addObject:[NSString stringWithUTF8String:aArgv[i]]];
|
||||
}
|
||||
NSTask* child = [NSTask launchedTaskWithLaunchPath:launchPath arguments:arguments];
|
||||
NSTask* child = [NSTask launchedTaskWithLaunchPath:launchPath
|
||||
arguments:arguments];
|
||||
if (aPid) {
|
||||
*aPid = [child processIdentifier];
|
||||
// We used to use waitpid to wait for the process to terminate. This is
|
||||
|
@ -43,31 +44,36 @@ bool InstallPrivilegedHelper() {
|
|||
AuthorizationRef authRef = NULL;
|
||||
OSStatus status = AuthorizationCreate(
|
||||
NULL, kAuthorizationEmptyEnvironment,
|
||||
kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed, &authRef);
|
||||
kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed,
|
||||
&authRef);
|
||||
if (status != errAuthorizationSuccess) {
|
||||
// AuthorizationCreate really shouldn't fail.
|
||||
NSLog(@"AuthorizationCreate failed! NSOSStatusErrorDomain / %d", (int)status);
|
||||
NSLog(@"AuthorizationCreate failed! NSOSStatusErrorDomain / %d",
|
||||
(int)status);
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL result = NO;
|
||||
AuthorizationItem authItem = {kSMRightBlessPrivilegedHelper, 0, NULL, 0};
|
||||
AuthorizationRights authRights = {1, &authItem};
|
||||
AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed |
|
||||
kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
|
||||
AuthorizationFlags flags =
|
||||
kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed |
|
||||
kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
|
||||
|
||||
// Obtain the right to install our privileged helper tool.
|
||||
status =
|
||||
AuthorizationCopyRights(authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL);
|
||||
status = AuthorizationCopyRights(authRef, &authRights,
|
||||
kAuthorizationEmptyEnvironment, flags, NULL);
|
||||
if (status != errAuthorizationSuccess) {
|
||||
NSLog(@"AuthorizationCopyRights failed! NSOSStatusErrorDomain / %d", (int)status);
|
||||
NSLog(@"AuthorizationCopyRights failed! NSOSStatusErrorDomain / %d",
|
||||
(int)status);
|
||||
} else {
|
||||
CFErrorRef cfError;
|
||||
// This does all the work of verifying the helper tool against the
|
||||
// application and vice-versa. Once verification has passed, the embedded
|
||||
// launchd.plist is extracted and placed in /Library/LaunchDaemons and then
|
||||
// loaded. The executable is placed in /Library/PrivilegedHelperTools.
|
||||
result = (BOOL)SMJobBless(kSMDomainSystemLaunchd, (CFStringRef) @"org.mozilla.updater", authRef,
|
||||
result = (BOOL)SMJobBless(kSMDomainSystemLaunchd,
|
||||
(CFStringRef) @"org.mozilla.updater", authRef,
|
||||
&cfError);
|
||||
if (!result) {
|
||||
NSLog(@"Unable to install helper!");
|
||||
|
@ -90,7 +96,8 @@ void AbortElevatedUpdate() {
|
|||
updateServer = (id)[NSConnection
|
||||
rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server"
|
||||
host:nil
|
||||
usingNameServer:[NSSocketPortNameServer sharedInstance]];
|
||||
usingNameServer:[NSSocketPortNameServer
|
||||
sharedInstance]];
|
||||
if (updateServer && [updateServer respondsToSelector:@selector(abort)]) {
|
||||
[updateServer performSelector:@selector(abort)];
|
||||
return;
|
||||
|
|
|
@ -59,30 +59,37 @@ static bool AskUserIfWeShouldLaunchExistingInstall() {
|
|||
|
||||
ErrorResult rv;
|
||||
nsAutoCString mozTitle, mozMessage, mozLaunchExisting, mozLaunchFromDMG;
|
||||
l10n->FormatValueSync("prompt-to-launch-existing-app-title"_ns, {}, mozTitle, rv);
|
||||
l10n->FormatValueSync("prompt-to-launch-existing-app-title"_ns, {}, mozTitle,
|
||||
rv);
|
||||
if (rv.Failed()) {
|
||||
return false;
|
||||
}
|
||||
l10n->FormatValueSync("prompt-to-launch-existing-app-message"_ns, {}, mozMessage, rv);
|
||||
l10n->FormatValueSync("prompt-to-launch-existing-app-message"_ns, {},
|
||||
mozMessage, rv);
|
||||
if (rv.Failed()) {
|
||||
return false;
|
||||
}
|
||||
l10n->FormatValueSync("prompt-to-launch-existing-app-yes-button"_ns, {}, mozLaunchExisting, rv);
|
||||
l10n->FormatValueSync("prompt-to-launch-existing-app-yes-button"_ns, {},
|
||||
mozLaunchExisting, rv);
|
||||
if (rv.Failed()) {
|
||||
return false;
|
||||
}
|
||||
l10n->FormatValueSync("prompt-to-launch-existing-app-no-button"_ns, {}, mozLaunchFromDMG, rv);
|
||||
l10n->FormatValueSync("prompt-to-launch-existing-app-no-button"_ns, {},
|
||||
mozLaunchFromDMG, rv);
|
||||
if (rv.Failed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||
NSString* message =
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||
NSString* title = [NSString
|
||||
stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||
NSString* message = [NSString
|
||||
stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||
NSString* launchExisting =
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozLaunchExisting.get())];
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(
|
||||
mozLaunchExisting.get())];
|
||||
NSString* launchFromDMG =
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozLaunchFromDMG.get())];
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(
|
||||
mozLaunchFromDMG.get())];
|
||||
|
||||
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
||||
|
||||
|
@ -144,18 +151,20 @@ static bool AskUserIfWeShouldInstall() {
|
|||
if (rv.Failed()) {
|
||||
return false;
|
||||
}
|
||||
l10n->FormatValueSync("prompt-to-install-no-button"_ns, {}, mozDontInstall, rv);
|
||||
l10n->FormatValueSync("prompt-to-install-no-button"_ns, {}, mozDontInstall,
|
||||
rv);
|
||||
if (rv.Failed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||
NSString* message =
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||
NSString* install =
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozInstall.get())];
|
||||
NSString* dontInstall =
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozDontInstall.get())];
|
||||
NSString* title = [NSString
|
||||
stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||
NSString* message = [NSString
|
||||
stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||
NSString* install = [NSString
|
||||
stringWithUTF8String:reinterpret_cast<const char*>(mozInstall.get())];
|
||||
NSString* dontInstall = [NSString
|
||||
stringWithUTF8String:reinterpret_cast<const char*>(mozDontInstall.get())];
|
||||
|
||||
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
||||
|
||||
|
@ -179,15 +188,15 @@ static bool AskUserIfWeShouldInstall() {
|
|||
// AskUserIfWeShouldInstall
|
||||
// |
|
||||
// | ---> [NSApp run]
|
||||
// | |
|
||||
// | | -----> task
|
||||
// | | | -----------> [alert runModal]
|
||||
// | | | | (User selects button)
|
||||
// | | | <--------------- done
|
||||
// | | |
|
||||
// | | | -----------> [NSApp stop:nil]
|
||||
// | | | <-----------
|
||||
// | | <--------
|
||||
// | |
|
||||
// | | ---> task
|
||||
// | | | ----> [alert runModal]
|
||||
// | | | | (User selects button)
|
||||
// | | | <--------- done
|
||||
// | | |
|
||||
// | | | -----> [NSApp stop:nil]
|
||||
// | | | <-----
|
||||
// | | <-----
|
||||
// | <-------
|
||||
// done
|
||||
__block NSInteger result = -1;
|
||||
|
@ -225,9 +234,10 @@ static void ShowInstallFailedDialog() {
|
|||
return;
|
||||
}
|
||||
|
||||
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||
NSString* message =
|
||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||
NSString* title = [NSString
|
||||
stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||
NSString* message = [NSString
|
||||
stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||
|
||||
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
||||
|
||||
|
@ -322,8 +332,9 @@ static bool InstallFromPath(NSString* aBundlePath, NSString* aDestPath) {
|
|||
NSString* destDir = [aDestPath stringByDeletingLastPathComponent];
|
||||
if (!installSuccessful && ![fileManager isWritableFileAtPath:destDir]) {
|
||||
NSString* updaterBinPath = [NSString pathWithComponents:@[
|
||||
aBundlePath, @"Contents", @"MacOS", [NSString stringWithUTF8String:UPDATER_APP], @"Contents",
|
||||
@"MacOS", [NSString stringWithUTF8String:UPDATER_BIN]
|
||||
aBundlePath, @"Contents", @"MacOS",
|
||||
[NSString stringWithUTF8String:UPDATER_APP], @"Contents", @"MacOS",
|
||||
[NSString stringWithUTF8String:UPDATER_BIN]
|
||||
]];
|
||||
|
||||
NSArray* arguments = @[ @"-dmgInstall", aBundlePath, aDestPath ];
|
||||
|
@ -354,7 +365,8 @@ static bool InstallFromPath(NSString* aBundlePath, NSString* aDestPath) {
|
|||
bool IsAppRunningFromDmg() {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
const char* path = [[[NSBundle mainBundle] bundlePath] fileSystemRepresentation];
|
||||
const char* path =
|
||||
[[[NSBundle mainBundle] bundlePath] fileSystemRepresentation];
|
||||
|
||||
struct statfs statfsBuf;
|
||||
if (statfs(path, &statfsBuf) != 0) {
|
||||
|
@ -388,11 +400,13 @@ bool IsAppRunningFromDmg() {
|
|||
|
||||
// Get the IOMedia object:
|
||||
// (Note: IOServiceGetMatchingServices takes ownership of serviceDict's ref.)
|
||||
CFMutableDictionaryRef serviceDict = IOBSDNameMatching(kIOMasterPortDefault, 0, bsdDeviceName);
|
||||
CFMutableDictionaryRef serviceDict =
|
||||
IOBSDNameMatching(kIOMasterPortDefault, 0, bsdDeviceName);
|
||||
if (!serviceDict) {
|
||||
return false;
|
||||
}
|
||||
io_service_t media = IOServiceGetMatchingService(kIOMasterPortDefault, serviceDict);
|
||||
io_service_t media =
|
||||
IOServiceGetMatchingService(kIOMasterPortDefault, serviceDict);
|
||||
if (!media || !IOObjectConformsTo(media, "IOMedia")) {
|
||||
return false;
|
||||
}
|
||||
|
@ -401,14 +415,16 @@ bool IsAppRunningFromDmg() {
|
|||
// (taking care to start with `media` itself):
|
||||
io_service_t imageDrive = IO_OBJECT_NULL;
|
||||
io_iterator_t iter;
|
||||
if (IORegistryEntryCreateIterator(media, kIOServicePlane,
|
||||
kIORegistryIterateRecursively | kIORegistryIterateParents,
|
||||
&iter) != KERN_SUCCESS) {
|
||||
if (IORegistryEntryCreateIterator(
|
||||
media, kIOServicePlane,
|
||||
kIORegistryIterateRecursively | kIORegistryIterateParents,
|
||||
&iter) != KERN_SUCCESS) {
|
||||
IOObjectRelease(media);
|
||||
return false;
|
||||
}
|
||||
const char* imageClass =
|
||||
nsCocoaFeatures::OnMontereyOrLater() ? "AppleDiskImageDevice" : "IOHDIXHDDrive";
|
||||
const char* imageClass = nsCocoaFeatures::OnMontereyOrLater()
|
||||
? "AppleDiskImageDevice"
|
||||
: "IOHDIXHDDrive";
|
||||
for (imageDrive = media; imageDrive; imageDrive = IOIteratorNext(iter)) {
|
||||
if (IOObjectConformsTo(imageDrive, imageClass)) {
|
||||
break;
|
||||
|
@ -446,20 +462,22 @@ bool MaybeInstallAndRelaunch() {
|
|||
// The Applications directory may not be at /Applications, although in
|
||||
// practice we're unlikely to encounter since run-from-.dmg is really an
|
||||
// issue with novice mac users. Still, look it up correctly:
|
||||
NSArray* applicationsDirs =
|
||||
NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES);
|
||||
NSArray* applicationsDirs = NSSearchPathForDirectoriesInDomains(
|
||||
NSApplicationDirectory, NSLocalDomainMask, YES);
|
||||
NSString* applicationsDir = applicationsDirs[0];
|
||||
|
||||
// Sanity check dir exists
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
BOOL isDir;
|
||||
if (![fileManager fileExistsAtPath:applicationsDir isDirectory:&isDir] || !isDir) {
|
||||
if (![fileManager fileExistsAtPath:applicationsDir isDirectory:&isDir] ||
|
||||
!isDir) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||
NSString* appName = [bundlePath lastPathComponent];
|
||||
NSString* destPath = [applicationsDir stringByAppendingPathComponent:appName];
|
||||
NSString* destPath =
|
||||
[applicationsDir stringByAppendingPathComponent:appName];
|
||||
|
||||
// If the app (an app of the same name) is already installed we can't really
|
||||
// tell without asking if we're dealing with the edge case of an
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
#include "UIKitDirProvider.h"
|
||||
|
||||
bool GetUIKitDirectory(bool aLocal, nsACString& aUserDir) {
|
||||
NSSearchPathDirectory directory = aLocal ? NSCachesDirectory : NSApplicationSupportDirectory;
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
||||
NSSearchPathDirectory directory =
|
||||
aLocal ? NSCachesDirectory : NSApplicationSupportDirectory;
|
||||
NSArray* paths =
|
||||
NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
||||
if ([paths count] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ static bool sBuildingCommandLine = false;
|
|||
void AddToCommandLine(const char* inArgText) {
|
||||
if (sArgsUsed >= sArgsAllocated - 1) {
|
||||
// realloc does not free the given pointer if allocation fails
|
||||
char** temp =
|
||||
static_cast<char**>(realloc(sArgs, (sArgsAllocated + kArgsGrowSize) * sizeof(char*)));
|
||||
char** temp = static_cast<char**>(
|
||||
realloc(sArgs, (sArgsAllocated + kArgsGrowSize) * sizeof(char*)));
|
||||
if (!temp) return;
|
||||
sArgs = temp;
|
||||
sArgsAllocated += kArgsGrowSize;
|
||||
|
@ -67,7 +67,8 @@ void SetupMacCommandLine(int& argc, char**& argv, bool forRestart) {
|
|||
// if the parent is in the foreground. This will be communicated in a
|
||||
// command-line argument to the child.
|
||||
if (forRestart) {
|
||||
NSRunningApplication* frontApp = [[NSWorkspace sharedWorkspace] frontmostApplication];
|
||||
NSRunningApplication* frontApp =
|
||||
[[NSWorkspace sharedWorkspace] frontmostApplication];
|
||||
if ([frontApp isEqual:[NSRunningApplication currentApplication]]) {
|
||||
AddToCommandLine("-foreground");
|
||||
}
|
||||
|
|
|
@ -119,7 +119,8 @@ nsNativeAppSupportCocoa::ReOpen() {
|
|||
windowList->HasMoreElements(&more);
|
||||
continue;
|
||||
}
|
||||
NSWindow* cocoaWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
NSWindow* cocoaWindow =
|
||||
(NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
if (![cocoaWindow isMiniaturized]) {
|
||||
haveNonMiniaturized = true;
|
||||
break; // have un-minimized windows, nothing to do
|
||||
|
@ -154,7 +155,8 @@ nsNativeAppSupportCocoa::ReOpen() {
|
|||
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
||||
|
||||
nsresult rv;
|
||||
rv = cmdLine->Init(0, argv, nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
|
||||
rv = cmdLine->Init(0, argv, nullptr,
|
||||
nsICommandLine::STATE_REMOTE_EXPLICIT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return cmdLine->Run();
|
||||
|
|
|
@ -13,8 +13,10 @@ bool IsRecursivelyWritable(const char* aPath) {
|
|||
NSString* rootPath = [NSString stringWithUTF8String:aPath];
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
NSError* error = nil;
|
||||
NSArray* subPaths = [fileManager subpathsOfDirectoryAtPath:rootPath error:&error];
|
||||
NSMutableArray* paths = [NSMutableArray arrayWithCapacity:[subPaths count] + 1];
|
||||
NSArray* subPaths = [fileManager subpathsOfDirectoryAtPath:rootPath
|
||||
error:&error];
|
||||
NSMutableArray* paths =
|
||||
[NSMutableArray arrayWithCapacity:[subPaths count] + 1];
|
||||
[paths addObject:@""];
|
||||
[paths addObjectsFromArray:subPaths];
|
||||
|
||||
|
@ -26,7 +28,8 @@ bool IsRecursivelyWritable(const char* aPath) {
|
|||
for (NSString* currPath in paths) {
|
||||
NSString* child = [rootPath stringByAppendingPathComponent:currPath];
|
||||
|
||||
NSDictionary* attributes = [fileManager attributesOfItemAtPath:child error:&error];
|
||||
NSDictionary* attributes = [fileManager attributesOfItemAtPath:child
|
||||
error:&error];
|
||||
if (error) {
|
||||
[pool drain];
|
||||
return false;
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
#include "nsILocalFileMac.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
// We override this to make sure app bundles display their pretty name (without .app suffix)
|
||||
// We override this to make sure app bundles display their pretty name (without
|
||||
// .app suffix)
|
||||
NS_IMETHODIMP nsLocalHandlerAppMac::GetName(nsAString& aName) {
|
||||
if (mExecutable) {
|
||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(mExecutable);
|
||||
|
@ -30,7 +31,8 @@ NS_IMETHODIMP nsLocalHandlerAppMac::GetName(nsAString& aName) {
|
|||
* somewhere more central (see bug 389922).
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerAppMac::LaunchWithURI(nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
|
||||
nsLocalHandlerAppMac::LaunchWithURI(
|
||||
nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsresult rv;
|
||||
|
@ -45,14 +47,15 @@ nsLocalHandlerAppMac::LaunchWithURI(nsIURI* aURI, mozilla::dom::BrowsingContext*
|
|||
aURI->GetAsciiSpec(uriSpec);
|
||||
|
||||
const UInt8* uriString = reinterpret_cast<const UInt8*>(uriSpec.get());
|
||||
CFURLRef uri =
|
||||
::CFURLCreateWithBytes(NULL, uriString, uriSpec.Length(), kCFStringEncodingUTF8, NULL);
|
||||
CFURLRef uri = ::CFURLCreateWithBytes(NULL, uriString, uriSpec.Length(),
|
||||
kCFStringEncodingUTF8, NULL);
|
||||
if (!uri) {
|
||||
::CFRelease(appURL);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
CFArrayRef uris = ::CFArrayCreate(NULL, reinterpret_cast<const void**>(&uri), 1, NULL);
|
||||
CFArrayRef uris =
|
||||
::CFArrayCreate(NULL, reinterpret_cast<const void**>(&uri), 1, NULL);
|
||||
if (!uris) {
|
||||
::CFRelease(uri);
|
||||
::CFRelease(appURL);
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
#include "nsMIMEInfoMac.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
|
||||
// We override this to make sure app bundles display their pretty name (without .app suffix)
|
||||
NS_IMETHODIMP nsMIMEInfoMac::GetDefaultDescription(nsAString& aDefaultDescription) {
|
||||
// We override this to make sure app bundles display their pretty name (without
|
||||
// .app suffix)
|
||||
NS_IMETHODIMP nsMIMEInfoMac::GetDefaultDescription(
|
||||
nsAString& aDefaultDescription) {
|
||||
nsCOMPtr<nsIFile> defaultApp = GetDefaultApplication();
|
||||
if (defaultApp) {
|
||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(defaultApp);
|
||||
|
@ -43,7 +45,8 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile* aFile) {
|
|||
if (mPreferredAction == useHelperApp) {
|
||||
// we don't yet support passing content by value (rather than reference)
|
||||
// to web apps. at some point, we will probably want to.
|
||||
nsCOMPtr<nsILocalHandlerApp> localHandlerApp = do_QueryInterface(mPreferredApplication, &rv);
|
||||
nsCOMPtr<nsILocalHandlerApp> localHandlerApp =
|
||||
do_QueryInterface(mPreferredApplication, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = localHandlerApp->GetExecutable(getter_AddRefs(application));
|
||||
|
@ -68,7 +71,8 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile* aFile) {
|
|||
tempFile->GetFSRef(&tempFileRef);
|
||||
|
||||
FSRef appFSRef;
|
||||
if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef, nullptr) == noErr) {
|
||||
if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef,
|
||||
nullptr) == noErr) {
|
||||
app = (do_CreateInstance("@mozilla.org/file/local;1"));
|
||||
if (!app) return NS_ERROR_FAILURE;
|
||||
app->InitWithFSRef(&appFSRef);
|
||||
|
@ -91,8 +95,9 @@ nsresult nsMIMEInfoMac::LoadUriInternal(nsIURI* aURI) {
|
|||
nsAutoCString uri;
|
||||
aURI->GetSpec(uri);
|
||||
if (!uri.IsEmpty()) {
|
||||
CFURLRef myURLRef = ::CFURLCreateWithBytes(kCFAllocatorDefault, (const UInt8*)uri.get(),
|
||||
strlen(uri.get()), kCFStringEncodingUTF8, NULL);
|
||||
CFURLRef myURLRef =
|
||||
::CFURLCreateWithBytes(kCFAllocatorDefault, (const UInt8*)uri.get(),
|
||||
strlen(uri.get()), kCFStringEncodingUTF8, NULL);
|
||||
if (myURLRef) {
|
||||
OSStatus status = ::LSOpenCFURLRef(myURLRef, NULL);
|
||||
if (status == noErr) rv = NS_OK;
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
#import <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
// chrome URL's
|
||||
#define HELPERAPPLAUNCHER_BUNDLE_URL "chrome://global/locale/helperAppLauncher.properties"
|
||||
#define HELPERAPPLAUNCHER_BUNDLE_URL \
|
||||
"chrome://global/locale/helperAppLauncher.properties"
|
||||
#define BRAND_BUNDLE_URL "chrome://branding/locale/brand.properties"
|
||||
|
||||
nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) {
|
||||
|
@ -34,18 +35,20 @@ nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) {
|
|||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
CFStringRef schemeCFString = ::CFStringCreateWithBytes(
|
||||
kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aScheme).get(), aScheme.Length(),
|
||||
kCFStringEncodingUTF8, false);
|
||||
kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aScheme).get(),
|
||||
aScheme.Length(), kCFStringEncodingUTF8, false);
|
||||
|
||||
if (schemeCFString) {
|
||||
CFStringRef lookupCFString =
|
||||
::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString);
|
||||
|
||||
if (lookupCFString) {
|
||||
CFURLRef lookupCFURL = ::CFURLCreateWithString(NULL, lookupCFString, NULL);
|
||||
CFURLRef lookupCFURL =
|
||||
::CFURLCreateWithString(NULL, lookupCFString, NULL);
|
||||
|
||||
if (lookupCFURL) {
|
||||
*aBundleURL = ::LSCopyDefaultApplicationURLForURL(lookupCFURL, kLSRolesAll, NULL);
|
||||
*aBundleURL =
|
||||
::LSCopyDefaultApplicationURLForURL(lookupCFURL, kLSRolesAll, NULL);
|
||||
if (*aBundleURL) {
|
||||
rv = NS_OK;
|
||||
}
|
||||
|
@ -88,15 +91,15 @@ using mozilla::LogLevel;
|
|||
|
||||
nsOSHelperAppService::~nsOSHelperAppService() {}
|
||||
|
||||
nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolScheme,
|
||||
bool* aHandlerExists) {
|
||||
nsresult nsOSHelperAppService::OSProtocolHandlerExists(
|
||||
const char* aProtocolScheme, bool* aHandlerExists) {
|
||||
// CFStringCreateWithBytes() can fail even if we're not out of memory --
|
||||
// for example if the 'bytes' parameter is something very weird (like
|
||||
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||
// specified in the 'encoding' parameter. See bug 548719.
|
||||
CFStringRef schemeString =
|
||||
::CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)aProtocolScheme,
|
||||
strlen(aProtocolScheme), kCFStringEncodingUTF8, false);
|
||||
CFStringRef schemeString = ::CFStringCreateWithBytes(
|
||||
kCFAllocatorDefault, (const UInt8*)aProtocolScheme,
|
||||
strlen(aProtocolScheme), kCFStringEncodingUTF8, false);
|
||||
if (schemeString) {
|
||||
// LSCopyDefaultHandlerForURLScheme() can fail to find the default handler
|
||||
// for aProtocolScheme when it's never been explicitly set (using
|
||||
|
@ -118,8 +121,8 @@ nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolSche
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& _retval) {
|
||||
NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(
|
||||
const nsACString& aScheme, nsAString& _retval) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
@ -136,14 +139,17 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString&
|
|||
|
||||
// Get the human-readable name of the bundle
|
||||
CFStringRef bundleName =
|
||||
(CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle, kCFBundleNameKey);
|
||||
(CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle,
|
||||
kCFBundleNameKey);
|
||||
|
||||
if (bundleName) {
|
||||
AutoTArray<UniChar, 255> buffer;
|
||||
CFIndex bundleNameLength = ::CFStringGetLength(bundleName);
|
||||
buffer.SetLength(bundleNameLength);
|
||||
::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength), buffer.Elements());
|
||||
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), bundleNameLength);
|
||||
::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength),
|
||||
buffer.Elements());
|
||||
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
|
||||
bundleNameLength);
|
||||
rv = NS_OK;
|
||||
}
|
||||
::CFRelease(handlerBundle);
|
||||
|
@ -155,8 +161,8 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString&
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
||||
bool* _retval) {
|
||||
NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
|
||||
const nsACString& aScheme, bool* _retval) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
@ -164,7 +170,8 @@ NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACS
|
|||
CFURLRef handlerBundleURL;
|
||||
rv = GetDefaultBundleURL(aScheme, &handlerBundleURL);
|
||||
if (NS_SUCCEEDED(rv) && handlerBundleURL) {
|
||||
// Ensure we don't accidentally return success if we can't get an app bundle.
|
||||
// Ensure we don't accidentally return success if we can't get an app
|
||||
// bundle.
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
CFBundleRef appBundle = ::CFBundleGetMainBundle();
|
||||
if (appBundle) {
|
||||
|
@ -181,23 +188,25 @@ NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACS
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppPath,
|
||||
nsIFile** aFile) {
|
||||
nsresult nsOSHelperAppService::GetFileTokenForPath(
|
||||
const char16_t* aPlatformAppPath, nsIFile** aFile) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocalFileMac> localFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
|
||||
nsCOMPtr<nsILocalFileMac> localFile(
|
||||
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
CFURLRef pathAsCFURL;
|
||||
CFStringRef pathAsCFString = ::CFStringCreateWithCharacters(
|
||||
NULL, reinterpret_cast<const UniChar*>(aPlatformAppPath), NS_strlen(aPlatformAppPath));
|
||||
NULL, reinterpret_cast<const UniChar*>(aPlatformAppPath),
|
||||
NS_strlen(aPlatformAppPath));
|
||||
if (!pathAsCFString) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (::CFStringGetCharacterAtIndex(pathAsCFString, 0) == '/') {
|
||||
// we have a Posix path
|
||||
pathAsCFURL =
|
||||
::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString, kCFURLPOSIXPathStyle, false);
|
||||
pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString,
|
||||
kCFURLPOSIXPathStyle, false);
|
||||
if (!pathAsCFURL) {
|
||||
::CFRelease(pathAsCFString);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -214,8 +223,8 @@ nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppP
|
|||
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
||||
}
|
||||
|
||||
pathAsCFURL =
|
||||
::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString, kCFURLHFSPathStyle, false);
|
||||
pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString,
|
||||
kCFURLHFSPathStyle, false);
|
||||
if (!pathAsCFURL) {
|
||||
::CFRelease(pathAsCFString);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -259,7 +268,8 @@ static CFArrayRef GetMIMETypesHandledByApp(FSRef* aAppRef) {
|
|||
if (!infoDict) {
|
||||
return NULL;
|
||||
}
|
||||
CFTypeRef cfObject = ::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes"));
|
||||
CFTypeRef cfObject =
|
||||
::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes"));
|
||||
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
|
||||
::CFRelease(infoDict);
|
||||
return NULL;
|
||||
|
@ -307,7 +317,8 @@ static CFArrayRef GetMIMETypesHandledByApp(FSRef* aAppRef) {
|
|||
}
|
||||
|
||||
nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt, bool* aFound,
|
||||
const nsACString& aFileExt,
|
||||
bool* aFound,
|
||||
nsIMIMEInfo** aMIMEInfo) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
@ -318,7 +329,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
const nsCString& flatExt = PromiseFlatCString(aFileExt);
|
||||
|
||||
MOZ_LOG(sLog, LogLevel::Debug,
|
||||
("Mac: HelperAppService lookup for type '%s' ext '%s'\n", flatType.get(), flatExt.get()));
|
||||
("Mac: HelperAppService lookup for type '%s' ext '%s'\n",
|
||||
flatType.get(), flatExt.get()));
|
||||
|
||||
// Create a Mac-specific MIME info so we can use Mac-specific members.
|
||||
RefPtr<nsMIMEInfoMac> mimeInfoMac = new nsMIMEInfoMac(aMIMEType);
|
||||
|
@ -337,13 +349,15 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
CFStringRef cfMIMEType = NULL;
|
||||
|
||||
if (!aMIMEType.IsEmpty()) {
|
||||
typeIsOctetStream = aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM);
|
||||
typeIsOctetStream =
|
||||
aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM);
|
||||
CFURLRef appURL = NULL;
|
||||
// CFStringCreateWithCString() can fail even if we're not out of memory --
|
||||
// for example if the 'cStr' parameter is something very weird (like
|
||||
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||
// specified in the 'encoding' parameter. See bug 548719.
|
||||
cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(), kCFStringEncodingUTF8);
|
||||
cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(),
|
||||
kCFStringEncodingUTF8);
|
||||
if (cfMIMEType) {
|
||||
err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL);
|
||||
if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) {
|
||||
|
@ -361,13 +375,15 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
// for example if the 'cStr' parameter is something very weird (like
|
||||
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||
// specified in the 'encoding' parameter. See bug 548719.
|
||||
CFStringRef cfExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
|
||||
CFStringRef cfExt =
|
||||
::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
|
||||
if (cfExt) {
|
||||
err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt, kLSRolesAll,
|
||||
&extAppFSRef, nullptr);
|
||||
err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt,
|
||||
kLSRolesAll, &extAppFSRef, nullptr);
|
||||
if (err == noErr) {
|
||||
haveAppForExt = true;
|
||||
MOZ_LOG(sLog, LogLevel::Debug, ("LSGetApplicationForInfo found a default application\n"));
|
||||
MOZ_LOG(sLog, LogLevel::Debug,
|
||||
("LSGetApplicationForInfo found a default application\n"));
|
||||
}
|
||||
::CFRelease(cfExt);
|
||||
}
|
||||
|
@ -375,7 +391,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
|
||||
if (haveAppForType && haveAppForExt) {
|
||||
// Do aMIMEType and aFileExt match?
|
||||
if (::FSCompareFSRefs((const FSRef*)&typeAppFSRef, (const FSRef*)&extAppFSRef) == noErr) {
|
||||
if (::FSCompareFSRefs((const FSRef*)&typeAppFSRef,
|
||||
(const FSRef*)&extAppFSRef) == noErr) {
|
||||
typeAppIsDefault = true;
|
||||
*aFound = true;
|
||||
}
|
||||
|
@ -418,9 +435,10 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef);
|
||||
if (extAppMIMETypes) {
|
||||
if (cfMIMEType) {
|
||||
if (::CFArrayContainsValue(extAppMIMETypes,
|
||||
::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)),
|
||||
cfMIMEType)) {
|
||||
if (::CFArrayContainsValue(
|
||||
extAppMIMETypes,
|
||||
::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)),
|
||||
cfMIMEType)) {
|
||||
extAppIsDefault = true;
|
||||
*aFound = true;
|
||||
}
|
||||
|
@ -445,11 +463,13 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
// the doc for this method says that if we have a MIME type (in
|
||||
// aMIMEType), we need to give it preference.)
|
||||
NSURLFileTypeMappings* map = [NSURLFileTypeMappings sharedMappings];
|
||||
NSString* extStr = [NSString stringWithCString:flatExt.get() encoding:NSASCIIStringEncoding];
|
||||
NSString* extStr = [NSString stringWithCString:flatExt.get()
|
||||
encoding:NSASCIIStringEncoding];
|
||||
NSString* typeStr = map ? [map MIMETypeForExtension:extStr] : NULL;
|
||||
if (typeStr) {
|
||||
nsAutoCString mimeType;
|
||||
mimeType.Assign((char*)[typeStr cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
mimeType.Assign(
|
||||
(char*)[typeStr cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
mimeInfoMac->SetMIMEType(mimeType);
|
||||
haveAppForType = true;
|
||||
} else {
|
||||
|
@ -476,7 +496,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
if (haveAppForExt) mimeInfoMac->AppendExtension(aFileExt);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocalFileMac> app(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
|
||||
nsCOMPtr<nsILocalFileMac> app(
|
||||
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
[localPool release];
|
||||
return rv;
|
||||
|
@ -485,20 +506,22 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
CFStringRef cfAppName = NULL;
|
||||
if (typeAppIsDefault) {
|
||||
app->InitWithFSRef(&typeAppFSRef);
|
||||
::LSCopyItemAttribute((const FSRef*)&typeAppFSRef, kLSRolesAll, kLSItemDisplayName,
|
||||
(CFTypeRef*)&cfAppName);
|
||||
::LSCopyItemAttribute((const FSRef*)&typeAppFSRef, kLSRolesAll,
|
||||
kLSItemDisplayName, (CFTypeRef*)&cfAppName);
|
||||
} else {
|
||||
app->InitWithFSRef(&extAppFSRef);
|
||||
::LSCopyItemAttribute((const FSRef*)&extAppFSRef, kLSRolesAll, kLSItemDisplayName,
|
||||
(CFTypeRef*)&cfAppName);
|
||||
::LSCopyItemAttribute((const FSRef*)&extAppFSRef, kLSRolesAll,
|
||||
kLSItemDisplayName, (CFTypeRef*)&cfAppName);
|
||||
}
|
||||
if (cfAppName) {
|
||||
AutoTArray<UniChar, 255> buffer;
|
||||
CFIndex appNameLength = ::CFStringGetLength(cfAppName);
|
||||
buffer.SetLength(appNameLength);
|
||||
::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength), buffer.Elements());
|
||||
::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength),
|
||||
buffer.Elements());
|
||||
nsAutoString appName;
|
||||
appName.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), appNameLength);
|
||||
appName.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
|
||||
appNameLength);
|
||||
mimeInfoMac->SetDefaultDescription(appName);
|
||||
::CFRelease(cfAppName);
|
||||
}
|
||||
|
@ -516,25 +539,29 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
// If we have a MIME type, make sure its extension list is included in our
|
||||
// list.
|
||||
NSURLFileTypeMappings* map = [NSURLFileTypeMappings sharedMappings];
|
||||
NSString* typeStr = [NSString stringWithCString:mimeType.get() encoding:NSASCIIStringEncoding];
|
||||
NSString* typeStr = [NSString stringWithCString:mimeType.get()
|
||||
encoding:NSASCIIStringEncoding];
|
||||
NSArray* extensionsList = map ? [map extensionsForMIMEType:typeStr] : NULL;
|
||||
if (extensionsList) {
|
||||
for (NSString* extension in extensionsList) {
|
||||
nsAutoCString ext;
|
||||
ext.Assign((char*)[extension cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
ext.Assign(
|
||||
(char*)[extension cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
mimeInfoMac->AppendExtension(ext);
|
||||
}
|
||||
}
|
||||
|
||||
if (CFStringRef cfType =
|
||||
::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8)) {
|
||||
if (CFStringRef cfType = ::CFStringCreateWithCString(
|
||||
NULL, mimeType.get(), kCFStringEncodingUTF8)) {
|
||||
if (CFStringRef cfTypeDesc = ::UTTypeCopyDescription(cfType)) {
|
||||
AutoTArray<UniChar, 255> buffer;
|
||||
CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc);
|
||||
buffer.SetLength(typeDescLength);
|
||||
::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength), buffer.Elements());
|
||||
::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength),
|
||||
buffer.Elements());
|
||||
nsAutoString typeDesc;
|
||||
typeDesc.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), typeDescLength);
|
||||
typeDesc.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
|
||||
typeDescLength);
|
||||
mimeInfoMac->SetDescription(typeDesc);
|
||||
::CFRelease(cfTypeDesc);
|
||||
}
|
||||
|
@ -542,7 +569,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_LOG(sLog, LogLevel::Debug, ("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound));
|
||||
MOZ_LOG(sLog, LogLevel::Debug,
|
||||
("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound));
|
||||
|
||||
[localPool release];
|
||||
mimeInfoMac.forget(aMIMEInfo);
|
||||
|
@ -552,14 +580,17 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found,
|
||||
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme,
|
||||
bool* found,
|
||||
nsIHandlerInfo** _retval) {
|
||||
NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!");
|
||||
|
||||
nsresult rv = OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(), found);
|
||||
nsresult rv =
|
||||
OSProtocolHandlerExists(nsPromiseFlatCString(aScheme).get(), found);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsMIMEInfoMac* handlerInfo = new nsMIMEInfoMac(aScheme, nsMIMEInfoBase::eProtocolInfo);
|
||||
nsMIMEInfoMac* handlerInfo =
|
||||
new nsMIMEInfoMac(aScheme, nsMIMEInfoBase::eProtocolInfo);
|
||||
NS_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(*_retval = handlerInfo);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "nsIURI.h"
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocalHandlerAppUIKit::LaunchWithURI(nsIURI* aURI,
|
||||
mozilla::dom::BrowsingContext* aBrowsingContext) {
|
||||
nsLocalHandlerAppUIKit::LaunchWithURI(
|
||||
nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#include "nsMIMEInfoUIKit.h"
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEInfoUIKit::LaunchWithFile(nsIFile* aFile) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
nsMIMEInfoUIKit::LaunchWithFile(nsIFile* aFile) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult nsMIMEInfoUIKit::LoadUriInternal(nsIURI* aURI) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
nsresult nsMIMEInfoUIKit::LoadUriInternal(nsIURI* aURI) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -10,43 +10,48 @@ nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService() {}
|
|||
|
||||
nsOSHelperAppService::~nsOSHelperAppService() {}
|
||||
|
||||
nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolScheme,
|
||||
bool* aHandlerExists) {
|
||||
nsresult nsOSHelperAppService::OSProtocolHandlerExists(
|
||||
const char* aProtocolScheme, bool* aHandlerExists) {
|
||||
*aHandlerExists = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval) {
|
||||
nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme,
|
||||
nsAString& _retval) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme, bool* _retval) {
|
||||
nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
|
||||
const nsACString& aScheme, bool* _retval) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppPath,
|
||||
nsIFile** aFile) {
|
||||
nsresult nsOSHelperAppService::GetFileTokenForPath(
|
||||
const char16_t* aPlatformAppPath, nsIFile** aFile) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt,
|
||||
nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType,
|
||||
const nsACString& aFileExt,
|
||||
nsIMIMEInfo** aMIMEInfo) {
|
||||
return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo);
|
||||
return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt,
|
||||
aMIMEInfo);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||
const nsACString& aFileExt, bool* aFound,
|
||||
nsIMIMEInfo** aMIMEInfo) {
|
||||
NS_IMETHODIMP nsOSHelperAppService::GetMIMEInfoFromOS(
|
||||
const nsACString& aMIMEType, const nsACString& aFileExt, bool* aFound,
|
||||
nsIMIMEInfo** aMIMEInfo) {
|
||||
*aMIMEInfo = nullptr;
|
||||
*aFound = false;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found,
|
||||
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme,
|
||||
bool* found,
|
||||
nsIHandlerInfo** _retval) {
|
||||
*found = false;
|
||||
return NS_OK;
|
||||
|
|
|
@ -29,7 +29,8 @@ static void ToolbarThemePrefChanged(const char* aPref, void* aUserInfo);
|
|||
if (XRE_IsParentProcess()) {
|
||||
mozilla::Preferences::RegisterCallbackAndCall(
|
||||
&ToolbarThemePrefChanged,
|
||||
nsDependentCString(mozilla::StaticPrefs::GetPrefName_browser_theme_toolbar_theme()));
|
||||
nsDependentCString(
|
||||
mozilla::StaticPrefs::GetPrefName_browser_theme_toolbar_theme()));
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
|
@ -60,9 +61,10 @@ static void ToolbarThemePrefChanged(const char* aPref, void* aUserInfo);
|
|||
}
|
||||
|
||||
+ (NSSet*)keyPathsForValuesAffectingEffectiveAppearance {
|
||||
// Automatically notify any key-value observers of our effectiveAppearance property whenever the
|
||||
// pref or the NSApp's effectiveAppearance change.
|
||||
return [NSSet setWithObjects:@"toolbarTheme", @"_app.effectiveAppearance", nil];
|
||||
// Automatically notify any key-value observers of our effectiveAppearance
|
||||
// property whenever the pref or the NSApp's effectiveAppearance change.
|
||||
return
|
||||
[NSSet setWithObjects:@"toolbarTheme", @"_app.effectiveAppearance", nil];
|
||||
}
|
||||
|
||||
- (NSAppearance*)effectiveAppearance {
|
||||
|
|
|
@ -52,15 +52,16 @@ void SetDesktopImage(nsIFile* aImage) {
|
|||
}
|
||||
|
||||
// Use existing options for this screen
|
||||
NSDictionary* screenOptions =
|
||||
[[NSWorkspace sharedWorkspace] desktopImageOptionsForScreen:currentScreen];
|
||||
NSDictionary* screenOptions = [[NSWorkspace sharedWorkspace]
|
||||
desktopImageOptionsForScreen:currentScreen];
|
||||
|
||||
NSError* error = nil;
|
||||
if (![[NSWorkspace sharedWorkspace] setDesktopImageURL:url
|
||||
forScreen:currentScreen
|
||||
options:screenOptions
|
||||
error:&error]) {
|
||||
LOG("%s ERROR: setDesktopImageURL failed (%ld)", __func__, (long)[error code]);
|
||||
LOG("%s ERROR: setDesktopImageURL failed (%ld)", __func__,
|
||||
(long)[error code]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,9 @@ using namespace mozilla::widget;
|
|||
NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
|
||||
#endif
|
||||
|
||||
GfxInfo::GfxInfo() : mNumGPUsDetected(0), mOSXVersion{0} { mAdapterRAM[0] = mAdapterRAM[1] = 0; }
|
||||
GfxInfo::GfxInfo() : mNumGPUsDetected(0), mOSXVersion{0} {
|
||||
mAdapterRAM[0] = mAdapterRAM[1] = 0;
|
||||
}
|
||||
|
||||
static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
|
||||
switch (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion)) {
|
||||
|
@ -78,10 +80,11 @@ static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
|
|||
return OperatingSystem::Unknown;
|
||||
}
|
||||
// The following three functions are derived from Chromium code
|
||||
static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort, CFStringRef propertyName) {
|
||||
return IORegistryEntrySearchCFProperty(dspPort, kIOServicePlane, propertyName,
|
||||
kCFAllocatorDefault,
|
||||
kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||
static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort,
|
||||
CFStringRef propertyName) {
|
||||
return IORegistryEntrySearchCFProperty(
|
||||
dspPort, kIOServicePlane, propertyName, kCFAllocatorDefault,
|
||||
kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||
}
|
||||
|
||||
static uint32_t IntValueOfCFData(CFDataRef d) {
|
||||
|
@ -100,29 +103,33 @@ void GfxInfo::GetDeviceInfo() {
|
|||
|
||||
CFMutableDictionaryRef pci_dev_dict = IOServiceMatching("IOPCIDevice");
|
||||
io_iterator_t io_iter;
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict, &io_iter) !=
|
||||
kIOReturnSuccess) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false,
|
||||
"Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)");
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict,
|
||||
&io_iter) != kIOReturnSuccess) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
false,
|
||||
"Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)");
|
||||
return;
|
||||
}
|
||||
|
||||
io_registry_entry_t entry = IO_OBJECT_NULL;
|
||||
while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
|
||||
constexpr uint32_t kClassCodeDisplayVGA = 0x30000;
|
||||
CFTypeRef class_code_ref = SearchPortForProperty(entry, CFSTR("class-code"));
|
||||
CFTypeRef class_code_ref =
|
||||
SearchPortForProperty(entry, CFSTR("class-code"));
|
||||
if (class_code_ref) {
|
||||
const uint32_t class_code = IntValueOfCFData((CFDataRef)class_code_ref);
|
||||
CFRelease(class_code_ref);
|
||||
|
||||
if (class_code == kClassCodeDisplayVGA) {
|
||||
CFTypeRef vendor_id_ref = SearchPortForProperty(entry, CFSTR("vendor-id"));
|
||||
CFTypeRef vendor_id_ref =
|
||||
SearchPortForProperty(entry, CFSTR("vendor-id"));
|
||||
if (vendor_id_ref) {
|
||||
mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
|
||||
"0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
|
||||
CFRelease(vendor_id_ref);
|
||||
}
|
||||
CFTypeRef device_id_ref = SearchPortForProperty(entry, CFSTR("device-id"));
|
||||
CFTypeRef device_id_ref =
|
||||
SearchPortForProperty(entry, CFSTR("device-id"));
|
||||
if (device_id_ref) {
|
||||
mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
|
||||
"0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
|
||||
|
@ -145,14 +152,15 @@ void GfxInfo::GetDeviceInfo() {
|
|||
}
|
||||
|
||||
CFMutableDictionaryRef agx_dev_dict = IOServiceMatching("AGXAccelerator");
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict, &io_iter) ==
|
||||
kIOReturnSuccess) {
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict,
|
||||
&io_iter) == kIOReturnSuccess) {
|
||||
io_registry_entry_t entry = IO_OBJECT_NULL;
|
||||
while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
|
||||
CFTypeRef vendor_id_ref = SearchPortForProperty(entry, CFSTR("vendor-id"));
|
||||
CFTypeRef vendor_id_ref =
|
||||
SearchPortForProperty(entry, CFSTR("vendor-id"));
|
||||
if (vendor_id_ref) {
|
||||
mAdapterVendorID[mNumGPUsDetected].AppendPrintf("0x%04x",
|
||||
IntValueOfCFData((CFDataRef)vendor_id_ref));
|
||||
mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
|
||||
"0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
|
||||
CFRelease(vendor_id_ref);
|
||||
++mNumGPUsDetected;
|
||||
}
|
||||
|
@ -189,22 +197,32 @@ NS_IMETHODIMP
|
|||
GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
|
||||
|
||||
/* readonly attribute bool HasBattery; */
|
||||
NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString DWriteVersion; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) { return NS_ERROR_FAILURE; }
|
||||
GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) { return NS_ERROR_FAILURE; }
|
||||
GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString cleartypeParameters; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) { return NS_ERROR_FAILURE; }
|
||||
GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString windowProtocol; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString testType; */
|
||||
NS_IMETHODIMP
|
||||
|
@ -348,14 +366,20 @@ GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
|
|||
|
||||
/* readonly attribute DOMString adapterSubsysID; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) { return NS_ERROR_FAILURE; }
|
||||
GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterSubsysID2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) { return NS_ERROR_FAILURE; }
|
||||
GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean isGPU2Active; */
|
||||
NS_IMETHODIMP
|
||||
|
@ -372,60 +396,70 @@ void GfxInfo::AddCrashReportAnnotations() {
|
|||
GetAdapterDriverVersion(driverVersion);
|
||||
CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
|
||||
|
||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID, narrowVendorID);
|
||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID, narrowDeviceID);
|
||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDriverVersion,
|
||||
narrowDriverVersion);
|
||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
|
||||
narrowVendorID);
|
||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
|
||||
narrowDeviceID);
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion);
|
||||
}
|
||||
|
||||
// We don't support checking driver versions on Mac.
|
||||
#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \
|
||||
APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, DRIVER_COMPARISON_IGNORED, \
|
||||
V(0, 0, 0, 0), ruleId, "")
|
||||
#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \
|
||||
APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, \
|
||||
DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), ruleId, \
|
||||
"")
|
||||
|
||||
const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
|
||||
if (!sDriverInfo->Length()) {
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||
OperatingSystem::OSX, DeviceFamily::RadeonX1000, nsIGfxInfo::FEATURE_OPENGL_LAYERS,
|
||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
|
||||
OperatingSystem::OSX, DeviceFamily::RadeonX1000,
|
||||
nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||
OperatingSystem::OSX, DeviceFamily::Geforce7300GT, nsIGfxInfo::FEATURE_WEBGL_OPENGL,
|
||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
|
||||
nsIGfxInfo::FEATURE_GL_SWIZZLE,
|
||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
|
||||
// We block texture swizzling everwhere on mac because it's broken in some configurations
|
||||
// and we want to support GPU switching.
|
||||
OperatingSystem::OSX, DeviceFamily::Geforce7300GT,
|
||||
nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_MAC_7300_NO_WEBGL");
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||
OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
|
||||
nsIGfxInfo::FEATURE_GL_SWIZZLE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
|
||||
// We block texture swizzling everwhere on mac because it's broken in some
|
||||
// configurations and we want to support GPU switching.
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||
OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE,
|
||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE");
|
||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_MAC_GPU_SWITCHING_NO_SWIZZLE");
|
||||
|
||||
// Older generation Intel devices do not perform well with WebRender.
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||
OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked, nsIGfxInfo::FEATURE_WEBRENDER,
|
||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
|
||||
OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked,
|
||||
nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
|
||||
|
||||
// Intel HD3000 disabled due to bug 1661505
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||
OperatingSystem::OSX, DeviceFamily::IntelSandyBridge, nsIGfxInfo::FEATURE_WEBRENDER,
|
||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
|
||||
OperatingSystem::OSX, DeviceFamily::IntelSandyBridge,
|
||||
nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
|
||||
|
||||
// wgpu doesn't safely support OOB behavior on Metal yet.
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::All,
|
||||
nsIGfxInfo::FEATURE_WEBGPU, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS");
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||
OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_WEBGPU,
|
||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||
"FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS");
|
||||
}
|
||||
return *sDriverInfo;
|
||||
}
|
||||
|
||||
OperatingSystem GfxInfo::GetOperatingSystem() { return OSXVersionToOperatingSystem(mOSXVersion); }
|
||||
OperatingSystem GfxInfo::GetOperatingSystem() {
|
||||
return OSXVersionToOperatingSystem(mOSXVersion);
|
||||
}
|
||||
|
||||
nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
|
||||
nsAString& aSuggestedDriverVersion,
|
||||
const nsTArray<GfxDriverInfo>& aDriverInfo,
|
||||
nsACString& aFailureId,
|
||||
OperatingSystem* aOS /* = nullptr */) {
|
||||
nsresult GfxInfo::GetFeatureStatusImpl(
|
||||
int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
|
||||
const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
|
||||
OperatingSystem* aOS /* = nullptr */) {
|
||||
NS_ENSURE_ARG_POINTER(aStatus);
|
||||
aSuggestedDriverVersion.SetIsVoid(true);
|
||||
*aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
|
||||
|
@ -436,7 +470,8 @@ nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Don't evaluate special cases when we're evaluating the downloaded blocklist.
|
||||
// Don't evaluate special cases when we're evaluating the downloaded
|
||||
// blocklist.
|
||||
if (!aDriverInfo.Length()) {
|
||||
if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
|
||||
// See bug 1249659
|
||||
|
@ -460,8 +495,8 @@ nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
|
|||
}
|
||||
}
|
||||
|
||||
return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo,
|
||||
aFailureId, &os);
|
||||
return GfxInfoBase::GetFeatureStatusImpl(
|
||||
aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -23,19 +23,20 @@
|
|||
+ (NSImage*)iconImageFromImageContainer:(imgIContainer*)aImage
|
||||
withSize:(NSSize)aSize
|
||||
presContext:(const nsPresContext*)aPresContext
|
||||
computedStyle:(const mozilla::ComputedStyle*)aComputedStyle
|
||||
computedStyle:
|
||||
(const mozilla::ComputedStyle*)aComputedStyle
|
||||
scaleFactor:(CGFloat)aScaleFactor {
|
||||
bool isEntirelyBlack = false;
|
||||
NSImage* retainedImage = nil;
|
||||
nsresult rv;
|
||||
if (aScaleFactor != 0.0f) {
|
||||
rv = nsCocoaUtils::CreateNSImageFromImageContainer(aImage, imgIContainer::FRAME_CURRENT,
|
||||
aPresContext, aComputedStyle, &retainedImage,
|
||||
aScaleFactor, &isEntirelyBlack);
|
||||
rv = nsCocoaUtils::CreateNSImageFromImageContainer(
|
||||
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle,
|
||||
&retainedImage, aScaleFactor, &isEntirelyBlack);
|
||||
} else {
|
||||
rv = nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
|
||||
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle, &retainedImage,
|
||||
&isEntirelyBlack);
|
||||
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle,
|
||||
&retainedImage, &isEntirelyBlack);
|
||||
}
|
||||
|
||||
NSImage* image = [retainedImage autorelease];
|
||||
|
|
|
@ -68,7 +68,8 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
|
|||
withAppearance:(NSAppearance*)aAppearance
|
||||
asContextMenu:(BOOL)aIsContextMenu {
|
||||
MOZ_RELEASE_ASSERT(!mPendingOpening,
|
||||
"A menu is already waiting to open. Before opening the next one, either wait "
|
||||
"A menu is already waiting to open. Before opening the "
|
||||
"next one, either wait "
|
||||
"for this one to open or cancel the request.");
|
||||
|
||||
NSInteger handle = ++mLastHandle;
|
||||
|
@ -134,33 +135,36 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
|
|||
asContextMenu:(BOOL)aIsContextMenu {
|
||||
// There are multiple ways to display an NSMenu as a context menu.
|
||||
//
|
||||
// 1. We can return the NSMenu from -[ChildView menuForEvent:] and the NSView will open it for
|
||||
// us.
|
||||
// 2. We can call +[NSMenu popUpContextMenu:withEvent:forView:] inside a mouseDown handler with a
|
||||
// real mouse down event.
|
||||
// 3. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at a later time, with a real
|
||||
// mouse event that we stored earlier.
|
||||
// 4. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at any time, with a synthetic
|
||||
// mouse event that we create just for that purpose.
|
||||
// 5. We can call -[NSMenu popUpMenuPositioningItem:atLocation:inView:] and it just takes a
|
||||
// position, not an event.
|
||||
// 1. We can return the NSMenu from -[ChildView menuForEvent:] and the NSView
|
||||
// will open it for us.
|
||||
// 2. We can call +[NSMenu popUpContextMenu:withEvent:forView:] inside a
|
||||
// mouseDown handler with a real mouse down event.
|
||||
// 3. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at a later
|
||||
// time, with a real mouse event that we stored earlier.
|
||||
// 4. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at any time,
|
||||
// with a synthetic mouse event that we create just for that purpose.
|
||||
// 5. We can call -[NSMenu popUpMenuPositioningItem:atLocation:inView:] and
|
||||
// it just takes a position, not an event.
|
||||
//
|
||||
// 1-4 look the same, 5 looks different: 5 is made for use with NSPopUpButton, where the selected
|
||||
// item needs to be shown at a specific position. If a tall menu is opened with a position close
|
||||
// to the bottom edge of the screen, 5 results in a cropped menu with scroll arrows, even if the
|
||||
// entire menu would fit on the screen, due to the positioning constraint.
|
||||
// 1-2 only work if the menu contents are known synchronously during the call to menuForEvent or
|
||||
// 1-4 look the same, 5 looks different: 5 is made for use with NSPopUpButton,
|
||||
// where the selected item needs to be shown at a specific position. If a tall
|
||||
// menu is opened with a position close to the bottom edge of the screen, 5
|
||||
// results in a cropped menu with scroll arrows, even if the entire menu would
|
||||
// fit on the screen, due to the positioning constraint. 1-2 only work if the
|
||||
// menu contents are known synchronously during the call to menuForEvent or
|
||||
// during the mouseDown event handler.
|
||||
// NativeMenuMac::ShowAsContextMenu can be called at any time. It could be called during a
|
||||
// menuForEvent call (during a "contextmenu" event handler), or during a mouseDown handler, or at
|
||||
// a later time.
|
||||
// The code below uses option 4 as the preferred option for context menus because it's the
|
||||
// simplest: It works in all scenarios and it doesn't have the drawbacks of option 5. For popups
|
||||
// that aren't context menus and that should be positioned as close as possible to the given
|
||||
// screen position, we use option 5.
|
||||
// NativeMenuMac::ShowAsContextMenu can be called at any time. It could be
|
||||
// called during a menuForEvent call (during a "contextmenu" event handler),
|
||||
// or during a mouseDown handler, or at a later time. The code below uses
|
||||
// option 4 as the preferred option for context menus because it's the
|
||||
// simplest: It works in all scenarios and it doesn't have the drawbacks of
|
||||
// option 5. For popups that aren't context menus and that should be
|
||||
// positioned as close as possible to the given screen position, we use
|
||||
// option 5.
|
||||
|
||||
if (aAppearance) {
|
||||
#if !defined(MAC_OS_VERSION_11_0) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_11_0
|
||||
#if !defined(MAC_OS_VERSION_11_0) || \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_11_0
|
||||
if (nsCocoaFeatures::OnBigSurOrLater()) {
|
||||
#else
|
||||
if (@available(macOS 11.0, *)) {
|
||||
|
@ -174,18 +178,21 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
|
|||
|
||||
if (aView) {
|
||||
NSWindow* window = aView.window;
|
||||
NSPoint locationInWindow = nsCocoaUtils::ConvertPointFromScreen(window, aPosition);
|
||||
NSPoint locationInWindow =
|
||||
nsCocoaUtils::ConvertPointFromScreen(window, aPosition);
|
||||
if (aIsContextMenu) {
|
||||
// Create a synthetic event at the right location and open the menu [option 4].
|
||||
NSEvent* event = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
|
||||
location:locationInWindow
|
||||
modifierFlags:0
|
||||
timestamp:NSProcessInfo.processInfo.systemUptime
|
||||
windowNumber:window.windowNumber
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:1
|
||||
pressure:0.0f];
|
||||
// Create a synthetic event at the right location and open the menu
|
||||
// [option 4].
|
||||
NSEvent* event =
|
||||
[NSEvent mouseEventWithType:NSEventTypeRightMouseDown
|
||||
location:locationInWindow
|
||||
modifierFlags:0
|
||||
timestamp:NSProcessInfo.processInfo.systemUptime
|
||||
windowNumber:window.windowNumber
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:1
|
||||
pressure:0.0f];
|
||||
[NSMenu popUpContextMenu:aMenu withEvent:event forView:aView];
|
||||
} else {
|
||||
// For popups which are not context menus, we open the menu using [option
|
||||
|
@ -193,14 +200,18 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
|
|||
// corner of the menu. This path is used for anchored menupopups, so we
|
||||
// prefer option 5 over option 4 so that the menu doesn't get flipped if
|
||||
// space is tight.
|
||||
NSPoint locationInView = [aView convertPoint:locationInWindow fromView:nil];
|
||||
[aMenu popUpMenuPositioningItem:nil atLocation:locationInView inView:aView];
|
||||
NSPoint locationInView = [aView convertPoint:locationInWindow
|
||||
fromView:nil];
|
||||
[aMenu popUpMenuPositioningItem:nil
|
||||
atLocation:locationInView
|
||||
inView:aView];
|
||||
}
|
||||
} else {
|
||||
// Open the menu using popUpMenuPositioningItem:atLocation:inView: [option 5].
|
||||
// This is not preferred, because it positions the menu differently from how a native context
|
||||
// menu would be positioned; it enforces aPosition for the top left corner even if this
|
||||
// means that the menu will be displayed in a clipped fashion with scroll arrows.
|
||||
// Open the menu using popUpMenuPositioningItem:atLocation:inView: [option
|
||||
// 5]. This is not preferred, because it positions the menu differently from
|
||||
// how a native context menu would be positioned; it enforces aPosition for
|
||||
// the top left corner even if this means that the menu will be displayed in
|
||||
// a clipped fashion with scroll arrows.
|
||||
[aMenu popUpMenuPositioningItem:nil atLocation:aPosition inView:nil];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,9 @@ static MediaControlKey ToMediaControlKey(int aKeyCode) {
|
|||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
bool MediaHardwareKeysEventSourceMac::IsOpened() const { return mEventTap && mEventTapSource; }
|
||||
bool MediaHardwareKeysEventSourceMac::IsOpened() const {
|
||||
return mEventTap && mEventTapSource;
|
||||
}
|
||||
|
||||
bool MediaHardwareKeysEventSourceMac::Open() {
|
||||
LOG("Open MediaHardwareKeysEventSourceMac");
|
||||
|
@ -89,22 +91,24 @@ bool MediaHardwareKeysEventSourceMac::StartEventTap() {
|
|||
MOZ_ASSERT(!mEventTapSource);
|
||||
|
||||
// Add an event tap to intercept the system defined media key events.
|
||||
mEventTap =
|
||||
CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
|
||||
CGEventMaskBit(NX_SYSDEFINED), EventTapCallback, this);
|
||||
mEventTap = CGEventTapCreate(
|
||||
kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
|
||||
CGEventMaskBit(NX_SYSDEFINED), EventTapCallback, this);
|
||||
if (!mEventTap) {
|
||||
LOG("Fail to create event tap");
|
||||
return false;
|
||||
}
|
||||
|
||||
mEventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mEventTap, 0);
|
||||
mEventTapSource =
|
||||
CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mEventTap, 0);
|
||||
if (!mEventTapSource) {
|
||||
LOG("Fail to create an event tap source.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG("Add an event tap source to current loop");
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventTapSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventTapSource,
|
||||
kCFRunLoopCommonModes);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -115,18 +119,20 @@ void MediaHardwareKeysEventSourceMac::StopEventTap() {
|
|||
mEventTap = nullptr;
|
||||
}
|
||||
if (mEventTapSource) {
|
||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventTapSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventTapSource,
|
||||
kCFRunLoopCommonModes);
|
||||
CFRelease(mEventTapSource);
|
||||
mEventTapSource = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy proxy,
|
||||
CGEventType type, CGEventRef event,
|
||||
void* refcon) {
|
||||
CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(
|
||||
CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) {
|
||||
// Re-enable event tap when receiving disabled events.
|
||||
MediaHardwareKeysEventSourceMac* source = static_cast<MediaHardwareKeysEventSourceMac*>(refcon);
|
||||
if (type == kCGEventTapDisabledByUserInput || type == kCGEventTapDisabledByTimeout) {
|
||||
MediaHardwareKeysEventSourceMac* source =
|
||||
static_cast<MediaHardwareKeysEventSourceMac*>(refcon);
|
||||
if (type == kCGEventTapDisabledByUserInput ||
|
||||
type == kCGEventTapDisabledByTimeout) {
|
||||
MOZ_ASSERT(source->mEventTap);
|
||||
CGEventTapEnable(source->mEventTap, true);
|
||||
return event;
|
||||
|
@ -151,8 +157,9 @@ CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy pro
|
|||
// - keyRepeat = (keyFlags & 0x1);
|
||||
const NSInteger data1 = [nsEvent data1];
|
||||
int keyCode = (data1 & 0xFFFF0000) >> 16;
|
||||
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_NEXT && keyCode != NX_KEYTYPE_PREVIOUS &&
|
||||
keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND) {
|
||||
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_NEXT &&
|
||||
keyCode != NX_KEYTYPE_PREVIOUS && keyCode != NX_KEYTYPE_FAST &&
|
||||
keyCode != NX_KEYTYPE_REWIND) {
|
||||
return event;
|
||||
}
|
||||
|
||||
|
@ -173,7 +180,8 @@ CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy pro
|
|||
}
|
||||
|
||||
LOG2("Get media key %s", source, ToMediaControlKeyStr(keyCode));
|
||||
for (auto iter = source->mListeners.begin(); iter != source->mListeners.end(); ++iter) {
|
||||
for (auto iter = source->mListeners.begin(); iter != source->mListeners.end();
|
||||
++iter) {
|
||||
(*iter)->OnActionPerformed(MediaControlAction(ToMediaControlKey(keyCode)));
|
||||
}
|
||||
return event;
|
||||
|
|
|
@ -13,39 +13,45 @@ using namespace mozilla::dom;
|
|||
|
||||
// avoid redefined macro in unified build
|
||||
#undef LOG
|
||||
#define LOG(msg, ...) \
|
||||
MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
|
||||
("MediaHardwareKeysEventSourceMacMediaCenter=%p, " msg, this, ##__VA_ARGS__))
|
||||
#define LOG(msg, ...) \
|
||||
MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
|
||||
("MediaHardwareKeysEventSourceMacMediaCenter=%p, " msg, this, \
|
||||
##__VA_ARGS__))
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayPauseHandler() {
|
||||
MediaCenterEventHandler
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayPauseHandler() {
|
||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||
center.playbackState = center.playbackState == MPNowPlayingPlaybackStatePlaying
|
||||
? MPNowPlayingPlaybackStatePaused
|
||||
: MPNowPlayingPlaybackStatePlaying;
|
||||
center.playbackState =
|
||||
center.playbackState == MPNowPlayingPlaybackStatePlaying
|
||||
? MPNowPlayingPlaybackStatePaused
|
||||
: MPNowPlayingPlaybackStatePlaying;
|
||||
HandleEvent(MediaControlKey::Playpause);
|
||||
return MPRemoteCommandHandlerStatusSuccess;
|
||||
});
|
||||
}
|
||||
|
||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreateNextTrackHandler() {
|
||||
MediaCenterEventHandler
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::CreateNextTrackHandler() {
|
||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||
HandleEvent(MediaControlKey::Nexttrack);
|
||||
return MPRemoteCommandHandlerStatusSuccess;
|
||||
});
|
||||
}
|
||||
|
||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePreviousTrackHandler() {
|
||||
MediaCenterEventHandler
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::CreatePreviousTrackHandler() {
|
||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||
HandleEvent(MediaControlKey::Previoustrack);
|
||||
return MPRemoteCommandHandlerStatusSuccess;
|
||||
});
|
||||
}
|
||||
|
||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHandler() {
|
||||
MediaCenterEventHandler
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHandler() {
|
||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||
if (center.playbackState != MPNowPlayingPlaybackStatePlaying) {
|
||||
|
@ -56,7 +62,8 @@ MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHa
|
|||
});
|
||||
}
|
||||
|
||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseHandler() {
|
||||
MediaCenterEventHandler
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseHandler() {
|
||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||
if (center.playbackState != MPNowPlayingPlaybackStatePaused) {
|
||||
|
@ -67,7 +74,8 @@ MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseH
|
|||
});
|
||||
}
|
||||
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::MediaHardwareKeysEventSourceMacMediaCenter() {
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::
|
||||
MediaHardwareKeysEventSourceMacMediaCenter() {
|
||||
mPlayPauseHandler = CreatePlayPauseHandler();
|
||||
mNextTrackHandler = CreateNextTrackHandler();
|
||||
mPreviousTrackHandler = CreatePreviousTrackHandler();
|
||||
|
@ -76,7 +84,8 @@ MediaHardwareKeysEventSourceMacMediaCenter::MediaHardwareKeysEventSourceMacMedia
|
|||
LOG("Create MediaHardwareKeysEventSourceMacMediaCenter");
|
||||
}
|
||||
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::~MediaHardwareKeysEventSourceMacMediaCenter() {
|
||||
MediaHardwareKeysEventSourceMacMediaCenter::
|
||||
~MediaHardwareKeysEventSourceMacMediaCenter() {
|
||||
LOG("Destroy MediaHardwareKeysEventSourceMacMediaCenter");
|
||||
EndListeningForEvents();
|
||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||
|
@ -86,13 +95,15 @@ MediaHardwareKeysEventSourceMacMediaCenter::~MediaHardwareKeysEventSourceMacMedi
|
|||
void MediaHardwareKeysEventSourceMacMediaCenter::BeginListeningForEvents() {
|
||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||
center.playbackState = MPNowPlayingPlaybackStatePlaying;
|
||||
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
|
||||
MPRemoteCommandCenter* commandCenter =
|
||||
[MPRemoteCommandCenter sharedCommandCenter];
|
||||
commandCenter.togglePlayPauseCommand.enabled = true;
|
||||
[commandCenter.togglePlayPauseCommand addTargetWithHandler:mPlayPauseHandler];
|
||||
commandCenter.nextTrackCommand.enabled = true;
|
||||
[commandCenter.nextTrackCommand addTargetWithHandler:mNextTrackHandler];
|
||||
commandCenter.previousTrackCommand.enabled = true;
|
||||
[commandCenter.previousTrackCommand addTargetWithHandler:mPreviousTrackHandler];
|
||||
[commandCenter.previousTrackCommand
|
||||
addTargetWithHandler:mPreviousTrackHandler];
|
||||
commandCenter.playCommand.enabled = true;
|
||||
[commandCenter.playCommand addTargetWithHandler:mPlayHandler];
|
||||
commandCenter.pauseCommand.enabled = true;
|
||||
|
@ -103,7 +114,8 @@ void MediaHardwareKeysEventSourceMacMediaCenter::EndListeningForEvents() {
|
|||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||
center.playbackState = MPNowPlayingPlaybackStatePaused;
|
||||
center.nowPlayingInfo = nil;
|
||||
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
|
||||
MPRemoteCommandCenter* commandCenter =
|
||||
[MPRemoteCommandCenter sharedCommandCenter];
|
||||
commandCenter.togglePlayPauseCommand.enabled = false;
|
||||
[commandCenter.togglePlayPauseCommand removeTarget:nil];
|
||||
commandCenter.nextTrackCommand.enabled = false;
|
||||
|
@ -131,9 +143,12 @@ void MediaHardwareKeysEventSourceMacMediaCenter::Close() {
|
|||
MediaControlKeySource::Close();
|
||||
}
|
||||
|
||||
bool MediaHardwareKeysEventSourceMacMediaCenter::IsOpened() const { return mOpened; }
|
||||
bool MediaHardwareKeysEventSourceMacMediaCenter::IsOpened() const {
|
||||
return mOpened;
|
||||
}
|
||||
|
||||
void MediaHardwareKeysEventSourceMacMediaCenter::HandleEvent(MediaControlKey aEvent) {
|
||||
void MediaHardwareKeysEventSourceMacMediaCenter::HandleEvent(
|
||||
MediaControlKey aEvent) {
|
||||
for (auto iter = mListeners.begin(); iter != mListeners.end(); ++iter) {
|
||||
(*iter)->OnActionPerformed(MediaControlAction(aEvent));
|
||||
}
|
||||
|
|
|
@ -56,12 +56,16 @@ void NativeKeyBindings::Shutdown() {
|
|||
|
||||
NativeKeyBindings::NativeKeyBindings() {}
|
||||
|
||||
inline objc_selector* ToObjcSelectorPtr(SEL aSel) { return reinterpret_cast<objc_selector*>(aSel); }
|
||||
#define SEL_TO_COMMAND(aSel, aCommand) \
|
||||
mSelectorToCommand.InsertOrUpdate(ToObjcSelectorPtr(@selector(aSel)), aCommand)
|
||||
inline objc_selector* ToObjcSelectorPtr(SEL aSel) {
|
||||
return reinterpret_cast<objc_selector*>(aSel);
|
||||
}
|
||||
#define SEL_TO_COMMAND(aSel, aCommand) \
|
||||
mSelectorToCommand.InsertOrUpdate(ToObjcSelectorPtr(@selector(aSel)), \
|
||||
aCommand)
|
||||
|
||||
void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p NativeKeyBindings::Init", this));
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::Init", this));
|
||||
|
||||
// Many selectors have a one-to-one mapping to a Gecko command. Those mappings
|
||||
// are registered in mSelectorToCommand.
|
||||
|
@ -88,7 +92,8 @@ void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
|
|||
|
||||
// TODO: deleteTo* selectors are also supposed to add text to a kill buffer
|
||||
SEL_TO_COMMAND(deleteToBeginningOfLine:, Command::DeleteToBeginningOfLine);
|
||||
SEL_TO_COMMAND(deleteToBeginningOfParagraph:, Command::DeleteToBeginningOfLine);
|
||||
SEL_TO_COMMAND(deleteToBeginningOfParagraph:,
|
||||
Command::DeleteToBeginningOfLine);
|
||||
SEL_TO_COMMAND(deleteToEndOfLine:, Command::DeleteToEndOfLine);
|
||||
SEL_TO_COMMAND(deleteToEndOfParagraph:, Command::DeleteToEndOfLine);
|
||||
// SEL_TO_COMMAND(deleteToMark:, );
|
||||
|
@ -119,26 +124,34 @@ void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
|
|||
SEL_TO_COMMAND(moveForwardAndModifySelection:, Command::SelectCharNext);
|
||||
SEL_TO_COMMAND(moveLeft:, Command::CharPrevious);
|
||||
SEL_TO_COMMAND(moveLeftAndModifySelection:, Command::SelectCharPrevious);
|
||||
SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:, Command::SelectBeginLine);
|
||||
SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, Command::SelectEndLine);
|
||||
SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
|
||||
Command::SelectBeginLine);
|
||||
SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:,
|
||||
Command::SelectEndLine);
|
||||
SEL_TO_COMMAND(moveRight:, Command::CharNext);
|
||||
SEL_TO_COMMAND(moveRightAndModifySelection:, Command::SelectCharNext);
|
||||
SEL_TO_COMMAND(moveToBeginningOfDocument:, Command::MoveTop);
|
||||
SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:, Command::SelectTop);
|
||||
SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:,
|
||||
Command::SelectTop);
|
||||
SEL_TO_COMMAND(moveToBeginningOfLine:, Command::BeginLine);
|
||||
SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:, Command::SelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
|
||||
Command::SelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToBeginningOfParagraph:, Command::BeginLine);
|
||||
SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:, Command::SelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:,
|
||||
Command::SelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToEndOfDocument:, Command::MoveBottom);
|
||||
SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, Command::SelectBottom);
|
||||
SEL_TO_COMMAND(moveToEndOfLine:, Command::EndLine);
|
||||
SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, Command::SelectEndLine);
|
||||
SEL_TO_COMMAND(moveToEndOfParagraph:, Command::EndLine);
|
||||
SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, Command::SelectEndLine);
|
||||
SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:,
|
||||
Command::SelectEndLine);
|
||||
SEL_TO_COMMAND(moveToLeftEndOfLine:, Command::BeginLine);
|
||||
SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:, Command::SelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:,
|
||||
Command::SelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToRightEndOfLine:, Command::EndLine);
|
||||
SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, Command::SelectEndLine);
|
||||
SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:,
|
||||
Command::SelectEndLine);
|
||||
if (aType == NativeKeyBindingsType::SingleLineEditor) {
|
||||
SEL_TO_COMMAND(moveUp:, Command::BeginLine);
|
||||
} else {
|
||||
|
@ -146,7 +159,8 @@ void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
|
|||
}
|
||||
SEL_TO_COMMAND(moveUpAndModifySelection:, Command::SelectLinePrevious);
|
||||
SEL_TO_COMMAND(moveWordBackward:, Command::WordPrevious);
|
||||
SEL_TO_COMMAND(moveWordBackwardAndModifySelection:, Command::SelectWordPrevious);
|
||||
SEL_TO_COMMAND(moveWordBackwardAndModifySelection:,
|
||||
Command::SelectWordPrevious);
|
||||
SEL_TO_COMMAND(moveWordForward:, Command::WordNext);
|
||||
SEL_TO_COMMAND(moveWordForwardAndModifySelection:, Command::SelectWordNext);
|
||||
SEL_TO_COMMAND(moveWordLeft:, Command::WordPrevious);
|
||||
|
@ -191,7 +205,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
|||
MOZ_ASSERT(!aEvent.mFlags.mIsSynthesizedForTests);
|
||||
MOZ_ASSERT(aCommands.IsEmpty());
|
||||
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p NativeKeyBindings::GetEditCommands", this));
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::GetEditCommands", this));
|
||||
|
||||
// Recover the current event, which should always be the key down we are
|
||||
// responding to.
|
||||
|
@ -200,7 +215,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
|||
|
||||
if (!cocoaEvent || [cocoaEvent type] != NSEventTypeKeyDown) {
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event", this));
|
||||
("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event",
|
||||
this));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -210,7 +226,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
|||
NSEvent* originalEvent = cocoaEvent;
|
||||
|
||||
// TODO: Use KeyNameIndex rather than legacy keyCode.
|
||||
uint32_t remappedGeckoKeyCode = aEvent.GetRemappedKeyCode(aWritingMode.ref());
|
||||
uint32_t remappedGeckoKeyCode =
|
||||
aEvent.GetRemappedKeyCode(aWritingMode.ref());
|
||||
uint32_t remappedCocoaKeyCode = 0;
|
||||
switch (remappedGeckoKeyCode) {
|
||||
case NS_VK_UP:
|
||||
|
@ -229,8 +246,10 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
|||
MOZ_ASSERT_UNREACHABLE("Add a case for the new remapped key");
|
||||
return;
|
||||
}
|
||||
unichar ch = nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(remappedGeckoKeyCode);
|
||||
NSString* chars = [[[NSString alloc] initWithCharacters:&ch length:1] autorelease];
|
||||
unichar ch =
|
||||
nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(remappedGeckoKeyCode);
|
||||
NSString* chars = [[[NSString alloc] initWithCharacters:&ch
|
||||
length:1] autorelease];
|
||||
cocoaEvent = [NSEvent keyEventWithType:[originalEvent type]
|
||||
location:[originalEvent locationInWindow]
|
||||
modifierFlags:[originalEvent modifierFlags]
|
||||
|
@ -272,11 +291,12 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
|||
LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommands");
|
||||
}
|
||||
|
||||
void NativeKeyBindings::AppendEditCommandsForSelector(objc_selector* aSelector,
|
||||
nsTArray<CommandInt>& aCommands) const {
|
||||
void NativeKeyBindings::AppendEditCommandsForSelector(
|
||||
objc_selector* aSelector, nsTArray<CommandInt>& aCommands) const {
|
||||
// Try to find a simple mapping in the hashtable
|
||||
Command geckoCommand = Command::DoNothing;
|
||||
if (mSelectorToCommand.Get(aSelector, &geckoCommand) && geckoCommand != Command::DoNothing) {
|
||||
if (mSelectorToCommand.Get(aSelector, &geckoCommand) &&
|
||||
geckoCommand != Command::DoNothing) {
|
||||
aCommands.AppendElement(static_cast<CommandInt>(geckoCommand));
|
||||
} else if (aSelector == ToObjcSelectorPtr(@selector(selectLine:))) {
|
||||
// This is functional, but Cocoa's version is direction-less in that
|
||||
|
@ -300,7 +320,8 @@ void NativeKeyBindings::LogEditCommands(const nsTArray<CommandInt>& aCommands,
|
|||
}
|
||||
|
||||
if (aCommands.IsEmpty()) {
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p %s, no edit commands", this, aDescription));
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p %s, no edit commands", this, aDescription));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -313,10 +334,9 @@ void NativeKeyBindings::LogEditCommands(const nsTArray<CommandInt>& aCommands,
|
|||
}
|
||||
|
||||
// static
|
||||
void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||
const WidgetKeyboardEvent& aEvent,
|
||||
const Maybe<WritingMode>& aWritingMode,
|
||||
nsTArray<CommandInt>& aCommands) {
|
||||
void NativeKeyBindings::GetEditCommandsForTests(
|
||||
NativeKeyBindingsType aType, const WidgetKeyboardEvent& aEvent,
|
||||
const Maybe<WritingMode>& aWritingMode, nsTArray<CommandInt>& aCommands) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aEvent.IsTrusted());
|
||||
|
||||
// The following mapping is checked on Big Sur. Some of them are defined in:
|
||||
|
@ -325,8 +345,9 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
if (NS_WARN_IF(!instance)) {
|
||||
return;
|
||||
}
|
||||
switch (aWritingMode.isSome() ? aEvent.GetRemappedKeyNameIndex(aWritingMode.ref())
|
||||
: aEvent.mKeyNameIndex) {
|
||||
switch (aWritingMode.isSome()
|
||||
? aEvent.GetRemappedKeyNameIndex(aWritingMode.ref())
|
||||
: aEvent.mKeyNameIndex) {
|
||||
case KEY_NAME_INDEX_USE_STRING:
|
||||
if (!aEvent.IsControl() || aEvent.IsAlt() || aEvent.IsMeta()) {
|
||||
break;
|
||||
|
@ -337,21 +358,23 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:))
|
||||
: ToObjcSelectorPtr(@selector(moveToBeginningOfParagraphAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(@selector(
|
||||
moveToBeginningOfParagraphAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveBackward:))
|
||||
: ToObjcSelectorPtr(@selector(moveBackwardAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(@selector(
|
||||
moveBackwardAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
if (!aEvent.IsShift()) {
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteForward:)),
|
||||
aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(deleteForward:)), aCommands);
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
|
@ -359,42 +382,47 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveToEndOfParagraph:))
|
||||
: ToObjcSelectorPtr(@selector(moveToEndOfParagraphAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(
|
||||
@selector(moveToEndOfParagraphAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case 'f':
|
||||
case 'F':
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveForward:))
|
||||
: ToObjcSelectorPtr(@selector(moveForwardAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(@selector(
|
||||
moveForwardAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
if (!aEvent.IsShift()) {
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteBackward:)),
|
||||
aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(deleteBackward:)), aCommands);
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
case 'K':
|
||||
if (!aEvent.IsShift()) {
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(deleteToEndOfParagraph:)), aCommands);
|
||||
ToObjcSelectorPtr(@selector(deleteToEndOfParagraph:)),
|
||||
aCommands);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
case 'N':
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveDown:))
|
||||
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveDown:))
|
||||
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveUp:))
|
||||
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveUp:))
|
||||
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
default:
|
||||
|
@ -413,21 +441,22 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
}
|
||||
if (aEvent.IsAlt()) {
|
||||
// Shift and Control are ignored.
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteWordBackward:)),
|
||||
aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(deleteWordBackward:)), aCommands);
|
||||
break;
|
||||
}
|
||||
if (aEvent.IsControl()) {
|
||||
if (aEvent.IsShift()) {
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(deleteBackwardByDecomposingPreviousCharacter:)),
|
||||
ToObjcSelectorPtr(
|
||||
@selector(deleteBackwardByDecomposingPreviousCharacter:)),
|
||||
aCommands);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Shift is ignored.
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteBackward:)),
|
||||
aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(deleteBackward:)), aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_Delete:
|
||||
if (aEvent.IsControl() || aEvent.IsMeta()) {
|
||||
|
@ -435,13 +464,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
}
|
||||
if (aEvent.IsAlt()) {
|
||||
// Shift is ignored.
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteWordForward:)),
|
||||
aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(deleteWordForward:)), aCommands);
|
||||
break;
|
||||
}
|
||||
// Shift is ignored.
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteForward:)),
|
||||
aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(deleteForward:)), aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_PageDown:
|
||||
if (aEvent.IsControl() || aEvent.IsMeta()) {
|
||||
|
@ -449,12 +478,14 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
}
|
||||
if (aEvent.IsAlt()) {
|
||||
// Shift is ignored.
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(pageDown:)), aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(pageDown:)), aCommands);
|
||||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollPageDown:))
|
||||
: ToObjcSelectorPtr(@selector(pageDownAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(scrollPageDown:))
|
||||
: ToObjcSelectorPtr(@selector(pageDownAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_PageUp:
|
||||
|
@ -463,12 +494,14 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
}
|
||||
if (aEvent.IsAlt()) {
|
||||
// Shift is ignored.
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(pageUp:)), aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(pageUp:)), aCommands);
|
||||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollPageUp:))
|
||||
: ToObjcSelectorPtr(@selector(pageUpAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(scrollPageUp:))
|
||||
: ToObjcSelectorPtr(@selector(pageUpAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_Home:
|
||||
|
@ -478,7 +511,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(scrollToBeginningOfDocument:))
|
||||
: ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(
|
||||
@selector(moveToBeginningOfDocumentAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_End:
|
||||
|
@ -486,8 +520,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollToEndOfDocument:))
|
||||
: ToObjcSelectorPtr(@selector(moveToEndOfDocumentAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(scrollToEndOfDocument:))
|
||||
: ToObjcSelectorPtr(@selector
|
||||
(moveToEndOfDocumentAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_ArrowLeft:
|
||||
|
@ -498,7 +534,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveToLeftEndOfLine:))
|
||||
: ToObjcSelectorPtr(@selector(moveToLeftEndOfLineAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(@selector
|
||||
(moveToLeftEndOfLineAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
}
|
||||
|
@ -506,8 +543,9 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveLeft:))
|
||||
: ToObjcSelectorPtr(@selector(moveLeftAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveLeft:))
|
||||
: ToObjcSelectorPtr(@selector(moveLeftAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_ArrowRight:
|
||||
|
@ -518,7 +556,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveToRightEndOfLine:))
|
||||
: ToObjcSelectorPtr(@selector(moveToRightEndOfLineAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(@selector
|
||||
(moveToRightEndOfLineAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
}
|
||||
|
@ -526,8 +565,9 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveRight:))
|
||||
: ToObjcSelectorPtr(@selector(moveRightAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveRight:))
|
||||
: ToObjcSelectorPtr(@selector(moveRightAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_ArrowUp:
|
||||
|
@ -541,25 +581,30 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
|
||||
: ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(
|
||||
@selector(moveToBegginingOfDocumentAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
}
|
||||
if (aEvent.IsAlt()) {
|
||||
if (!aEvent.IsShift()) {
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(moveBackward:)),
|
||||
aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)), aCommands);
|
||||
ToObjcSelectorPtr(@selector(moveBackward:)), aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)),
|
||||
aCommands);
|
||||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(moveParagraphBackwardAndModifySelection:)), aCommands);
|
||||
ToObjcSelectorPtr(@selector
|
||||
(moveParagraphBackwardAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveUp:))
|
||||
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveUp:))
|
||||
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
case KEY_NAME_INDEX_ArrowDown:
|
||||
|
@ -573,32 +618,37 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
|||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveToEndOfDocument:))
|
||||
: ToObjcSelectorPtr(@selector(moveToEndOfDocumentAndModifySelection:)),
|
||||
: ToObjcSelectorPtr(@selector
|
||||
(moveToEndOfDocumentAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
}
|
||||
if (aEvent.IsAlt()) {
|
||||
if (!aEvent.IsShift()) {
|
||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(moveForward:)),
|
||||
aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(moveForward:)), aCommands);
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(moveToEndOfParagraph:)), aCommands);
|
||||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
ToObjcSelectorPtr(@selector(moveParagraphForwardAndModifySelection:)), aCommands);
|
||||
ToObjcSelectorPtr(@selector
|
||||
(moveParagraphForwardAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
}
|
||||
instance->AppendEditCommandsForSelector(
|
||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveDown:))
|
||||
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
|
||||
!aEvent.IsShift()
|
||||
? ToObjcSelectorPtr(@selector(moveDown:))
|
||||
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
|
||||
aCommands);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
instance->LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommandsForTests");
|
||||
instance->LogEditCommands(aCommands,
|
||||
"NativeKeyBindings::GetEditCommandsForTests");
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
|
|
|
@ -37,7 +37,8 @@ namespace widget {
|
|||
|
||||
NativeMenuMac::NativeMenuMac(dom::Element* aElement)
|
||||
: mElement(aElement), mContainerStatusBarItem(nil) {
|
||||
MOZ_RELEASE_ASSERT(aElement->IsAnyOfXULElements(nsGkAtoms::menu, nsGkAtoms::menupopup));
|
||||
MOZ_RELEASE_ASSERT(
|
||||
aElement->IsAnyOfXULElements(nsGkAtoms::menu, nsGkAtoms::menupopup));
|
||||
mMenuGroupOwner = new nsMenuGroupOwnerX(aElement, nullptr);
|
||||
mMenu = MakeRefPtr<nsMenuX>(nullptr, mMenuGroupOwner, aElement);
|
||||
mMenu->SetObserver(this);
|
||||
|
@ -78,9 +79,11 @@ bool NativeMenuMac::ActivateNativeMenuItemAt(const nsAString& aIndexString) {
|
|||
nsMenuUtilsX::CheckNativeMenuConsistency(menu);
|
||||
|
||||
NSString* locationString =
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading())
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
aIndexString.BeginReading())
|
||||
length:aIndexString.Length()];
|
||||
NSMenuItem* item = nsMenuUtilsX::NativeMenuItemWithLocation(menu, locationString, false);
|
||||
NSMenuItem* item =
|
||||
nsMenuUtilsX::NativeMenuItemWithLocation(menu, locationString, false);
|
||||
|
||||
// We can't perform an action on an item with a submenu, that will raise
|
||||
// an obj-c exception.
|
||||
|
@ -106,9 +109,11 @@ void NativeMenuMac::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
|
|||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
NSString* locationString =
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading())
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
aIndexString.BeginReading())
|
||||
length:aIndexString.Length()];
|
||||
NSArray<NSString*>* indexes = [locationString componentsSeparatedByString:@"|"];
|
||||
NSArray<NSString*>* indexes =
|
||||
[locationString componentsSeparatedByString:@"|"];
|
||||
RefPtr<nsMenuX> currentMenu = mMenu.get();
|
||||
|
||||
// now find the correct submenu
|
||||
|
@ -124,7 +129,9 @@ void NativeMenuMac::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
|
|||
}
|
||||
RefPtr<nsIContent> content = targetMenu->match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->Content();
|
||||
});
|
||||
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
|
||||
visible++;
|
||||
if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) {
|
||||
|
@ -175,8 +182,8 @@ void NativeMenuMac::OnMenuWillOpen(dom::Element* aPopupElement) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case
|
||||
// one of the observer notifications destroys us.
|
||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout
|
||||
// this function in case one of the observer notifications destroys us.
|
||||
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
||||
|
||||
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
||||
|
@ -185,8 +192,8 @@ void NativeMenuMac::OnMenuWillOpen(dom::Element* aPopupElement) {
|
|||
}
|
||||
|
||||
void NativeMenuMac::OnMenuDidOpen(dom::Element* aPopupElement) {
|
||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case
|
||||
// one of the observer notifications destroys us.
|
||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout
|
||||
// this function in case one of the observer notifications destroys us.
|
||||
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
||||
|
||||
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
||||
|
@ -200,8 +207,8 @@ void NativeMenuMac::OnMenuDidOpen(dom::Element* aPopupElement) {
|
|||
|
||||
void NativeMenuMac::OnMenuWillActivateItem(dom::Element* aPopupElement,
|
||||
dom::Element* aMenuItemElement) {
|
||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case
|
||||
// one of the observer notifications destroys us.
|
||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout
|
||||
// this function in case one of the observer notifications destroys us.
|
||||
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
||||
|
||||
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
||||
|
@ -210,8 +217,8 @@ void NativeMenuMac::OnMenuWillActivateItem(dom::Element* aPopupElement,
|
|||
}
|
||||
|
||||
void NativeMenuMac::OnMenuClosed(dom::Element* aPopupElement) {
|
||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case
|
||||
// one of the observer notifications destroys us.
|
||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout
|
||||
// this function in case one of the observer notifications destroys us.
|
||||
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
||||
|
||||
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
||||
|
@ -236,7 +243,8 @@ static NSAppearance* NativeAppearanceForContent(nsIContent* aContent) {
|
|||
return NSAppearanceForColorScheme(LookAndFeel::ColorSchemeForFrame(f));
|
||||
}
|
||||
|
||||
void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame, const CSSIntPoint& aPosition,
|
||||
void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame,
|
||||
const CSSIntPoint& aPosition,
|
||||
bool aIsContextMenu) {
|
||||
nsPresContext* pc = aClickedFrame->PresContext();
|
||||
auto cssToDesktopScale =
|
||||
|
@ -250,24 +258,29 @@ void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame, const CSSIntPoint
|
|||
NSAppearance* appearance = NativeAppearanceForContent(mMenu->Content());
|
||||
NSPoint locationOnScreen = nsCocoaUtils::GeckoPointToCocoaPoint(desktopPoint);
|
||||
|
||||
// Let the MOZMenuOpeningCoordinator do the actual opening, so that this ShowAsContextMenu call
|
||||
// does not spawn a nested event loop, which would be surprising to our callers.
|
||||
mOpeningHandle = [MOZMenuOpeningCoordinator.sharedInstance asynchronouslyOpenMenu:menu
|
||||
atScreenPosition:locationOnScreen
|
||||
forView:view
|
||||
withAppearance:appearance
|
||||
asContextMenu:aIsContextMenu];
|
||||
// Let the MOZMenuOpeningCoordinator do the actual opening, so that this
|
||||
// ShowAsContextMenu call does not spawn a nested event loop, which would be
|
||||
// surprising to our callers.
|
||||
mOpeningHandle = [MOZMenuOpeningCoordinator.sharedInstance
|
||||
asynchronouslyOpenMenu:menu
|
||||
atScreenPosition:locationOnScreen
|
||||
forView:view
|
||||
withAppearance:appearance
|
||||
asContextMenu:aIsContextMenu];
|
||||
}
|
||||
|
||||
bool NativeMenuMac::Close() {
|
||||
if (mOpeningHandle) {
|
||||
// In case the menu was trying to open, but this Close() call interrupted it, cancel opening.
|
||||
[MOZMenuOpeningCoordinator.sharedInstance cancelAsynchronousOpening:mOpeningHandle];
|
||||
// In case the menu was trying to open, but this Close() call interrupted
|
||||
// it, cancel opening.
|
||||
[MOZMenuOpeningCoordinator.sharedInstance
|
||||
cancelAsynchronousOpening:mOpeningHandle];
|
||||
}
|
||||
return mMenu->Close();
|
||||
}
|
||||
|
||||
RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(dom::Element* aElement) {
|
||||
RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(
|
||||
dom::Element* aElement) {
|
||||
nsTArray<RefPtr<dom::Element>> submenuChain;
|
||||
RefPtr<dom::Element> currentElement = aElement->GetParentElement();
|
||||
while (currentElement && currentElement != mElement) {
|
||||
|
@ -281,7 +294,8 @@ RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(dom::Element* aEleme
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Traverse submenuChain from shallow to deep, to find the nsMenuX that contains aElement.
|
||||
// Traverse submenuChain from shallow to deep, to find the nsMenuX that
|
||||
// contains aElement.
|
||||
submenuChain.Reverse();
|
||||
RefPtr<nsMenuX> menu = mMenu;
|
||||
for (const auto& submenu : submenuChain) {
|
||||
|
@ -321,7 +335,8 @@ static NSEventModifierFlags ConvertModifierFlags(Modifiers aModifiers) {
|
|||
return flags;
|
||||
}
|
||||
|
||||
void NativeMenuMac::ActivateItem(dom::Element* aItemElement, Modifiers aModifiers, int16_t aButton,
|
||||
void NativeMenuMac::ActivateItem(dom::Element* aItemElement,
|
||||
Modifiers aModifiers, int16_t aButton,
|
||||
ErrorResult& aRv) {
|
||||
RefPtr<nsMenuX> menu = GetOpenMenuContainingElement(aItemElement);
|
||||
if (!menu) {
|
||||
|
@ -343,27 +358,29 @@ void NativeMenuMac::ActivateItem(dom::Element* aItemElement, Modifiers aModifier
|
|||
NSMenuItem* nativeItem = [item->NativeNSMenuItem() retain];
|
||||
|
||||
// First, initiate the closing of the NSMenu.
|
||||
// This synchronously calls the menu delegate's menuDidClose handler. So menuDidClose is
|
||||
// what runs first; this matches the order of events for user-initiated menu item activation.
|
||||
// This call doesn't immediately hide the menu; the menu only hides once the stack unwinds
|
||||
// from NSMenu's nested "tracking" event loop.
|
||||
// This synchronously calls the menu delegate's menuDidClose handler. So
|
||||
// menuDidClose is what runs first; this matches the order of events for
|
||||
// user-initiated menu item activation. This call doesn't immediately hide the
|
||||
// menu; the menu only hides once the stack unwinds from NSMenu's nested
|
||||
// "tracking" event loop.
|
||||
[mMenu->NativeNSMenu() cancelTrackingWithoutAnimation];
|
||||
|
||||
// Next, call OnWillActivateItem. This also matches the order of calls that happen when a user
|
||||
// activates a menu item in the real world: -[MenuDelegate menu:willActivateItem:] runs after
|
||||
// menuDidClose.
|
||||
// Next, call OnWillActivateItem. This also matches the order of calls that
|
||||
// happen when a user activates a menu item in the real world: -[MenuDelegate
|
||||
// menu:willActivateItem:] runs after menuDidClose.
|
||||
menu->OnWillActivateItem(nativeItem);
|
||||
|
||||
// Finally, call ActivateItemAfterClosing. This also mimics the order in the real world:
|
||||
// menuItemHit is called after menu:willActivateItem:.
|
||||
menu->ActivateItemAfterClosing(std::move(item), ConvertModifierFlags(aModifiers), aButton);
|
||||
// Finally, call ActivateItemAfterClosing. This also mimics the order in the
|
||||
// real world: menuItemHit is called after menu:willActivateItem:.
|
||||
menu->ActivateItemAfterClosing(std::move(item),
|
||||
ConvertModifierFlags(aModifiers), aButton);
|
||||
|
||||
// Tell our native event loop that it should not process any more work before
|
||||
// unwinding the stack, so that we can get out of the menu's nested event loop
|
||||
// as fast as possible. This was needed to fix spurious failures in tests, where
|
||||
// a call to cancelTrackingWithoutAnimation was ignored if more native events were
|
||||
// processed before the event loop was exited. As a result, the menu stayed open
|
||||
// forever and the test never finished.
|
||||
// as fast as possible. This was needed to fix spurious failures in tests,
|
||||
// where a call to cancelTrackingWithoutAnimation was ignored if more native
|
||||
// events were processed before the event loop was exited. As a result, the
|
||||
// menu stayed open forever and the test never finished.
|
||||
MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES;
|
||||
|
||||
[nativeItem release];
|
||||
|
|
|
@ -14,14 +14,19 @@
|
|||
|
||||
namespace mozilla::widget {
|
||||
|
||||
void NativeMenuSupport::CreateNativeMenuBar(nsIWidget* aParent, dom::Element* aMenuBarElement) {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Attempting to create native menu bar on wrong thread!");
|
||||
void NativeMenuSupport::CreateNativeMenuBar(nsIWidget* aParent,
|
||||
dom::Element* aMenuBarElement) {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread(),
|
||||
"Attempting to create native menu bar on wrong thread!");
|
||||
|
||||
// Create the menubar and give it to the parent window. The parent takes ownership.
|
||||
static_cast<nsCocoaWindow*>(aParent)->SetMenuBar(MakeRefPtr<nsMenuBarX>(aMenuBarElement));
|
||||
// Create the menubar and give it to the parent window. The parent takes
|
||||
// ownership.
|
||||
static_cast<nsCocoaWindow*>(aParent)->SetMenuBar(
|
||||
MakeRefPtr<nsMenuBarX>(aMenuBarElement));
|
||||
}
|
||||
|
||||
already_AddRefed<NativeMenu> NativeMenuSupport::CreateNativeContextMenu(dom::Element* aPopup) {
|
||||
already_AddRefed<NativeMenu> NativeMenuSupport::CreateNativeContextMenu(
|
||||
dom::Element* aPopup) {
|
||||
return MakeAndAddRef<NativeMenuMac>(aPopup);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,8 @@ using namespace mozilla;
|
|||
- (void)_removeDisplayedNotification:(id<FakeNSUserNotification>)notification;
|
||||
@end
|
||||
|
||||
@interface mozNotificationCenterDelegate : NSObject <NSUserNotificationCenterDelegate> {
|
||||
@interface mozNotificationCenterDelegate
|
||||
: NSObject <NSUserNotificationCenterDelegate> {
|
||||
OSXNotificationCenter* mOSXNC;
|
||||
}
|
||||
- (id)initWithOSXNC:(OSXNotificationCenter*)osxnc;
|
||||
|
@ -78,11 +79,12 @@ using namespace mozilla;
|
|||
didActivateNotification:(id<FakeNSUserNotification>)notification {
|
||||
unsigned long long additionalActionIndex = ULLONG_MAX;
|
||||
if ([notification respondsToSelector:@selector(_alternateActionIndex)]) {
|
||||
NSNumber* alternateActionIndex = [(NSObject*)notification valueForKey:@"_alternateActionIndex"];
|
||||
NSNumber* alternateActionIndex =
|
||||
[(NSObject*)notification valueForKey:@"_alternateActionIndex"];
|
||||
additionalActionIndex = [alternateActionIndex unsignedLongLongValue];
|
||||
}
|
||||
mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"], notification.activationType,
|
||||
additionalActionIndex);
|
||||
mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"],
|
||||
notification.activationType, additionalActionIndex);
|
||||
}
|
||||
|
||||
- (BOOL)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
||||
|
@ -100,7 +102,8 @@ using namespace mozilla;
|
|||
}
|
||||
}
|
||||
|
||||
// This is an undocumented method that we need to be notified if a user clicks the close button.
|
||||
// This is an undocumented method that we need to be notified if a user clicks
|
||||
// the close button.
|
||||
- (void)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
||||
didDismissAlert:(id<FakeNSUserNotification>)notification {
|
||||
NSString* name = [[notification userInfo] valueForKey:@"name"];
|
||||
|
@ -122,7 +125,8 @@ class OSXNotificationInfo final : public nsISupports {
|
|||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
OSXNotificationInfo(NSString* name, nsIObserver* observer, const nsAString& alertCookie);
|
||||
OSXNotificationInfo(NSString* name, nsIObserver* observer,
|
||||
const nsAString& alertCookie);
|
||||
|
||||
NSString* mName;
|
||||
nsCOMPtr<nsIObserver> mObserver;
|
||||
|
@ -183,50 +187,56 @@ OSXNotificationCenter::~OSXNotificationCenter() {
|
|||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsIAlertsIconData, nsIAlertsDoNotDisturb,
|
||||
nsIAlertNotificationImageListener)
|
||||
NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsIAlertsIconData,
|
||||
nsIAlertsDoNotDisturb, nsIAlertNotificationImageListener)
|
||||
|
||||
nsresult OSXNotificationCenter::Init() {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
return (!!NSClassFromString(@"NSUserNotification")) ? NS_OK : NS_ERROR_FAILURE;
|
||||
return (!!NSClassFromString(@"NSUserNotification")) ? NS_OK
|
||||
: NS_ERROR_FAILURE;
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowAlertNotification(
|
||||
const nsAString& aImageUrl, const nsAString& aAlertTitle, const nsAString& aAlertText,
|
||||
bool aAlertTextClickable, const nsAString& aAlertCookie, nsIObserver* aAlertListener,
|
||||
const nsAString& aImageUrl, const nsAString& aAlertTitle,
|
||||
const nsAString& aAlertText, bool aAlertTextClickable,
|
||||
const nsAString& aAlertCookie, nsIObserver* aAlertListener,
|
||||
const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang,
|
||||
const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
|
||||
bool aRequireInteraction) {
|
||||
nsCOMPtr<nsIAlertNotification> alert = do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
|
||||
// vibrate is unused for now
|
||||
nsTArray<uint32_t> vibrate;
|
||||
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aBidi, aLang, aData, aPrincipal, aInPrivateBrowsing,
|
||||
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle, aAlertText,
|
||||
aAlertTextClickable, aAlertCookie, aBidi, aLang,
|
||||
aData, aPrincipal, aInPrivateBrowsing,
|
||||
aRequireInteraction, false, vibrate);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return ShowAlert(alert, aAlertListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowPersistentNotification(const nsAString& aPersistentData,
|
||||
nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener) {
|
||||
OSXNotificationCenter::ShowPersistentNotification(
|
||||
const nsAString& aPersistentData, nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener) {
|
||||
return ShowAlert(aAlert, aAlertListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert, nsIObserver* aAlertListener) {
|
||||
OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener) {
|
||||
return ShowAlertWithIconData(aAlert, aAlertListener, 0, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener, uint32_t aIconSize,
|
||||
nsIObserver* aAlertListener,
|
||||
uint32_t aIconSize,
|
||||
const uint8_t* aIconData) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
|
@ -248,13 +258,16 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
|||
rv = aAlert->GetSource(hostPort);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle));
|
||||
nsCOMPtr<nsIStringBundleService> sbs =
|
||||
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
sbs->CreateBundle("chrome://alerts/locale/alert.properties",
|
||||
getter_AddRefs(bundle));
|
||||
|
||||
if (!hostPort.IsEmpty() && bundle) {
|
||||
AutoTArray<nsString, 1> formatStrings = {hostPort};
|
||||
nsAutoString notificationSource;
|
||||
bundle->FormatStringFromName("source.label", formatStrings, notificationSource);
|
||||
bundle->FormatStringFromName("source.label", formatStrings,
|
||||
notificationSource);
|
||||
notification.subtitle = nsCocoaUtils::ToNSString(notificationSource);
|
||||
}
|
||||
|
||||
|
@ -268,17 +281,19 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
|||
notification.soundName = isSilent ? nil : NSUserNotificationDefaultSoundName;
|
||||
notification.hasActionButton = NO;
|
||||
|
||||
// If this is not an application/extension alert, show additional actions dealing with
|
||||
// permissions.
|
||||
// If this is not an application/extension alert, show additional actions
|
||||
// dealing with permissions.
|
||||
bool isActionable;
|
||||
if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) && isActionable) {
|
||||
nsAutoString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle;
|
||||
if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) &&
|
||||
isActionable) {
|
||||
nsAutoString closeButtonTitle, actionButtonTitle, disableButtonTitle,
|
||||
settingsButtonTitle;
|
||||
bundle->GetStringFromName("closeButton.title", closeButtonTitle);
|
||||
bundle->GetStringFromName("actionButton.label", actionButtonTitle);
|
||||
if (!hostPort.IsEmpty()) {
|
||||
AutoTArray<nsString, 1> formatStrings = {hostPort};
|
||||
bundle->FormatStringFromName("webActions.disableForOrigin.label", formatStrings,
|
||||
disableButtonTitle);
|
||||
bundle->FormatStringFromName("webActions.disableForOrigin.label",
|
||||
formatStrings, disableButtonTitle);
|
||||
}
|
||||
bundle->GetStringFromName("webActions.settings.label", settingsButtonTitle);
|
||||
|
||||
|
@ -288,15 +303,20 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
|||
// Notification Center preferences, and doesn't support the alternate
|
||||
// action menu.
|
||||
if ([notification respondsToSelector:@selector(set_showsButtons:)] &&
|
||||
[notification respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] &&
|
||||
[notification respondsToSelector:@selector(set_alternateActionButtonTitles:)]) {
|
||||
[notification
|
||||
respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] &&
|
||||
[notification
|
||||
respondsToSelector:@selector(set_alternateActionButtonTitles:)]) {
|
||||
notification.hasActionButton = YES;
|
||||
notification.actionButtonTitle = nsCocoaUtils::ToNSString(actionButtonTitle);
|
||||
notification.actionButtonTitle =
|
||||
nsCocoaUtils::ToNSString(actionButtonTitle);
|
||||
|
||||
[(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"];
|
||||
[(NSObject*)notification setValue:@(YES) forKey:@"_alwaysShowAlternateActionMenu"];
|
||||
[(NSObject*)notification setValue:@(YES)
|
||||
forKey:@"_alwaysShowAlternateActionMenu"];
|
||||
[(NSObject*)notification setValue:@[
|
||||
nsCocoaUtils::ToNSString(disableButtonTitle), nsCocoaUtils::ToNSString(settingsButtonTitle)
|
||||
nsCocoaUtils::ToNSString(disableButtonTitle),
|
||||
nsCocoaUtils::ToNSString(settingsButtonTitle)
|
||||
]
|
||||
forKey:@"_alternateActionButtonTitles"];
|
||||
}
|
||||
|
@ -315,19 +335,22 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
|||
if (!alertName) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
notification.userInfo =
|
||||
[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil]
|
||||
forKeys:[NSArray arrayWithObjects:@"name", nil]];
|
||||
notification.userInfo = [NSDictionary
|
||||
dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil]
|
||||
forKeys:[NSArray arrayWithObjects:@"name", nil]];
|
||||
|
||||
nsAutoString cookie;
|
||||
rv = aAlert->GetCookie(cookie);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
OSXNotificationInfo* osxni = new OSXNotificationInfo(alertName, aAlertListener, cookie);
|
||||
OSXNotificationInfo* osxni =
|
||||
new OSXNotificationInfo(alertName, aAlertListener, cookie);
|
||||
|
||||
// Show the favicon if supported on this version of OS X.
|
||||
if (aIconSize > 0 && [notification respondsToSelector:@selector(set_identityImage:)] &&
|
||||
[notification respondsToSelector:@selector(set_identityImageHasBorder:)]) {
|
||||
if (aIconSize > 0 &&
|
||||
[notification respondsToSelector:@selector(set_identityImage:)] &&
|
||||
[notification
|
||||
respondsToSelector:@selector(set_identityImageHasBorder:)]) {
|
||||
NSData* iconData = [NSData dataWithBytes:aIconData length:aIconSize];
|
||||
NSImage* icon = [[[NSImage alloc] initWithData:iconData] autorelease];
|
||||
|
||||
|
@ -339,8 +362,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
|||
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Show the notification without waiting for an image if there is no icon URL or
|
||||
// notification icons are not supported on this version of OS X.
|
||||
// Show the notification without waiting for an image if there is no icon URL
|
||||
// or notification icons are not supported on this version of OS X.
|
||||
if (![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
|
||||
CloseAlertCocoaString(alertName);
|
||||
mActiveAlerts.AppendElement(osxni);
|
||||
|
@ -353,7 +376,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
|||
mPendingAlerts.AppendElement(osxni);
|
||||
osxni->mPendingNotification = notification;
|
||||
// Wait six seconds for the image to load.
|
||||
rv = aAlert->LoadImage(6000, this, osxni, getter_AddRefs(osxni->mIconRequest));
|
||||
rv = aAlert->LoadImage(6000, this, osxni,
|
||||
getter_AddRefs(osxni->mIconRequest));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ShowPendingNotification(osxni);
|
||||
}
|
||||
|
@ -365,7 +389,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::CloseAlert(const nsAString& aAlertName, bool aContextClosed) {
|
||||
OSXNotificationCenter::CloseAlert(const nsAString& aAlertName,
|
||||
bool aContextClosed) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSString* alertName = nsCocoaUtils::ToNSString(aAlertName);
|
||||
|
@ -396,7 +421,8 @@ void OSXNotificationCenter::CloseAlertCocoaString(NSString* aAlertName) {
|
|||
OSXNotificationInfo* osxni = mActiveAlerts[i];
|
||||
if ([aAlertName isEqualToString:osxni->mName]) {
|
||||
if (osxni->mObserver) {
|
||||
osxni->mObserver->Observe(nullptr, "alertfinished", osxni->mCookie.get());
|
||||
osxni->mObserver->Observe(nullptr, "alertfinished",
|
||||
osxni->mCookie.get());
|
||||
}
|
||||
if (osxni->mIconRequest) {
|
||||
osxni->mIconRequest->Cancel(NS_BINDING_ABORTED);
|
||||
|
@ -410,9 +436,9 @@ void OSXNotificationCenter::CloseAlertCocoaString(NSString* aAlertName) {
|
|||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
void OSXNotificationCenter::OnActivate(NSString* aAlertName,
|
||||
NSUserNotificationActivationType aActivationType,
|
||||
unsigned long long aAdditionalActionIndex) {
|
||||
void OSXNotificationCenter::OnActivate(
|
||||
NSString* aAlertName, NSUserNotificationActivationType aActivationType,
|
||||
unsigned long long aAdditionalActionIndex) {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
if (!aAlertName) {
|
||||
|
@ -428,18 +454,22 @@ void OSXNotificationCenter::OnActivate(NSString* aAlertName,
|
|||
case NSUserNotificationActivationTypeActionButtonClicked:
|
||||
switch (aAdditionalActionIndex) {
|
||||
case OSXNotificationActionDisable:
|
||||
osxni->mObserver->Observe(nullptr, "alertdisablecallback", osxni->mCookie.get());
|
||||
osxni->mObserver->Observe(nullptr, "alertdisablecallback",
|
||||
osxni->mCookie.get());
|
||||
break;
|
||||
case OSXNotificationActionSettings:
|
||||
osxni->mObserver->Observe(nullptr, "alertsettingscallback", osxni->mCookie.get());
|
||||
osxni->mObserver->Observe(nullptr, "alertsettingscallback",
|
||||
osxni->mCookie.get());
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unknown NSUserNotification additional action clicked");
|
||||
NS_WARNING(
|
||||
"Unknown NSUserNotification additional action clicked");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
osxni->mObserver->Observe(nullptr, "alertclickcallback", osxni->mCookie.get());
|
||||
osxni->mObserver->Observe(nullptr, "alertclickcallback",
|
||||
osxni->mCookie.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -450,7 +480,8 @@ void OSXNotificationCenter::OnActivate(NSString* aAlertName,
|
|||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
void OSXNotificationCenter::ShowPendingNotification(OSXNotificationInfo* osxni) {
|
||||
void OSXNotificationCenter::ShowPendingNotification(
|
||||
OSXNotificationInfo* osxni) {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
if (osxni->mIconRequest) {
|
||||
|
@ -496,7 +527,8 @@ OSXNotificationCenter::OnImageMissing(nsISupports* aUserData) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aRequest) {
|
||||
OSXNotificationCenter::OnImageReady(nsISupports* aUserData,
|
||||
imgIRequest* aRequest) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
|
@ -511,9 +543,10 @@ OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aReques
|
|||
}
|
||||
|
||||
NSImage* cocoaImage = nil;
|
||||
// TODO: Pass pres context / ComputedStyle here to support context paint properties
|
||||
nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(image, imgIContainer::FRAME_FIRST,
|
||||
nullptr, nullptr, &cocoaImage);
|
||||
// TODO: Pass pres context / ComputedStyle here to support context paint
|
||||
// properties
|
||||
nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
|
||||
image, imgIContainer::FRAME_FIRST, nullptr, nullptr, &cocoaImage);
|
||||
(osxni->mPendingNotification).contentImage = cocoaImage;
|
||||
[cocoaImage release];
|
||||
ShowPendingNotification(osxni);
|
||||
|
@ -525,7 +558,9 @@ OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aReques
|
|||
|
||||
// nsIAlertsDoNotDisturb
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::GetManualDoNotDisturb(bool* aRetVal) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
OSXNotificationCenter::GetManualDoNotDisturb(bool* aRetVal) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::SetManualDoNotDisturb(bool aDoNotDisturb) {
|
||||
|
|
|
@ -79,19 +79,20 @@ ScreenHelperCocoa::~ScreenHelperCocoa() {
|
|||
static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
DesktopToLayoutDeviceScale contentsScaleFactor(nsCocoaUtils::GetBackingScaleFactor(aScreen));
|
||||
DesktopToLayoutDeviceScale contentsScaleFactor(
|
||||
nsCocoaUtils::GetBackingScaleFactor(aScreen));
|
||||
CSSToLayoutDeviceScale defaultCssScaleFactor(contentsScaleFactor.scale);
|
||||
NSRect frame = [aScreen frame];
|
||||
LayoutDeviceIntRect rect =
|
||||
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale);
|
||||
LayoutDeviceIntRect rect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(
|
||||
frame, contentsScaleFactor.scale);
|
||||
frame = [aScreen visibleFrame];
|
||||
LayoutDeviceIntRect availRect =
|
||||
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale);
|
||||
LayoutDeviceIntRect availRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(
|
||||
frame, contentsScaleFactor.scale);
|
||||
|
||||
// aScreen may be capable of displaying multiple pixel depths, for example by
|
||||
// transitioning to an HDR-capable depth when required by a window displayed on
|
||||
// the screen. We want to note the maximum capabilities of the screen, so we use
|
||||
// the largest depth it offers.
|
||||
// transitioning to an HDR-capable depth when required by a window displayed
|
||||
// on the screen. We want to note the maximum capabilities of the screen, so
|
||||
// we use the largest depth it offers.
|
||||
uint32_t pixelDepth = 0;
|
||||
const NSWindowDepth* depths = [aScreen supportedWindowDepths];
|
||||
for (size_t d = 0; NSWindowDepth depth = depths[d]; d++) {
|
||||
|
@ -116,16 +117,17 @@ static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
|
|||
dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
|
||||
}
|
||||
MOZ_LOG(sScreenLog, LogLevel::Debug,
|
||||
("New screen [%d %d %d %d (%d %d %d %d) %d %f %f %f]", rect.x, rect.y, rect.width,
|
||||
rect.height, availRect.x, availRect.y, availRect.width, availRect.height, pixelDepth,
|
||||
contentsScaleFactor.scale, defaultCssScaleFactor.scale, dpi));
|
||||
("New screen [%d %d %d %d (%d %d %d %d) %d %f %f %f]", rect.x, rect.y,
|
||||
rect.width, rect.height, availRect.x, availRect.y, availRect.width,
|
||||
availRect.height, pixelDepth, contentsScaleFactor.scale,
|
||||
defaultCssScaleFactor.scale, dpi));
|
||||
|
||||
// Getting the refresh rate is a little hard on OS X. We could use
|
||||
// CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little
|
||||
// involved. Ideally we could query it from vsync. For now, we leave it out.
|
||||
RefPtr<Screen> screen =
|
||||
new Screen(rect, availRect, pixelDepth, pixelDepth, 0, contentsScaleFactor,
|
||||
defaultCssScaleFactor, dpi, Screen::IsPseudoDisplay::No);
|
||||
RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth, 0,
|
||||
contentsScaleFactor, defaultCssScaleFactor,
|
||||
dpi, Screen::IsPseudoDisplay::No);
|
||||
return screen.forget();
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nullptr);
|
||||
|
@ -164,7 +166,8 @@ NSScreen* ScreenHelperCocoa::CocoaScreenForScreen(nsIScreen* aScreen) {
|
|||
aScreen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
aScreen->GetContentsScaleFactor(&scale);
|
||||
NSRect frame = [screen frame];
|
||||
LayoutDeviceIntRect frameRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, scale);
|
||||
LayoutDeviceIntRect frameRect =
|
||||
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, scale);
|
||||
if (rect == frameRect) {
|
||||
return screen;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -18,7 +18,8 @@
|
|||
namespace mozilla::widget {
|
||||
|
||||
auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
|
||||
const nsTArray<nsCString>& aLanguages) -> RefPtr<NativePromise> {
|
||||
const nsTArray<nsCString>& aLanguages)
|
||||
-> RefPtr<NativePromise> {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK
|
||||
|
||||
// TODO - Is this the most efficient path? Maybe we can write a new
|
||||
|
@ -26,7 +27,8 @@ auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
|
|||
CGImageRef imageRef = NULL;
|
||||
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(&aSurface, &imageRef);
|
||||
if (NS_FAILED(rv) || !imageRef) {
|
||||
return NativePromise::CreateAndReject("Failed to create CGImage"_ns, __func__);
|
||||
return NativePromise::CreateAndReject("Failed to create CGImage"_ns,
|
||||
__func__);
|
||||
}
|
||||
|
||||
auto promise = MakeRefPtr<NativePromise::Private>(__func__);
|
||||
|
@ -48,47 +50,63 @@ auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
|
|||
dom::TextRecognitionResult result;
|
||||
dom::TextRecognitionResult* pResult = &result;
|
||||
|
||||
// Define the request to use, which also handles the result. It will be run below
|
||||
// directly in this thread. After creating this request.
|
||||
VNRecognizeTextRequest* textRecognitionRequest = [[VNRecognizeTextRequest alloc]
|
||||
initWithCompletionHandler:^(VNRequest* _Nonnull request, NSError* _Nullable error) {
|
||||
NSArray<VNRecognizedTextObservation*>* observations = request.results;
|
||||
// Define the request to use, which also handles the result. It will
|
||||
// be run below directly in this thread. After creating this
|
||||
// request.
|
||||
VNRecognizeTextRequest* textRecognitionRequest =
|
||||
[[VNRecognizeTextRequest alloc] initWithCompletionHandler:^(
|
||||
VNRequest* _Nonnull request,
|
||||
NSError* _Nullable error) {
|
||||
NSArray<VNRecognizedTextObservation*>* observations =
|
||||
request.results;
|
||||
|
||||
[observations
|
||||
enumerateObjectsUsingBlock:^(VNRecognizedTextObservation* _Nonnull obj,
|
||||
NSUInteger idx, BOOL* _Nonnull stop) {
|
||||
// Requests the n top candidates for a recognized text string.
|
||||
VNRecognizedText* recognizedText = [obj topCandidates:1].firstObject;
|
||||
[observations enumerateObjectsUsingBlock:^(
|
||||
VNRecognizedTextObservation* _Nonnull obj,
|
||||
NSUInteger idx, BOOL* _Nonnull stop) {
|
||||
// Requests the n top candidates for a recognized text
|
||||
// string.
|
||||
VNRecognizedText* recognizedText =
|
||||
[obj topCandidates:1].firstObject;
|
||||
|
||||
// https://developer.apple.com/documentation/vision/vnrecognizedtext?language=objc
|
||||
auto& quad = *pResult->quads().AppendElement();
|
||||
CopyCocoaStringToXPCOMString(recognizedText.string, quad.string());
|
||||
quad.confidence() = recognizedText.confidence;
|
||||
// https://developer.apple.com/documentation/vision/vnrecognizedtext?language=objc
|
||||
auto& quad = *pResult->quads().AppendElement();
|
||||
CopyCocoaStringToXPCOMString(recognizedText.string,
|
||||
quad.string());
|
||||
quad.confidence() = recognizedText.confidence;
|
||||
|
||||
auto ToImagePoint = [](CGPoint aPoint) -> ImagePoint {
|
||||
return {static_cast<float>(aPoint.x), static_cast<float>(aPoint.y)};
|
||||
};
|
||||
*quad.points().AppendElement() = ToImagePoint(obj.bottomLeft);
|
||||
*quad.points().AppendElement() = ToImagePoint(obj.topLeft);
|
||||
*quad.points().AppendElement() = ToImagePoint(obj.topRight);
|
||||
*quad.points().AppendElement() = ToImagePoint(obj.bottomRight);
|
||||
}];
|
||||
auto ToImagePoint = [](CGPoint aPoint) -> ImagePoint {
|
||||
return {static_cast<float>(aPoint.x),
|
||||
static_cast<float>(aPoint.y)};
|
||||
};
|
||||
*quad.points().AppendElement() =
|
||||
ToImagePoint(obj.bottomLeft);
|
||||
*quad.points().AppendElement() = ToImagePoint(obj.topLeft);
|
||||
*quad.points().AppendElement() = ToImagePoint(obj.topRight);
|
||||
*quad.points().AppendElement() =
|
||||
ToImagePoint(obj.bottomRight);
|
||||
}];
|
||||
}];
|
||||
|
||||
textRecognitionRequest.recognitionLevel = VNRequestTextRecognitionLevelAccurate;
|
||||
textRecognitionRequest.recognitionLevel =
|
||||
VNRequestTextRecognitionLevelAccurate;
|
||||
textRecognitionRequest.recognitionLanguages = recognitionLanguages;
|
||||
textRecognitionRequest.usesLanguageCorrection = true;
|
||||
|
||||
// Send out the request. This blocks execution of this thread with an expensive
|
||||
// CPU call.
|
||||
// Send out the request. This blocks execution of this thread with
|
||||
// an expensive CPU call.
|
||||
NSError* error = nil;
|
||||
VNImageRequestHandler* requestHandler =
|
||||
[[[VNImageRequestHandler alloc] initWithCGImage:imageRef options:@{}] autorelease];
|
||||
[[[VNImageRequestHandler alloc] initWithCGImage:imageRef
|
||||
options:@{}]
|
||||
autorelease];
|
||||
|
||||
[requestHandler performRequests:@[ textRecognitionRequest ] error:&error];
|
||||
[requestHandler performRequests:@[ textRecognitionRequest ]
|
||||
error:&error];
|
||||
if (error != nil) {
|
||||
promise->Reject(
|
||||
nsPrintfCString("Failed to perform text recognition request (%ld)\n", error.code),
|
||||
nsPrintfCString(
|
||||
"Failed to perform text recognition request (%ld)\n",
|
||||
error.code),
|
||||
__func__);
|
||||
} else {
|
||||
promise->Resolve(std::move(result), __func__);
|
||||
|
|
|
@ -16,27 +16,29 @@ using namespace mozilla;
|
|||
@interface MOZVibrantView : NSVisualEffectView {
|
||||
VibrancyType mType;
|
||||
}
|
||||
- (instancetype)initWithFrame:(NSRect)aRect vibrancyType:(VibrancyType)aVibrancyType;
|
||||
- (instancetype)initWithFrame:(NSRect)aRect
|
||||
vibrancyType:(VibrancyType)aVibrancyType;
|
||||
@end
|
||||
|
||||
@interface MOZVibrantLeafView : MOZVibrantView
|
||||
@end
|
||||
|
||||
static NSVisualEffectState VisualEffectStateForVibrancyType(VibrancyType aType) {
|
||||
static NSVisualEffectState VisualEffectStateForVibrancyType(
|
||||
VibrancyType aType) {
|
||||
switch (aType) {
|
||||
case VibrancyType::TOOLTIP:
|
||||
case VibrancyType::MENU:
|
||||
case VibrancyType::HIGHLIGHTED_MENUITEM:
|
||||
// Tooltip and menu windows are never "key", so we need to tell the vibrancy effect to look
|
||||
// active regardless of window state.
|
||||
// Tooltip and menu windows are never "key", so we need to tell the
|
||||
// vibrancy effect to look active regardless of window state.
|
||||
return NSVisualEffectStateActive;
|
||||
default:
|
||||
return NSVisualEffectStateFollowsWindowActiveState;
|
||||
}
|
||||
}
|
||||
|
||||
static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(VibrancyType aType,
|
||||
BOOL* aOutIsEmphasized) {
|
||||
static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(
|
||||
VibrancyType aType, BOOL* aOutIsEmphasized) {
|
||||
switch (aType) {
|
||||
case VibrancyType::TOOLTIP:
|
||||
return (NSVisualEffectMaterial)NSVisualEffectMaterialToolTip;
|
||||
|
@ -90,8 +92,8 @@ static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(VibrancyType a
|
|||
|
||||
@end
|
||||
|
||||
bool VibrancyManager::UpdateVibrantRegion(VibrancyType aType,
|
||||
const LayoutDeviceIntRegion& aRegion) {
|
||||
bool VibrancyManager::UpdateVibrantRegion(
|
||||
VibrancyType aType, const LayoutDeviceIntRegion& aRegion) {
|
||||
if (aRegion.IsEmpty()) {
|
||||
return mVibrantRegions.Remove(uint32_t(aType));
|
||||
}
|
||||
|
@ -109,7 +111,10 @@ LayoutDeviceIntRegion VibrancyManager::GetUnionOfVibrantRegions() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
/* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType, BOOL aIsContainer) {
|
||||
return aIsContainer ? [[MOZVibrantView alloc] initWithFrame:NSZeroRect vibrancyType:aType]
|
||||
: [[MOZVibrantLeafView alloc] initWithFrame:NSZeroRect vibrancyType:aType];
|
||||
/* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType,
|
||||
BOOL aIsContainer) {
|
||||
return aIsContainer ? [[MOZVibrantView alloc] initWithFrame:NSZeroRect
|
||||
vibrancyType:aType]
|
||||
: [[MOZVibrantLeafView alloc] initWithFrame:NSZeroRect
|
||||
vibrancyType:aType];
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ ViewRegion::~ViewRegion() {
|
|||
}
|
||||
|
||||
bool ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion,
|
||||
const nsChildView& aCoordinateConverter, NSView* aContainerView,
|
||||
const nsChildView& aCoordinateConverter,
|
||||
NSView* aContainerView,
|
||||
NSView* (^aViewCreationCallback)()) {
|
||||
if (mRegion == aRegion) {
|
||||
return false;
|
||||
|
@ -33,7 +34,8 @@ bool ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion,
|
|||
// The mViews array is now empty.
|
||||
|
||||
size_t i = 0;
|
||||
for (auto iter = aRegion.RectIter(); !iter.Done() || i < viewsToRecycle.Length(); i++) {
|
||||
for (auto iter = aRegion.RectIter();
|
||||
!iter.Done() || i < viewsToRecycle.Length(); i++) {
|
||||
if (!iter.Done()) {
|
||||
NSView* view = nil;
|
||||
NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(iter.Get());
|
||||
|
|
|
@ -57,7 +57,8 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#define WAKE_LOCK_LOG(...) MOZ_LOG(gMacWakeLockLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
#define WAKE_LOCK_LOG(...) \
|
||||
MOZ_LOG(gMacWakeLockLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
static mozilla::LazyLogModule gMacWakeLockLog("MacWakeLock");
|
||||
|
||||
// A wake lock listener that disables screen saver when requested by
|
||||
|
@ -74,24 +75,30 @@ class MacWakeLockListener final : public nsIDOMMozWakeLockListener {
|
|||
IOPMAssertionID mAssertionNoDisplaySleepID = kIOPMNullAssertionID;
|
||||
IOPMAssertionID mAssertionNoIdleSleepID = kIOPMNullAssertionID;
|
||||
|
||||
NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) override {
|
||||
NS_IMETHOD Callback(const nsAString& aTopic,
|
||||
const nsAString& aState) override {
|
||||
if (!aTopic.EqualsASCII("screen") && !aTopic.EqualsASCII("audio-playing") &&
|
||||
!aTopic.EqualsASCII("video-playing")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// we should still hold the lock for background audio.
|
||||
if (aTopic.EqualsASCII("audio-playing") && aState.EqualsASCII("locked-background")) {
|
||||
if (aTopic.EqualsASCII("audio-playing") &&
|
||||
aState.EqualsASCII("locked-background")) {
|
||||
WAKE_LOCK_LOG("keep audio playing even in background");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool shouldKeepDisplayOn = aTopic.EqualsASCII("screen") || aTopic.EqualsASCII("video-playing");
|
||||
CFStringRef assertionType =
|
||||
shouldKeepDisplayOn ? kIOPMAssertionTypeNoDisplaySleep : kIOPMAssertionTypeNoIdleSleep;
|
||||
IOPMAssertionID& assertionId =
|
||||
shouldKeepDisplayOn ? mAssertionNoDisplaySleepID : mAssertionNoIdleSleepID;
|
||||
WAKE_LOCK_LOG("topic=%s, state=%s, shouldKeepDisplayOn=%d", NS_ConvertUTF16toUTF8(aTopic).get(),
|
||||
bool shouldKeepDisplayOn =
|
||||
aTopic.EqualsASCII("screen") || aTopic.EqualsASCII("video-playing");
|
||||
CFStringRef assertionType = shouldKeepDisplayOn
|
||||
? kIOPMAssertionTypeNoDisplaySleep
|
||||
: kIOPMAssertionTypeNoIdleSleep;
|
||||
IOPMAssertionID& assertionId = shouldKeepDisplayOn
|
||||
? mAssertionNoDisplaySleepID
|
||||
: mAssertionNoIdleSleepID;
|
||||
WAKE_LOCK_LOG("topic=%s, state=%s, shouldKeepDisplayOn=%d",
|
||||
NS_ConvertUTF16toUTF8(aTopic).get(),
|
||||
NS_ConvertUTF16toUTF8(aState).get(), shouldKeepDisplayOn);
|
||||
|
||||
// Note the wake lock code ensures that we're not sent duplicate
|
||||
|
@ -103,9 +110,10 @@ class MacWakeLockListener final : public nsIDOMMozWakeLockListener {
|
|||
}
|
||||
// Prevent screen saver.
|
||||
CFStringRef cf_topic = ::CFStringCreateWithCharacters(
|
||||
kCFAllocatorDefault, reinterpret_cast<const UniChar*>(aTopic.Data()), aTopic.Length());
|
||||
IOReturn success = ::IOPMAssertionCreateWithName(assertionType, kIOPMAssertionLevelOn,
|
||||
cf_topic, &assertionId);
|
||||
kCFAllocatorDefault, reinterpret_cast<const UniChar*>(aTopic.Data()),
|
||||
aTopic.Length());
|
||||
IOReturn success = ::IOPMAssertionCreateWithName(
|
||||
assertionType, kIOPMAssertionLevelOn, cf_topic, &assertionId);
|
||||
CFRelease(cf_topic);
|
||||
if (success != kIOReturnSuccess) {
|
||||
WAKE_LOCK_LOG("failed to disable screensaver");
|
||||
|
@ -133,19 +141,21 @@ static bool gAppShellMethodsSwizzled = false;
|
|||
|
||||
void OnUncaughtException(NSException* aException) {
|
||||
nsObjCExceptionLog(aException);
|
||||
MOZ_CRASH("Uncaught Objective C exception from NSSetUncaughtExceptionHandler");
|
||||
MOZ_CRASH(
|
||||
"Uncaught Objective C exception from NSSetUncaughtExceptionHandler");
|
||||
}
|
||||
|
||||
@implementation GeckoNSApplication
|
||||
|
||||
// Load is called very early during startup, when the Objective C runtime loads this class.
|
||||
// Load is called very early during startup, when the Objective C runtime loads
|
||||
// this class.
|
||||
+ (void)load {
|
||||
NSSetUncaughtExceptionHandler(OnUncaughtException);
|
||||
}
|
||||
|
||||
// This method is called from NSDefaultTopLevelErrorHandler, which is invoked when an Objective C
|
||||
// exception propagates up into the native event loop. It is possible that it is also called in
|
||||
// other cases.
|
||||
// This method is called from NSDefaultTopLevelErrorHandler, which is invoked
|
||||
// when an Objective C exception propagates up into the native event loop. It is
|
||||
// possible that it is also called in other cases.
|
||||
- (void)reportException:(NSException*)aException {
|
||||
if (ShouldIgnoreObjCException(aException)) {
|
||||
return;
|
||||
|
@ -154,14 +164,16 @@ void OnUncaughtException(NSException* aException) {
|
|||
nsObjCExceptionLog(aException);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
MOZ_CRASH("Uncaught Objective C exception from -[GeckoNSApplication reportException:]");
|
||||
MOZ_CRASH("Uncaught Objective C exception from -[GeckoNSApplication "
|
||||
"reportException:]");
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)sendEvent:(NSEvent*)anEvent {
|
||||
mozilla::BackgroundHangMonitor().NotifyActivity();
|
||||
|
||||
if ([anEvent type] == NSEventTypeApplicationDefined && [anEvent subtype] == kEventSubtypeTrace) {
|
||||
if ([anEvent type] == NSEventTypeApplicationDefined &&
|
||||
[anEvent subtype] == kEventSubtypeTrace) {
|
||||
mozilla::SignalTracerThread();
|
||||
return;
|
||||
}
|
||||
|
@ -208,7 +220,8 @@ void OnUncaughtException(NSException* aException) {
|
|||
NS_IMETHODIMP
|
||||
nsAppShell::ResumeNative(void) {
|
||||
nsresult retval = nsBaseAppShell::ResumeNative();
|
||||
if (NS_SUCCEEDED(retval) && (mSuspendNativeCount == 0) && mSkippedNativeCallback) {
|
||||
if (NS_SUCCEEDED(retval) && (mSuspendNativeCount == 0) &&
|
||||
mSkippedNativeCallback) {
|
||||
mSkippedNativeCallback = false;
|
||||
ScheduleNativeEventCallback();
|
||||
}
|
||||
|
@ -243,11 +256,13 @@ nsAppShell::~nsAppShell() {
|
|||
|
||||
if (mCFRunLoop) {
|
||||
if (mCFRunLoopSource) {
|
||||
::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
|
||||
::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource,
|
||||
kCFRunLoopCommonModes);
|
||||
::CFRelease(mCFRunLoopSource);
|
||||
}
|
||||
if (mCFRunLoopObserver) {
|
||||
::CFRunLoopRemoveObserver(mCFRunLoop, mCFRunLoopObserver, kCFRunLoopCommonModes);
|
||||
::CFRunLoopRemoveObserver(mCFRunLoop, mCFRunLoopObserver,
|
||||
kCFRunLoopCommonModes);
|
||||
::CFRelease(mCFRunLoopObserver);
|
||||
}
|
||||
::CFRelease(mCFRunLoop);
|
||||
|
@ -274,7 +289,8 @@ static void AddScreenWakeLockListener() {
|
|||
sWakeLockListener = new MacWakeLockListener();
|
||||
sPowerManagerService->AddWakeLockListener(sWakeLockListener);
|
||||
} else {
|
||||
NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
|
||||
NS_WARNING(
|
||||
"Failed to retrieve PowerManagerService, wakelocks will be broken!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,8 +304,8 @@ static void RemoveScreenWakeLockListener() {
|
|||
}
|
||||
}
|
||||
|
||||
void RunLoopObserverCallback(CFRunLoopObserverRef aObserver, CFRunLoopActivity aActivity,
|
||||
void* aInfo) {
|
||||
void RunLoopObserverCallback(CFRunLoopObserverRef aObserver,
|
||||
CFRunLoopActivity aActivity, void* aInfo) {
|
||||
static_cast<nsAppShell*>(aInfo)->OnRunLoopActivityChanged(aActivity);
|
||||
}
|
||||
|
||||
|
@ -298,30 +314,34 @@ void nsAppShell::OnRunLoopActivityChanged(CFRunLoopActivity aActivity) {
|
|||
mozilla::BackgroundHangMonitor().NotifyWait();
|
||||
}
|
||||
|
||||
// When the event loop is in its waiting state, we would like the profiler to know that the thread
|
||||
// is idle. The usual way to notify the profiler of idleness would be to place a profiler label
|
||||
// frame with the IDLE category on the stack, for the duration of the function that does the
|
||||
// waiting. However, since macOS uses an event loop model where "the event loop calls you", we do
|
||||
// not control the function that does the waiting; the waiting happens inside CFRunLoop code.
|
||||
// Instead, the run loop notifies us when it enters and exits the waiting state, by calling this
|
||||
// function.
|
||||
// So we do not have a function under our control that stays on the stack for the duration of the
|
||||
// wait. So, rather than putting an AutoProfilerLabel on the stack, we will manually push and pop
|
||||
// the label frame here.
|
||||
// The location in the stack where this label frame is inserted is somewhat arbitrary. In
|
||||
// practice, the label frame will be at the very tip of the stack, looking like it's "inside" the
|
||||
// When the event loop is in its waiting state, we would like the profiler to
|
||||
// know that the thread is idle. The usual way to notify the profiler of
|
||||
// idleness would be to place a profiler label frame with the IDLE category on
|
||||
// the stack, for the duration of the function that does the waiting. However,
|
||||
// since macOS uses an event loop model where "the event loop calls you", we
|
||||
// do not control the function that does the waiting; the waiting happens
|
||||
// inside CFRunLoop code. Instead, the run loop notifies us when it enters and
|
||||
// exits the waiting state, by calling this function. So we do not have a
|
||||
// function under our control that stays on the stack for the duration of the
|
||||
// wait. So, rather than putting an AutoProfilerLabel on the stack, we will
|
||||
// manually push and pop the label frame here. The location in the stack where
|
||||
// this label frame is inserted is somewhat arbitrary. In practice, the label
|
||||
// frame will be at the very tip of the stack, looking like it's "inside" the
|
||||
// mach_msg_trap wait function.
|
||||
if (aActivity == kCFRunLoopBeforeWaiting) {
|
||||
using ThreadRegistration = mozilla::profiler::ThreadRegistration;
|
||||
ThreadRegistration::WithOnThreadRef([&](ThreadRegistration::OnThreadRef aOnThreadRef) {
|
||||
ProfilingStack& profilingStack =
|
||||
aOnThreadRef.UnlockedConstReaderAndAtomicRWRef().ProfilingStackRef();
|
||||
mProfilingStackWhileWaiting = &profilingStack;
|
||||
uint8_t variableOnStack = 0;
|
||||
profilingStack.pushLabelFrame("Native event loop idle", nullptr, &variableOnStack,
|
||||
JS::ProfilingCategoryPair::IDLE, 0);
|
||||
profiler_thread_sleep();
|
||||
});
|
||||
ThreadRegistration::WithOnThreadRef(
|
||||
[&](ThreadRegistration::OnThreadRef aOnThreadRef) {
|
||||
ProfilingStack& profilingStack =
|
||||
aOnThreadRef.UnlockedConstReaderAndAtomicRWRef()
|
||||
.ProfilingStackRef();
|
||||
mProfilingStackWhileWaiting = &profilingStack;
|
||||
uint8_t variableOnStack = 0;
|
||||
profilingStack.pushLabelFrame("Native event loop idle", nullptr,
|
||||
&variableOnStack,
|
||||
JS::ProfilingCategoryPair::IDLE, 0);
|
||||
profiler_thread_sleep();
|
||||
});
|
||||
} else {
|
||||
if (mProfilingStackWhileWaiting) {
|
||||
mProfilingStackWhileWaiting->pop();
|
||||
|
@ -356,8 +376,9 @@ nsresult nsAppShell::Init() {
|
|||
mAutoreleasePools = ::CFArrayCreateMutable(nullptr, 0, nullptr);
|
||||
NS_ENSURE_STATE(mAutoreleasePools);
|
||||
|
||||
bool isNSApplicationProcessType = (XRE_GetProcessType() != GeckoProcessType_RDD) &&
|
||||
(XRE_GetProcessType() != GeckoProcessType_Socket);
|
||||
bool isNSApplicationProcessType =
|
||||
(XRE_GetProcessType() != GeckoProcessType_RDD) &&
|
||||
(XRE_GetProcessType() != GeckoProcessType_Socket);
|
||||
|
||||
if (isNSApplicationProcessType) {
|
||||
// This call initializes NSApplication unless:
|
||||
|
@ -391,14 +412,15 @@ nsresult nsAppShell::Init() {
|
|||
|
||||
::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
|
||||
|
||||
// Add a CFRunLoopObserver so that the profiler can be notified when we enter and exit the waiting
|
||||
// state.
|
||||
// Add a CFRunLoopObserver so that the profiler can be notified when we enter
|
||||
// and exit the waiting state.
|
||||
CFRunLoopObserverContext observerContext;
|
||||
PodZero(&observerContext);
|
||||
observerContext.info = this;
|
||||
|
||||
mCFRunLoopObserver = ::CFRunLoopObserverCreate(
|
||||
kCFAllocatorDefault, kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting | kCFRunLoopExit, true,
|
||||
kCFAllocatorDefault,
|
||||
kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting | kCFRunLoopExit, true,
|
||||
0, RunLoopObserverCallback, &observerContext);
|
||||
NS_ENSURE_STATE(mCFRunLoopObserver);
|
||||
|
||||
|
@ -491,9 +513,10 @@ void nsAppShell::ProcessGeckoEvents(void* aInfo) {
|
|||
// DummyEvent inserted by nsBaseAppShell::OnProcessNextEvent. This second
|
||||
// event will cause the second call to AcquireFirstMatchingEventInQueue in
|
||||
// nsAppShell::ProcessNextNativeEvent to return true. Which makes
|
||||
// nsBaseAppShell::OnProcessNextEvent call nsAppShell::ProcessNextNativeEvent
|
||||
// again during which it will loop until it sleeps because ProcessGeckoEvents()
|
||||
// won't be called for the DummyEvent.
|
||||
// nsBaseAppShell::OnProcessNextEvent call
|
||||
// nsAppShell::ProcessNextNativeEvent again during which it will loop until
|
||||
// it sleeps because ProcessGeckoEvents() won't be called for the
|
||||
// DummyEvent.
|
||||
//
|
||||
// This is not a good approach and we should fix things up so that only
|
||||
// one postEvent is needed.
|
||||
|
@ -551,8 +574,8 @@ void nsAppShell::ProcessGeckoEvents(void* aInfo) {
|
|||
if (self->mTerminated) {
|
||||
int32_t releaseCount = 0;
|
||||
if (self->mNativeEventScheduledDepth > self->mNativeEventCallbackDepth) {
|
||||
releaseCount =
|
||||
PR_ATOMIC_SET(&self->mNativeEventScheduledDepth, self->mNativeEventCallbackDepth);
|
||||
releaseCount = PR_ATOMIC_SET(&self->mNativeEventScheduledDepth,
|
||||
self->mNativeEventCallbackDepth);
|
||||
}
|
||||
while (releaseCount-- > self->mNativeEventCallbackDepth) self->Release();
|
||||
} else {
|
||||
|
@ -651,10 +674,10 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
|||
|
||||
if (mTerminated) return false;
|
||||
|
||||
// Do not call -[NSApplication nextEventMatchingMask:...] when we're trying to close a native
|
||||
// menu. Doing so could confuse the NSMenu's closing mechanism. Instead, we try to unwind the
|
||||
// stack as quickly as possible and return to the parent event loop. At that point, native events
|
||||
// will be processed.
|
||||
// Do not call -[NSApplication nextEventMatchingMask:...] when we're trying to
|
||||
// close a native menu. Doing so could confuse the NSMenu's closing mechanism.
|
||||
// Instead, we try to unwind the stack as quickly as possible and return to
|
||||
// the parent event loop. At that point, native events will be processed.
|
||||
if (MOZMenuOpeningCoordinator.needToUnwindForMenuClosing) {
|
||||
return false;
|
||||
}
|
||||
|
@ -700,12 +723,13 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
|||
}
|
||||
} else {
|
||||
// In at least 10.15, AcquireFirstMatchingEventInQueue will move 1
|
||||
// CGEvent from the CGEvent queue into the Carbon event queue. Unfortunately,
|
||||
// once an event has been moved to the Carbon event queue it's no longer a
|
||||
// candidate for coalescing. This means that even if we don't remove the
|
||||
// event from the queue, just calling AcquireFirstMatchingEventInQueue can
|
||||
// cause behaviour change. Prior to bug 1690687 landing, the event that we got
|
||||
// from AcquireFirstMatchingEventInQueue was often our own ApplicationDefined
|
||||
// CGEvent from the CGEvent queue into the Carbon event queue.
|
||||
// Unfortunately, once an event has been moved to the Carbon event queue
|
||||
// it's no longer a candidate for coalescing. This means that even if we
|
||||
// don't remove the event from the queue, just calling
|
||||
// AcquireFirstMatchingEventInQueue can cause behaviour change. Prior to
|
||||
// bug 1690687 landing, the event that we got from
|
||||
// AcquireFirstMatchingEventInQueue was often our own ApplicationDefined
|
||||
// event. However, once we stopped posting that event on every Gecko
|
||||
// event we're much more likely to get a CGEvent. When we have a high
|
||||
// amount of load on the main thread, we end up alternating between Gecko
|
||||
|
@ -719,8 +743,8 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
|||
// AcquireFirstMatchingEventInQueue() doesn't spin the (native) event
|
||||
// loop, though it does queue up any newly available events from the
|
||||
// window server.
|
||||
EventRef currentEvent =
|
||||
AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL, kEventQueueOptionsNone);
|
||||
EventRef currentEvent = AcquireFirstMatchingEventInQueue(
|
||||
currentEventQueue, 0, NULL, kEventQueueOptionsNone);
|
||||
if (!currentEvent) {
|
||||
continue;
|
||||
}
|
||||
|
@ -729,7 +753,8 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
|||
UInt32 eventClass = GetEventClass(currentEvent);
|
||||
bool osCocoaEvent =
|
||||
((eventClass == 'appl') || (eventClass == kEventClassAppleEvent) ||
|
||||
((eventClass == 'cgs ') && (eventKind != NSEventTypeApplicationDefined)));
|
||||
((eventClass == 'cgs ') &&
|
||||
(eventKind != NSEventTypeApplicationDefined)));
|
||||
// If attrs is kEventAttributeUserEvent or kEventAttributeMonitored
|
||||
// (i.e. a user input event), we shouldn't process it here while
|
||||
// aMayWait is false. Likewise if currentEvent will eventually be
|
||||
|
@ -761,8 +786,9 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
|||
} while (mRunningEventLoop);
|
||||
|
||||
if (eventProcessed) {
|
||||
moreEvents = (AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
|
||||
kEventQueueOptionsNone) != NULL);
|
||||
moreEvents =
|
||||
(AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
|
||||
kEventQueueOptionsNone) != NULL);
|
||||
}
|
||||
|
||||
mRunningEventLoop = wasRunningEventLoop;
|
||||
|
@ -790,7 +816,9 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
|||
// (Ventura) than on other versions of macOS. So we only use this hack on
|
||||
// macOS 13 and up.
|
||||
static void PinSidecarCoreTextCStringSections() {
|
||||
if (!dlopen("/System/Library/PrivateFrameworks/SidecarCore.framework/SidecarCore", RTLD_LAZY)) {
|
||||
if (!dlopen(
|
||||
"/System/Library/PrivateFrameworks/SidecarCore.framework/SidecarCore",
|
||||
RTLD_LAZY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -798,7 +826,8 @@ static void PinSidecarCoreTextCStringSections() {
|
|||
// normally runs automatically on the first Cmd-key combination.
|
||||
Class displayManagerClass = NSClassFromString(@"SidecarDisplayManager");
|
||||
if ([displayManagerClass respondsToSelector:@selector(sharedManager)]) {
|
||||
id sharedManager = [displayManagerClass performSelector:@selector(sharedManager)];
|
||||
id sharedManager =
|
||||
[displayManagerClass performSelector:@selector(sharedManager)];
|
||||
if ([sharedManager respondsToSelector:@selector(devices)]) {
|
||||
[sharedManager performSelector:@selector(devices)];
|
||||
}
|
||||
|
@ -877,7 +906,8 @@ nsAppShell::Exit(void) {
|
|||
// [NSApp stop:], so we have to assume that one extra call to [NSApp stop:]
|
||||
// will do the job.)
|
||||
BOOL cocoaModal = [NSApp _isRunningModal];
|
||||
NS_ASSERTION(!cocoaModal, "Don't call nsAppShell::Exit() from a modal event loop!");
|
||||
NS_ASSERTION(!cocoaModal,
|
||||
"Don't call nsAppShell::Exit() from a modal event loop!");
|
||||
if (cocoaModal) [NSApp stop:nullptr];
|
||||
[NSApp stop:nullptr];
|
||||
|
||||
|
@ -911,7 +941,8 @@ NS_IMETHODIMP
|
|||
nsAppShell::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NS_ASSERTION(mAutoreleasePools, "No stack on which to store autorelease pool");
|
||||
NS_ASSERTION(mAutoreleasePools,
|
||||
"No stack on which to store autorelease pool");
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
::CFArrayAppendValue(mAutoreleasePools, pool);
|
||||
|
@ -929,15 +960,17 @@ nsAppShell::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) {
|
|||
//
|
||||
// public
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::AfterProcessNextEvent(nsIThreadInternal* aThread, bool aEventWasProcessed) {
|
||||
nsAppShell::AfterProcessNextEvent(nsIThreadInternal* aThread,
|
||||
bool aEventWasProcessed) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
CFIndex count = ::CFArrayGetCount(mAutoreleasePools);
|
||||
|
||||
NS_ASSERTION(mAutoreleasePools && count, "Processed an event, but there's no autorelease pool?");
|
||||
NS_ASSERTION(mAutoreleasePools && count,
|
||||
"Processed an event, but there's no autorelease pool?");
|
||||
|
||||
const NSAutoreleasePool* pool =
|
||||
static_cast<const NSAutoreleasePool*>(::CFArrayGetValueAtIndex(mAutoreleasePools, count - 1));
|
||||
const NSAutoreleasePool* pool = static_cast<const NSAutoreleasePool*>(
|
||||
::CFArrayGetValueAtIndex(mAutoreleasePools, count - 1));
|
||||
::CFArrayRemoveValueAtIndex(mAutoreleasePools, count - 1);
|
||||
[pool release];
|
||||
|
||||
|
@ -952,11 +985,11 @@ void nsAppShell::InitMemoryPressureObserver() {
|
|||
// values. Hence this may need to be augmented with polling of the memory
|
||||
// pressure sysctls for lower latency reactions to OS memory pressure. This
|
||||
// was also observed when using DISPATCH_QUEUE_PRIORITY_HIGH.
|
||||
mMemoryPressureSource =
|
||||
dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
|
||||
DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN |
|
||||
DISPATCH_MEMORYPRESSURE_CRITICAL,
|
||||
dispatch_get_main_queue());
|
||||
mMemoryPressureSource = dispatch_source_create(
|
||||
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
|
||||
DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN |
|
||||
DISPATCH_MEMORYPRESSURE_CRITICAL,
|
||||
dispatch_get_main_queue());
|
||||
|
||||
dispatch_source_set_event_handler(mMemoryPressureSource, ^{
|
||||
dispatch_source_memorypressure_flags_t pressureLevel =
|
||||
|
@ -971,7 +1004,8 @@ void nsAppShell::InitMemoryPressureObserver() {
|
|||
nsAvailableMemoryWatcherBase::GetSingleton());
|
||||
}
|
||||
|
||||
void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t aPressureLevel) {
|
||||
void nsAppShell::OnMemoryPressureChanged(
|
||||
dispatch_source_memorypressure_flags_t aPressureLevel) {
|
||||
// The memory pressure dispatch source is created (above) with
|
||||
// dispatch_get_main_queue() which always fires on the main thread.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -1008,18 +1042,21 @@ void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t
|
|||
if ((self = [self init])) {
|
||||
mAppShell = aAppShell;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification
|
||||
object:NSApp];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationDidBecomeActive:)
|
||||
name:NSApplicationDidBecomeActiveNotification
|
||||
object:NSApp];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(timezoneChanged:)
|
||||
name:NSSystemTimeZoneDidChangeNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(applicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification
|
||||
object:NSApp];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(applicationDidBecomeActive:)
|
||||
name:NSApplicationDidBecomeActiveNotification
|
||||
object:NSApp];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(timezoneChanged:)
|
||||
name:NSSystemTimeZoneDidChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -1061,12 +1098,14 @@ void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t
|
|||
NSEvent* currentEvent = [NSApp currentEvent];
|
||||
if (currentEvent) {
|
||||
TextInputHandler::sLastModifierState =
|
||||
[currentEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||
[currentEvent modifierFlags] &
|
||||
NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->NotifyObservers(nullptr, NS_WIDGET_MAC_APP_ACTIVATE_OBSERVER_TOPIC, nullptr);
|
||||
observerService->NotifyObservers(
|
||||
nullptr, NS_WIDGET_MAC_APP_ACTIVATE_OBSERVER_TOPIC, nullptr);
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
|
@ -1111,8 +1150,9 @@ void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t
|
|||
// in XRE_Main(), which in particular means that ScopedXPCOMStartup's destructor
|
||||
// and NS_ShutdownXPCOM() never get called.
|
||||
- (void)nsAppShell_NSApplication_terminate:(id)sender {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification
|
||||
object:NSApp];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:NSApplicationWillTerminateNotification
|
||||
object:NSApp];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -32,9 +32,10 @@ mozilla::StaticRefPtr<nsITransferable> nsClipboard::sSelectionCache;
|
|||
int32_t nsClipboard::sSelectionCacheChangeCount = 0;
|
||||
|
||||
nsClipboard::nsClipboard()
|
||||
: nsBaseClipboard(mozilla::dom::ClipboardCapabilities(false /* supportsSelectionClipboard */,
|
||||
true /* supportsFindClipboard */,
|
||||
true /* supportsSelectionCache */)) {}
|
||||
: nsBaseClipboard(mozilla::dom::ClipboardCapabilities(
|
||||
false /* supportsSelectionClipboard */,
|
||||
true /* supportsFindClipboard */,
|
||||
true /* supportsSelectionCache */)) {}
|
||||
|
||||
nsClipboard::~nsClipboard() { ClearSelectionCache(); }
|
||||
|
||||
|
@ -45,15 +46,16 @@ namespace {
|
|||
// We separate this into its own function because after an @try, all local
|
||||
// variables within that function get marked as volatile, and our C++ type
|
||||
// system doesn't like volatile things.
|
||||
static NSData* GetDataFromPasteboard(NSPasteboard* aPasteboard, NSString* aType) {
|
||||
static NSData* GetDataFromPasteboard(NSPasteboard* aPasteboard,
|
||||
NSString* aType) {
|
||||
NSData* data = nil;
|
||||
@try {
|
||||
data = [aPasteboard dataForType:aType];
|
||||
} @catch (NSException* e) {
|
||||
NS_WARNING(
|
||||
nsPrintfCString("Exception raised while getting data from the pasteboard: \"%s - %s\"",
|
||||
[[e name] UTF8String], [[e reason] UTF8String])
|
||||
.get());
|
||||
NS_WARNING(nsPrintfCString("Exception raised while getting data from the "
|
||||
"pasteboard: \"%s - %s\"",
|
||||
[[e name] UTF8String], [[e reason] UTF8String])
|
||||
.get());
|
||||
mozilla::Unused << e;
|
||||
}
|
||||
return data;
|
||||
|
@ -80,7 +82,8 @@ void nsClipboard::SetSelectionCache(nsITransferable* aTransferable) {
|
|||
void nsClipboard::ClearSelectionCache() { SetSelectionCache(nullptr); }
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboardOwner* aOwner,
|
||||
nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
nsIClipboardOwner* aOwner,
|
||||
int32_t aWhichClipboard) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
|
@ -92,7 +95,8 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(aTransferable);
|
||||
NSDictionary* pasteboardOutputDict =
|
||||
PasteboardDictFromTransferable(aTransferable);
|
||||
if (!pasteboardOutputDict) return NS_ERROR_FAILURE;
|
||||
|
||||
unsigned int outputCount = [pasteboardOutputDict count];
|
||||
|
@ -100,8 +104,10 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
|
|||
NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
|
||||
MOZ_ASSERT(cocoaPasteboard);
|
||||
if (aWhichClipboard == kFindClipboard) {
|
||||
NSString* stringType = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
||||
[cocoaPasteboard declareTypes:[NSArray arrayWithObject:stringType] owner:nil];
|
||||
NSString* stringType =
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
||||
[cocoaPasteboard declareTypes:[NSArray arrayWithObject:stringType]
|
||||
owner:nil];
|
||||
} else {
|
||||
// Write everything else out to the general pasteboard.
|
||||
MOZ_ASSERT(aWhichClipboard == kGlobalClipboard);
|
||||
|
@ -112,32 +118,48 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
|
|||
NSString* currentKey = [outputKeys objectAtIndex:i];
|
||||
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
||||
if (aWhichClipboard == kFindClipboard) {
|
||||
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeString]]) {
|
||||
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:
|
||||
NSPasteboardTypeString]]) {
|
||||
[cocoaPasteboard setString:currentValue forType:currentKey];
|
||||
}
|
||||
} else {
|
||||
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeString]] ||
|
||||
[currentKey isEqualToString:[UTIHelper stringFromPboardType:kPublicUrlPboardType]] ||
|
||||
[currentKey isEqualToString:[UTIHelper stringFromPboardType:kPublicUrlNamePboardType]]) {
|
||||
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:
|
||||
NSPasteboardTypeString]] ||
|
||||
[currentKey
|
||||
isEqualToString:[UTIHelper
|
||||
stringFromPboardType:kPublicUrlPboardType]] ||
|
||||
[currentKey
|
||||
isEqualToString:
|
||||
[UTIHelper stringFromPboardType:kPublicUrlNamePboardType]]) {
|
||||
[cocoaPasteboard setString:currentValue forType:currentKey];
|
||||
} else if ([currentKey
|
||||
isEqualToString:[UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType]]) {
|
||||
[cocoaPasteboard setPropertyList:[pasteboardOutputDict valueForKey:currentKey]
|
||||
forType:currentKey];
|
||||
isEqualToString:
|
||||
[UTIHelper
|
||||
stringFromPboardType:kUrlsWithTitlesPboardType]]) {
|
||||
[cocoaPasteboard
|
||||
setPropertyList:[pasteboardOutputDict valueForKey:currentKey]
|
||||
forType:currentKey];
|
||||
} else if ([currentKey
|
||||
isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeHTML]]) {
|
||||
[cocoaPasteboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
|
||||
forType:currentKey];
|
||||
isEqualToString:[UTIHelper stringFromPboardType:
|
||||
NSPasteboardTypeHTML]]) {
|
||||
[cocoaPasteboard
|
||||
setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
|
||||
forType:currentKey];
|
||||
} else if ([currentKey
|
||||
isEqualToString:[UTIHelper stringFromPboardType:kMozFileUrlsPboardType]]) {
|
||||
isEqualToString:[UTIHelper stringFromPboardType:
|
||||
kMozFileUrlsPboardType]]) {
|
||||
[cocoaPasteboard writeObjects:currentValue];
|
||||
} else if ([currentKey
|
||||
isEqualToString:[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]]) {
|
||||
isEqualToString:
|
||||
[UTIHelper
|
||||
stringFromPboardType:(NSString*)kUTTypeFileURL]]) {
|
||||
[cocoaPasteboard setString:currentValue forType:currentKey];
|
||||
} else if ([currentKey
|
||||
isEqualToString:[UTIHelper stringFromPboardType:kPasteboardConcealedType]]) {
|
||||
// It's fine to set the data to null for this field - this field is an addition
|
||||
// to a value's other type and works like a flag.
|
||||
isEqualToString:
|
||||
[UTIHelper
|
||||
stringFromPboardType:kPasteboardConcealedType]]) {
|
||||
// It's fine to set the data to null for this field - this field is an
|
||||
// addition to a value's other type and works like a flag.
|
||||
[cocoaPasteboard setData:NULL forType:currentKey];
|
||||
} else {
|
||||
[cocoaPasteboard setData:currentValue forType:currentKey];
|
||||
|
@ -150,12 +172,12 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||
NSPasteboard* cocoaPasteboard) {
|
||||
nsresult nsClipboard::TransferableFromPasteboard(
|
||||
nsITransferable* aTransferable, NSPasteboard* cocoaPasteboard) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
// get flavor list that includes all acceptable flavors (including ones obtained through
|
||||
// conversion)
|
||||
// get flavor list that includes all acceptable flavors (including ones
|
||||
// obtained through conversion)
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
||||
|
@ -173,8 +195,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
|||
}
|
||||
|
||||
NSData* stringData;
|
||||
bool isRTF =
|
||||
[pboardType isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]];
|
||||
bool isRTF = [pboardType
|
||||
isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]];
|
||||
if (isRTF) {
|
||||
stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
|
||||
} else {
|
||||
|
@ -187,23 +209,25 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
|||
}
|
||||
[stringData getBytes:clipboardDataPtr length:dataLength];
|
||||
|
||||
// The DOM only wants LF, so convert from MacOS line endings to DOM line endings.
|
||||
// The DOM only wants LF, so convert from MacOS line endings to DOM line
|
||||
// endings.
|
||||
int32_t signedDataLength = dataLength;
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(isRTF, &clipboardDataPtr,
|
||||
&signedDataLength);
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
|
||||
isRTF, &clipboardDataPtr, &signedDataLength);
|
||||
dataLength = signedDataLength;
|
||||
|
||||
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
||||
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
|
||||
if ((dataLength > 2) &&
|
||||
((clipboardDataPtrNoBOM[0] == 0xFEFF) || (clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
||||
if ((dataLength > 2) && ((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
|
||||
(clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
||||
dataLength -= sizeof(char16_t);
|
||||
clipboardDataPtrNoBOM += 1;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
flavorStr, clipboardDataPtrNoBOM, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
|
||||
free(clipboardDataPtr);
|
||||
break;
|
||||
|
@ -220,11 +244,14 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
|||
continue;
|
||||
}
|
||||
|
||||
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable, flavorStr, item);
|
||||
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable,
|
||||
flavorStr, item);
|
||||
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
NSString* type = [cocoaPasteboard
|
||||
availableTypeFromArray:
|
||||
[NSArray arrayWithObject:[UTIHelper stringFromPboardType:kMozCustomTypesPboardType]]];
|
||||
[NSArray
|
||||
arrayWithObject:[UTIHelper stringFromPboardType:
|
||||
kMozCustomTypesPboardType]]];
|
||||
if (!type) {
|
||||
continue;
|
||||
}
|
||||
|
@ -242,19 +269,26 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
|||
[pasteboardData getBytes:clipboardDataPtr length:dataLength];
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
flavorStr, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
|
||||
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
|
||||
free(clipboardDataPtr);
|
||||
} else if (flavorStr.EqualsLiteral(kJPEGImageMime) || flavorStr.EqualsLiteral(kJPGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) {
|
||||
} else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kPNGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kGIFImageMime)) {
|
||||
// Figure out if there's data on the pasteboard we can grab (sanity check)
|
||||
NSString* type = [cocoaPasteboard
|
||||
availableTypeFromArray:
|
||||
[NSArray arrayWithObjects:[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL],
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypePNG], nil]];
|
||||
[NSArray
|
||||
arrayWithObjects:
|
||||
[UTIHelper
|
||||
stringFromPboardType:(NSString*)kUTTypeFileURL],
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypePNG],
|
||||
nil]];
|
||||
if (!type) continue;
|
||||
|
||||
// Read data off the clipboard
|
||||
|
@ -263,7 +297,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
|||
|
||||
// Figure out what type we're converting to
|
||||
CFStringRef outputType = NULL;
|
||||
if (flavorStr.EqualsLiteral(kJPEGImageMime) || flavorStr.EqualsLiteral(kJPGImageMime))
|
||||
if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime))
|
||||
outputType = CFSTR("public.jpeg");
|
||||
else if (flavorStr.EqualsLiteral(kPNGImageMime))
|
||||
outputType = CFSTR("public.png");
|
||||
|
@ -276,20 +311,23 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
|||
// Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
|
||||
// and safely in most cases (like ObjC). A notable exception is CFRelease.
|
||||
NSDictionary* options = [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue, kCGImageSourceShouldAllowFloat,
|
||||
type, kCGImageSourceTypeIdentifierHint, nil];
|
||||
dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue,
|
||||
kCGImageSourceShouldAllowFloat, type,
|
||||
kCGImageSourceTypeIdentifierHint, nil];
|
||||
CGImageSourceRef source = nullptr;
|
||||
if (type == [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]) {
|
||||
NSString* urlStr = [cocoaPasteboard stringForType:type];
|
||||
NSURL* url = [NSURL URLWithString:urlStr];
|
||||
source = CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options);
|
||||
source =
|
||||
CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options);
|
||||
} else {
|
||||
source = CGImageSourceCreateWithData((CFDataRef)pasteboardData, (CFDictionaryRef)options);
|
||||
source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
|
||||
(CFDictionaryRef)options);
|
||||
}
|
||||
|
||||
NSMutableData* encodedData = [NSMutableData data];
|
||||
CGImageDestinationRef dest =
|
||||
CGImageDestinationCreateWithData((CFMutableDataRef)encodedData, outputType, 1, NULL);
|
||||
CGImageDestinationRef dest = CGImageDestinationCreateWithData(
|
||||
(CFMutableDataRef)encodedData, outputType, 1, NULL);
|
||||
CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
|
||||
bool successfullyConverted = CGImageDestinationFinalize(dest);
|
||||
|
||||
|
@ -297,7 +335,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
|||
// Put the converted data in a form Gecko can understand
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
NS_NewByteInputStream(getter_AddRefs(byteStream),
|
||||
mozilla::Span((const char*)[encodedData bytes], [encodedData length]),
|
||||
mozilla::Span((const char*)[encodedData bytes],
|
||||
[encodedData length]),
|
||||
NS_ASSIGNMENT_COPY);
|
||||
|
||||
aTransferable->SetTransferData(flavorStr.get(), byteStream);
|
||||
|
@ -321,19 +360,21 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) {
|
||||
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
int32_t aWhichClipboard) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
if (kSelectionCache == aWhichClipboard) {
|
||||
if (!sSelectionCache) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// get flavor list that includes all acceptable flavors (including ones obtained through
|
||||
// conversion)
|
||||
// get flavor list that includes all acceptable flavors (including ones
|
||||
// obtained through conversion)
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -342,7 +383,8 @@ nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhi
|
|||
|
||||
for (const auto& flavor : flavors) {
|
||||
nsCOMPtr<nsISupports> dataSupports;
|
||||
rv = sSelectionCache->GetTransferData(flavor.get(), getter_AddRefs(dataSupports));
|
||||
rv = sSelectionCache->GetTransferData(flavor.get(),
|
||||
getter_AddRefs(dataSupports));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
CLIPBOARD_LOG("%s: getting %s from cache.", __FUNCTION__, flavor.get());
|
||||
aTransferable->SetTransferData(flavor.get(), dataSupports);
|
||||
|
@ -364,18 +406,22 @@ nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhi
|
|||
}
|
||||
|
||||
// returns true if we have *any* of the passed in flavors available for pasting
|
||||
mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavors(
|
||||
mozilla::Result<bool, nsresult>
|
||||
nsClipboard::HasNativeClipboardDataMatchingFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
if (kSelectionCache == aWhichClipboard) {
|
||||
nsTArray<nsCString> transferableFlavors;
|
||||
if (sSelectionCache &&
|
||||
NS_SUCCEEDED(sSelectionCache->FlavorsTransferableCanImport(transferableFlavors))) {
|
||||
NS_SUCCEEDED(sSelectionCache->FlavorsTransferableCanImport(
|
||||
transferableFlavors))) {
|
||||
if (CLIPBOARD_LOG_ENABLED()) {
|
||||
CLIPBOARD_LOG(" SelectionCache types (nums %zu)\n", transferableFlavors.Length());
|
||||
CLIPBOARD_LOG(" SelectionCache types (nums %zu)\n",
|
||||
transferableFlavors.Length());
|
||||
for (const auto& transferableFlavor : transferableFlavors) {
|
||||
CLIPBOARD_LOG(" MIME %s", transferableFlavor.get());
|
||||
}
|
||||
|
@ -417,8 +463,8 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
|
|||
for (auto& mimeType : aFlavorList) {
|
||||
NSString* pboardType = nil;
|
||||
if (nsClipboard::IsStringType(mimeType, &pboardType)) {
|
||||
NSString* availableType =
|
||||
[cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
|
||||
NSString* availableType = [cocoaPasteboard
|
||||
availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
|
||||
if (availableType && [availableType isEqualToString:pboardType]) {
|
||||
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
||||
return true;
|
||||
|
@ -426,17 +472,24 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
|
|||
} else if (mimeType.EqualsLiteral(kCustomTypesMime)) {
|
||||
NSString* availableType = [cocoaPasteboard
|
||||
availableTypeFromArray:
|
||||
[NSArray arrayWithObject:[UTIHelper stringFromPboardType:kMozCustomTypesPboardType]]];
|
||||
[NSArray
|
||||
arrayWithObject:[UTIHelper stringFromPboardType:
|
||||
kMozCustomTypesPboardType]]];
|
||||
if (availableType) {
|
||||
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
||||
return true;
|
||||
}
|
||||
} else if (mimeType.EqualsLiteral(kJPEGImageMime) || mimeType.EqualsLiteral(kJPGImageMime) ||
|
||||
mimeType.EqualsLiteral(kPNGImageMime) || mimeType.EqualsLiteral(kGIFImageMime)) {
|
||||
} else if (mimeType.EqualsLiteral(kJPEGImageMime) ||
|
||||
mimeType.EqualsLiteral(kJPGImageMime) ||
|
||||
mimeType.EqualsLiteral(kPNGImageMime) ||
|
||||
mimeType.EqualsLiteral(kGIFImageMime)) {
|
||||
NSString* availableType = [cocoaPasteboard
|
||||
availableTypeFromArray:
|
||||
[NSArray arrayWithObjects:[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypePNG], nil]];
|
||||
[NSArray
|
||||
arrayWithObjects:
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypePNG],
|
||||
nil]];
|
||||
if (availableType) {
|
||||
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
||||
return true;
|
||||
|
@ -449,9 +502,11 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
|
|||
if (NSPasteboardItem* item = [items objectAtIndex:0]) {
|
||||
if (NSString *availableType = [item
|
||||
availableTypeFromArray:
|
||||
[NSArray arrayWithObjects:[UTIHelper
|
||||
stringFromPboardType:(NSString*)kUTTypeFileURL],
|
||||
nil]]) {
|
||||
[NSArray
|
||||
arrayWithObjects:[UTIHelper
|
||||
stringFromPboardType:
|
||||
(NSString*)kUTTypeFileURL],
|
||||
nil]]) {
|
||||
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
||||
return true;
|
||||
}
|
||||
|
@ -481,10 +536,10 @@ mozilla::Maybe<uint32_t> nsClipboard::FindIndexOfImageFlavor(
|
|||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
// This function converts anything that other applications might understand into the system format
|
||||
// and puts it into a dictionary which it returns.
|
||||
// static
|
||||
NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable) {
|
||||
// This function converts anything that other applications might understand into
|
||||
// the system format and puts it into a dictionary which it returns. static
|
||||
NSDictionary* nsClipboard::PasteboardDictFromTransferable(
|
||||
nsITransferable* aTransferable) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
if (!aTransferable) {
|
||||
|
@ -499,29 +554,33 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
return nil;
|
||||
}
|
||||
|
||||
const mozilla::Maybe<uint32_t> imageFlavorIndex = nsClipboard::FindIndexOfImageFlavor(flavors);
|
||||
const mozilla::Maybe<uint32_t> imageFlavorIndex =
|
||||
nsClipboard::FindIndexOfImageFlavor(flavors);
|
||||
|
||||
if (imageFlavorIndex) {
|
||||
// When right-clicking and "Copy Image" is clicked on macOS, some apps expect the
|
||||
// first flavor to be the image flavor. See bug 1689992. For other apps, the
|
||||
// order shouldn't matter.
|
||||
// When right-clicking and "Copy Image" is clicked on macOS, some apps
|
||||
// expect the first flavor to be the image flavor. See bug 1689992. For
|
||||
// other apps, the order shouldn't matter.
|
||||
std::swap(*flavors.begin(), flavors[*imageFlavorIndex]);
|
||||
}
|
||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||
nsCString& flavorStr = flavors[i];
|
||||
|
||||
CLIPBOARD_LOG("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i);
|
||||
CLIPBOARD_LOG("writing out clipboard data of type %s (%d)\n",
|
||||
flavorStr.get(), i);
|
||||
|
||||
NSString* pboardType = nil;
|
||||
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericDataWrapper));
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString data;
|
||||
if (nsCOMPtr<nsISupportsString> text = do_QueryInterface(genericDataWrapper)) {
|
||||
if (nsCOMPtr<nsISupportsString> text =
|
||||
do_QueryInterface(genericDataWrapper)) {
|
||||
text->GetData(data);
|
||||
}
|
||||
|
||||
|
@ -540,26 +599,32 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
}
|
||||
|
||||
if (aTransferable->GetIsPrivateData()) {
|
||||
// In the case of password strings, we want to include the key for concealed type.
|
||||
// These will be flagged as private data.
|
||||
[pasteboardOutputDict setObject:nativeString
|
||||
forKey:[UTIHelper stringFromPboardType:kPasteboardConcealedType]];
|
||||
// In the case of password strings, we want to include the key for
|
||||
// concealed type. These will be flagged as private data.
|
||||
[pasteboardOutputDict
|
||||
setObject:nativeString
|
||||
forKey:[UTIHelper
|
||||
stringFromPboardType:kPasteboardConcealedType]];
|
||||
}
|
||||
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericDataWrapper));
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoCString data;
|
||||
if (nsCOMPtr<nsISupportsCString> text = do_QueryInterface(genericDataWrapper)) {
|
||||
if (nsCOMPtr<nsISupportsCString> text =
|
||||
do_QueryInterface(genericDataWrapper)) {
|
||||
text->GetData(data);
|
||||
}
|
||||
|
||||
if (!data.IsEmpty()) {
|
||||
NSData* nativeData = [NSData dataWithBytes:data.get() length:data.Length()];
|
||||
NSString* customType = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
|
||||
NSData* nativeData = [NSData dataWithBytes:data.get()
|
||||
length:data.Length()];
|
||||
NSString* customType =
|
||||
[UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
|
||||
if (!nativeData) {
|
||||
continue;
|
||||
}
|
||||
|
@ -567,7 +632,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
}
|
||||
} else if (nsClipboard::IsImageType(flavorStr)) {
|
||||
nsCOMPtr<nsISupports> transferSupports;
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(transferSupports));
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||
getter_AddRefs(transferSupports));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -578,9 +644,9 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
continue;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> surface =
|
||||
image->GetFrame(imgIContainer::FRAME_CURRENT,
|
||||
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
|
||||
RefPtr<SourceSurface> surface = image->GetFrame(
|
||||
imgIContainer::FRAME_CURRENT,
|
||||
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
|
||||
if (!surface) {
|
||||
continue;
|
||||
}
|
||||
|
@ -592,8 +658,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
|
||||
// Convert the CGImageRef to TIFF data.
|
||||
CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||
CGImageDestinationRef destRef =
|
||||
CGImageDestinationCreateWithData(tiffData, CFSTR("public.tiff"), 1, NULL);
|
||||
CGImageDestinationRef destRef = CGImageDestinationCreateWithData(
|
||||
tiffData, CFSTR("public.tiff"), 1, NULL);
|
||||
CGImageDestinationAddImage(destRef, imageRef, NULL);
|
||||
bool successfullyConverted = CGImageDestinationFinalize(destRef);
|
||||
|
||||
|
@ -609,12 +675,14 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
continue;
|
||||
}
|
||||
|
||||
NSString* tiffType = [UTIHelper stringFromPboardType:NSPasteboardTypeTIFF];
|
||||
NSString* tiffType =
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF];
|
||||
[pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:tiffType];
|
||||
CFRelease(tiffData);
|
||||
} else if (flavorStr.EqualsLiteral(kFileMime)) {
|
||||
nsCOMPtr<nsISupports> genericFile;
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericFile));
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||
getter_AddRefs(genericFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -635,18 +703,22 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
if (!url || ![url absoluteString]) {
|
||||
continue;
|
||||
}
|
||||
NSString* fileUTType = [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL];
|
||||
NSString* fileUTType =
|
||||
[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL];
|
||||
[pasteboardOutputDict setObject:[url absoluteString] forKey:fileUTType];
|
||||
} else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
|
||||
NSString* urlPromise =
|
||||
[UTIHelper stringFromPboardType:(NSString*)kPasteboardTypeFileURLPromise];
|
||||
NSString* urlPromiseContent =
|
||||
[UTIHelper stringFromPboardType:(NSString*)kPasteboardTypeFilePromiseContent];
|
||||
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:urlPromise];
|
||||
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:urlPromiseContent];
|
||||
NSString* urlPromise = [UTIHelper
|
||||
stringFromPboardType:(NSString*)kPasteboardTypeFileURLPromise];
|
||||
NSString* urlPromiseContent = [UTIHelper
|
||||
stringFromPboardType:(NSString*)kPasteboardTypeFilePromiseContent];
|
||||
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""]
|
||||
forKey:urlPromise];
|
||||
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""]
|
||||
forKey:urlPromiseContent];
|
||||
} else if (flavorStr.EqualsLiteral(kURLMime)) {
|
||||
nsCOMPtr<nsISupports> genericURL;
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericURL));
|
||||
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||
getter_AddRefs(genericURL));
|
||||
nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL));
|
||||
|
||||
nsAutoString url;
|
||||
|
@ -662,10 +734,12 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
|
||||
nsAutoString urlTitle;
|
||||
urlObject->GetData(urlTitle);
|
||||
urlTitle.Mid(urlTitle, newlinePos + 1, urlTitle.Length() - (newlinePos + 1));
|
||||
urlTitle.Mid(urlTitle, newlinePos + 1,
|
||||
urlTitle.Length() - (newlinePos + 1));
|
||||
|
||||
nativeTitle =
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(urlTitle.get())
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
urlTitle.get())
|
||||
length:urlTitle.Length()];
|
||||
}
|
||||
// The Finder doesn't like getting random binary data aka
|
||||
|
@ -673,24 +747,29 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
// ASCII.
|
||||
nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length());
|
||||
nsAutoCString escData;
|
||||
NS_EscapeURL(utf8Data.get(), utf8Data.Length(), esc_OnlyNonASCII | esc_AlwaysCopy, escData);
|
||||
NS_EscapeURL(utf8Data.get(), utf8Data.Length(),
|
||||
esc_OnlyNonASCII | esc_AlwaysCopy, escData);
|
||||
|
||||
NSString* nativeURL = [NSString stringWithUTF8String:escData.get()];
|
||||
NSString* publicUrl = [UTIHelper stringFromPboardType:kPublicUrlPboardType];
|
||||
NSString* publicUrl =
|
||||
[UTIHelper stringFromPboardType:kPublicUrlPboardType];
|
||||
if (!nativeURL) {
|
||||
continue;
|
||||
}
|
||||
[pasteboardOutputDict setObject:nativeURL forKey:publicUrl];
|
||||
if (nativeTitle) {
|
||||
NSArray* urlsAndTitles = @[ @[ nativeURL ], @[ nativeTitle ] ];
|
||||
NSString* urlName = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
|
||||
NSString* urlsWithTitles = [UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType];
|
||||
NSString* urlName =
|
||||
[UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
|
||||
NSString* urlsWithTitles =
|
||||
[UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType];
|
||||
[pasteboardOutputDict setObject:nativeTitle forKey:urlName];
|
||||
[pasteboardOutputDict setObject:urlsAndTitles forKey:urlsWithTitles];
|
||||
}
|
||||
}
|
||||
// If it wasn't a type that we recognize as exportable we don't put it on the system
|
||||
// clipboard. We'll just access it from our cached transferable when we need it.
|
||||
// If it wasn't a type that we recognize as exportable we don't put it on
|
||||
// the system clipboard. We'll just access it from our cached transferable
|
||||
// when we need it.
|
||||
}
|
||||
|
||||
return pasteboardOutputDict;
|
||||
|
@ -698,7 +777,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
||||
bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPboardType) {
|
||||
bool nsClipboard::IsStringType(const nsCString& aMIMEType,
|
||||
NSString** aPboardType) {
|
||||
if (aMIMEType.EqualsLiteral(kTextMime)) {
|
||||
*aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
||||
return true;
|
||||
|
@ -715,29 +795,33 @@ bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPboardTyp
|
|||
|
||||
// static
|
||||
bool nsClipboard::IsImageType(const nsACString& aMIMEType) {
|
||||
return aMIMEType.EqualsLiteral(kPNGImageMime) || aMIMEType.EqualsLiteral(kJPEGImageMime) ||
|
||||
aMIMEType.EqualsLiteral(kJPGImageMime) || aMIMEType.EqualsLiteral(kGIFImageMime) ||
|
||||
return aMIMEType.EqualsLiteral(kPNGImageMime) ||
|
||||
aMIMEType.EqualsLiteral(kJPEGImageMime) ||
|
||||
aMIMEType.EqualsLiteral(kJPGImageMime) ||
|
||||
aMIMEType.EqualsLiteral(kGIFImageMime) ||
|
||||
aMIMEType.EqualsLiteral(kNativeImageMime);
|
||||
}
|
||||
|
||||
NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString) {
|
||||
NSString* wrapped = [NSString
|
||||
stringWithFormat:@"<html>"
|
||||
"<head>"
|
||||
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"%@"
|
||||
"</body>"
|
||||
"</html>",
|
||||
aString];
|
||||
NSString* wrapped =
|
||||
[NSString stringWithFormat:@"<html>"
|
||||
"<head>"
|
||||
"<meta http-equiv=\"content-type\" "
|
||||
"content=\"text/html; charset=utf-8\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"%@"
|
||||
"</body>"
|
||||
"</html>",
|
||||
aString];
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
if (kSelectionCache == aWhichClipboard) {
|
||||
ClearSelectionCache();
|
||||
|
@ -753,11 +837,12 @@ nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) {
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
mozilla::Result<int32_t, nsresult> nsClipboard::GetNativeClipboardSequenceNumber(
|
||||
int32_t aWhichClipboard) {
|
||||
mozilla::Result<int32_t, nsresult>
|
||||
nsClipboard::GetNativeClipboardSequenceNumber(int32_t aWhichClipboard) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
if (kSelectionCache == aWhichClipboard) {
|
||||
return sSelectionCacheChangeCount;
|
||||
|
|
|
@ -38,7 +38,8 @@
|
|||
/*static*/ int32_t nsCocoaFeatures::mOSVersion = 0;
|
||||
|
||||
// This should not be called with unchecked aMajor, which should be >= 10.
|
||||
inline int32_t AssembleVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix) {
|
||||
inline int32_t AssembleVersion(int32_t aMajor, int32_t aMinor,
|
||||
int32_t aBugFix) {
|
||||
MOZ_ASSERT(aMajor >= 10);
|
||||
return (aMajor << 16) + (aMinor << 8) + aBugFix;
|
||||
}
|
||||
|
@ -65,11 +66,13 @@ static int intAtStringIndex(NSArray* array, int index) {
|
|||
void nsCocoaFeatures::GetSystemVersion(int& major, int& minor, int& bugfix) {
|
||||
major = minor = bugfix = 0;
|
||||
|
||||
NSString* versionString = [[NSDictionary
|
||||
dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]
|
||||
objectForKey:@"ProductVersion"];
|
||||
NSString* versionString =
|
||||
[[NSDictionary dictionaryWithContentsOfFile:
|
||||
@"/System/Library/CoreServices/SystemVersion.plist"]
|
||||
objectForKey:@"ProductVersion"];
|
||||
if (!versionString) {
|
||||
NS_ERROR("Couldn't read /System/Library/CoreServices/SystemVersion.plist to determine macOS "
|
||||
NS_ERROR("Couldn't read /System/Library/CoreServices/SystemVersion.plist "
|
||||
"to determine macOS "
|
||||
"version.");
|
||||
return;
|
||||
}
|
||||
|
@ -86,7 +89,8 @@ void nsCocoaFeatures::GetSystemVersion(int& major, int& minor, int& bugfix) {
|
|||
}
|
||||
}
|
||||
|
||||
int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix) {
|
||||
int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor,
|
||||
int32_t aBugFix) {
|
||||
int32_t macOSVersion;
|
||||
if (aMajor < 10) {
|
||||
aMajor = 10;
|
||||
|
@ -148,7 +152,8 @@ int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor, int32_t aBug
|
|||
}
|
||||
|
||||
/* static */ bool nsCocoaFeatures::OnSierraExactly() {
|
||||
return (macOSVersion() >= MACOS_VERSION_10_12_HEX) && (macOSVersion() < MACOS_VERSION_10_13_HEX);
|
||||
return (macOSVersion() >= MACOS_VERSION_10_12_HEX) &&
|
||||
(macOSVersion() < MACOS_VERSION_10_13_HEX);
|
||||
}
|
||||
|
||||
/* Version of OnSierraExactly as global function callable from cairo & skia */
|
||||
|
@ -195,7 +200,8 @@ bool Gecko_OnSierraExactly() { return nsCocoaFeatures::OnSierraExactly(); }
|
|||
return (macOSVersion() >= MACOS_VERSION_13_0_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor,
|
||||
/* static */ bool nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor,
|
||||
int32_t aMinor,
|
||||
int32_t aBugFix) {
|
||||
return macOSVersion() >= GetVersion(aMajor, aMinor, aBugFix);
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -96,25 +96,30 @@ nsColorPicker::~nsColorPicker() {
|
|||
// TODO(bug 1805397): Implement default colors
|
||||
NS_IMETHODIMP
|
||||
nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
|
||||
const nsAString& aInitialColor, const nsTArray<nsString>& aDefaultColors) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Color pickers can only be opened from main thread currently");
|
||||
const nsAString& aInitialColor,
|
||||
const nsTArray<nsString>& aDefaultColors) {
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"Color pickers can only be opened from main thread currently");
|
||||
mTitle = aTitle;
|
||||
mColor = aInitialColor;
|
||||
mColorPanelWrapper = [[NSColorPanelWrapper alloc] initWithPicker:this];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ NSColor* nsColorPicker::GetNSColorFromHexString(const nsAString& aColor) {
|
||||
/* static */ NSColor* nsColorPicker::GetNSColorFromHexString(
|
||||
const nsAString& aColor) {
|
||||
NSString* str = nsCocoaUtils::ToNSString(aColor);
|
||||
|
||||
double red = HexStrToInt([str substringWithRange:NSMakeRange(1, 2)]) / 255.0;
|
||||
double green = HexStrToInt([str substringWithRange:NSMakeRange(3, 2)]) / 255.0;
|
||||
double green =
|
||||
HexStrToInt([str substringWithRange:NSMakeRange(3, 2)]) / 255.0;
|
||||
double blue = HexStrToInt([str substringWithRange:NSMakeRange(5, 2)]) / 255.0;
|
||||
|
||||
return [NSColor colorWithDeviceRed:red green:green blue:blue alpha:1.0];
|
||||
}
|
||||
|
||||
/* static */ void nsColorPicker::GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult) {
|
||||
/* static */ void nsColorPicker::GetHexStringFromNSColor(NSColor* aColor,
|
||||
nsAString& aResult) {
|
||||
CGFloat redFloat, greenFloat, blueFloat;
|
||||
|
||||
NSColor* color = aColor;
|
||||
|
@ -126,7 +131,8 @@ nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
|
|||
}
|
||||
|
||||
nsCocoaUtils::GetStringForNSString(
|
||||
[NSString stringWithFormat:@"#%02x%02x%02x", (int)(redFloat * 255), (int)(greenFloat * 255),
|
||||
[NSString stringWithFormat:@"#%02x%02x%02x", (int)(redFloat * 255),
|
||||
(int)(greenFloat * 255),
|
||||
(int)(blueFloat * 255)],
|
||||
aResult);
|
||||
}
|
||||
|
@ -136,7 +142,8 @@ nsColorPicker::Open(nsIColorPickerShownCallback* aCallback) {
|
|||
MOZ_ASSERT(aCallback);
|
||||
mCallback = aCallback;
|
||||
|
||||
[mColorPanelWrapper open:GetNSColorFromHexString(mColor) title:nsCocoaUtils::ToNSString(mTitle)];
|
||||
[mColorPanelWrapper open:GetNSColorFromHexString(mColor)
|
||||
title:nsCocoaUtils::ToNSString(mTitle)];
|
||||
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
/*! @method getCursor:
|
||||
@abstract Get a reference to the native Mac representation of a cursor.
|
||||
@discussion Gets a reference to the Mac native implementation of a cursor.
|
||||
If the cursor has been requested before, it is retreived from the cursor cache,
|
||||
otherwise it is created and cached.
|
||||
If the cursor has been requested before, it is retreived from
|
||||
the cursor cache, otherwise it is created and cached.
|
||||
@param aCursor the cursor to get
|
||||
@result the Mac native implementation of the cursor
|
||||
*/
|
||||
|
@ -29,8 +29,9 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
|
||||
/*! @method setMacCursor:
|
||||
@abstract Set the current Mac native cursor
|
||||
@discussion Sets the current cursor - this routine is what actually causes the cursor to change.
|
||||
The argument is retained and the old cursor is released.
|
||||
@discussion Sets the current cursor - this routine is what actually causes the
|
||||
cursor to change. The argument is retained and the old cursor is
|
||||
released.
|
||||
@param aMacCursor the cursor to set
|
||||
@result NS_OK
|
||||
*/
|
||||
|
@ -38,7 +39,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
|
||||
/*! @method createCursor:
|
||||
@abstract Create a Mac native representation of a cursor.
|
||||
@discussion Creates a version of the Mac native representation of this cursor
|
||||
@discussion Creates a version of the Mac native representation of this
|
||||
cursor.
|
||||
@param aCursor the cursor to create
|
||||
@result the Mac native implementation of the cursor
|
||||
*/
|
||||
|
@ -76,92 +78,128 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
|
||||
case eCursor_wait:
|
||||
case eCursor_spinning: {
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor]
|
||||
type:aCursor];
|
||||
}
|
||||
case eCursor_select:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor];
|
||||
case eCursor_hyperlink:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor]
|
||||
type:aCursor];
|
||||
case eCursor_crosshair:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor]
|
||||
type:aCursor];
|
||||
case eCursor_move:
|
||||
return [nsMacCursor cursorWithImageNamed:@"move" hotSpot:NSMakePoint(12, 12) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"move"
|
||||
hotSpot:NSMakePoint(12, 12)
|
||||
type:aCursor];
|
||||
case eCursor_help:
|
||||
return [nsMacCursor cursorWithImageNamed:@"help" hotSpot:NSMakePoint(12, 12) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"help"
|
||||
hotSpot:NSMakePoint(12, 12)
|
||||
type:aCursor];
|
||||
case eCursor_copy: {
|
||||
SEL cursorSelector = @selector(dragCopyCursor);
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||
? [NSCursor performSelector:cursorSelector]
|
||||
: [NSCursor arrowCursor]
|
||||
type:aCursor];
|
||||
return [nsMacCursor
|
||||
cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||
? [NSCursor performSelector:cursorSelector]
|
||||
: [NSCursor arrowCursor]
|
||||
type:aCursor];
|
||||
}
|
||||
case eCursor_alias: {
|
||||
SEL cursorSelector = @selector(dragLinkCursor);
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||
? [NSCursor performSelector:cursorSelector]
|
||||
: [NSCursor arrowCursor]
|
||||
type:aCursor];
|
||||
return [nsMacCursor
|
||||
cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||
? [NSCursor performSelector:cursorSelector]
|
||||
: [NSCursor arrowCursor]
|
||||
type:aCursor];
|
||||
}
|
||||
case eCursor_context_menu: {
|
||||
SEL cursorSelector = @selector(contextualMenuCursor);
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||
? [NSCursor performSelector:cursorSelector]
|
||||
: [NSCursor arrowCursor]
|
||||
type:aCursor];
|
||||
return [nsMacCursor
|
||||
cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||
? [NSCursor performSelector:cursorSelector]
|
||||
: [NSCursor arrowCursor]
|
||||
type:aCursor];
|
||||
}
|
||||
case eCursor_cell:
|
||||
return [nsMacCursor cursorWithImageNamed:@"cell" hotSpot:NSMakePoint(12, 12) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"cell"
|
||||
hotSpot:NSMakePoint(12, 12)
|
||||
type:aCursor];
|
||||
case eCursor_grab:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor]
|
||||
type:aCursor];
|
||||
case eCursor_grabbing:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor]
|
||||
type:aCursor];
|
||||
case eCursor_zoom_in:
|
||||
return [nsMacCursor cursorWithImageNamed:@"zoomIn" hotSpot:NSMakePoint(10, 10) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"zoomIn"
|
||||
hotSpot:NSMakePoint(10, 10)
|
||||
type:aCursor];
|
||||
case eCursor_zoom_out:
|
||||
return [nsMacCursor cursorWithImageNamed:@"zoomOut" hotSpot:NSMakePoint(10, 10) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"zoomOut"
|
||||
hotSpot:NSMakePoint(10, 10)
|
||||
type:aCursor];
|
||||
case eCursor_vertical_text:
|
||||
return [nsMacCursor cursorWithImageNamed:@"vtIBeam" hotSpot:NSMakePoint(12, 11) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"vtIBeam"
|
||||
hotSpot:NSMakePoint(12, 11)
|
||||
type:aCursor];
|
||||
case eCursor_all_scroll:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor]
|
||||
type:aCursor];
|
||||
case eCursor_not_allowed:
|
||||
case eCursor_no_drop: {
|
||||
SEL cursorSelector = @selector(operationNotAllowedCursor);
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||
? [NSCursor performSelector:cursorSelector]
|
||||
: [NSCursor arrowCursor]
|
||||
type:aCursor];
|
||||
return [nsMacCursor
|
||||
cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||
? [NSCursor performSelector:cursorSelector]
|
||||
: [NSCursor arrowCursor]
|
||||
type:aCursor];
|
||||
}
|
||||
// Resize Cursors:
|
||||
// North
|
||||
case eCursor_n_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor]
|
||||
type:aCursor];
|
||||
// North East
|
||||
case eCursor_ne_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNE" hotSpot:NSMakePoint(12, 11) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNE"
|
||||
hotSpot:NSMakePoint(12, 11)
|
||||
type:aCursor];
|
||||
// East
|
||||
case eCursor_e_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor]
|
||||
type:aCursor];
|
||||
// South East
|
||||
case eCursor_se_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeSE" hotSpot:NSMakePoint(12, 12) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeSE"
|
||||
hotSpot:NSMakePoint(12, 12)
|
||||
type:aCursor];
|
||||
// South
|
||||
case eCursor_s_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor]
|
||||
type:aCursor];
|
||||
// South West
|
||||
case eCursor_sw_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeSW" hotSpot:NSMakePoint(10, 12) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeSW"
|
||||
hotSpot:NSMakePoint(10, 12)
|
||||
type:aCursor];
|
||||
// West
|
||||
case eCursor_w_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor]
|
||||
type:aCursor];
|
||||
// North West
|
||||
case eCursor_nw_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNW" hotSpot:NSMakePoint(11, 11) type:aCursor];
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNW"
|
||||
hotSpot:NSMakePoint(11, 11)
|
||||
type:aCursor];
|
||||
// North & South
|
||||
case eCursor_ns_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor]
|
||||
type:aCursor];
|
||||
// East & West
|
||||
case eCursor_ew_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor] type:aCursor];
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor]
|
||||
type:aCursor];
|
||||
// North East & South West
|
||||
case eCursor_nesw_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNESW"
|
||||
|
@ -241,8 +279,10 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
widgetScaleFactor:(CGFloat)scaleFactor {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
// As the user moves the mouse, this gets called repeatedly with the same aCursorImage
|
||||
if (sCurrentCursor == aCursor && sCurrentCursorScaleFactor == scaleFactor && mCurrentMacCursor) {
|
||||
// As the user moves the mouse, this gets called repeatedly with the same
|
||||
// aCursorImage
|
||||
if (sCurrentCursor == aCursor && sCurrentCursorScaleFactor == scaleFactor &&
|
||||
mCurrentMacCursor) {
|
||||
// Native dragging can unset our cursor apparently (see bug 1739352).
|
||||
if (MOZ_UNLIKELY(![mCurrentMacCursor isSet])) {
|
||||
[mCurrentMacCursor set];
|
||||
|
@ -265,7 +305,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
|
||||
NSImage* cursorImage;
|
||||
nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(
|
||||
aCursor.mContainer, imgIContainer::FRAME_FIRST, nullptr, nullptr, &cursorImage, scaleFactor);
|
||||
aCursor.mContainer, imgIContainer::FRAME_FIRST, nullptr, nullptr,
|
||||
&cursorImage, scaleFactor);
|
||||
if (NS_FAILED(rv) || !cursorImage) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -277,11 +318,14 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
}
|
||||
|
||||
// if the hotspot is nonsensical, make it 0,0
|
||||
uint32_t hotspotX = aCursor.mHotspotX > (uint32_t(size.width) - 1) ? 0 : aCursor.mHotspotX;
|
||||
uint32_t hotspotY = aCursor.mHotspotY > (uint32_t(size.height) - 1) ? 0 : aCursor.mHotspotY;
|
||||
uint32_t hotspotX =
|
||||
aCursor.mHotspotX > (uint32_t(size.width) - 1) ? 0 : aCursor.mHotspotX;
|
||||
uint32_t hotspotY =
|
||||
aCursor.mHotspotY > (uint32_t(size.height) - 1) ? 0 : aCursor.mHotspotY;
|
||||
NSPoint hotSpot = ::NSMakePoint(hotspotX, hotspotY);
|
||||
[self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc] initWithImage:cursorImage
|
||||
hotSpot:hotSpot]
|
||||
[self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc]
|
||||
initWithImage:cursorImage
|
||||
hotSpot:hotSpot]
|
||||
type:kCustomCursor]];
|
||||
[cursorImage release];
|
||||
return NS_OK;
|
||||
|
@ -292,7 +336,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
|||
- (nsMacCursor*)getCursor:(enum nsCursor)aCursor {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsMacCursor* result = [mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
|
||||
nsMacCursor* result =
|
||||
[mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
|
||||
if (!result) {
|
||||
result = [nsCursorManager createCursor:aCursor];
|
||||
[mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]];
|
||||
|
|
|
@ -67,7 +67,8 @@ nsDeviceContextSpecX::~nsDeviceContextSpecX() {
|
|||
|
||||
NS_IMPL_ISUPPORTS(nsDeviceContextSpecX, nsIDeviceContextSpec)
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPreview) {
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS,
|
||||
bool aIsPrintPreview) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
RefPtr<nsPrintSettingsX> settings(do_QueryObject(aPS));
|
||||
|
@ -81,7 +82,8 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
|
|||
if (!printInfo) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (aPS->GetOutputDestination() == nsIPrintSettings::kOutputDestinationStream) {
|
||||
if (aPS->GetOutputDestination() ==
|
||||
nsIPrintSettings::kOutputDestinationStream) {
|
||||
aPS->GetOutputStream(getter_AddRefs(mOutputStream));
|
||||
if (!mOutputStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -108,17 +110,20 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
|
|||
// TODO: Currently we do not support using SkPDF for kPMDestinationFax or
|
||||
// kPMDestinationProcessPDF ("Add PDF to iBooks, etc.), and we only support
|
||||
// it for kPMDestinationFile if the destination file is a PDF.
|
||||
// XXX Could PMWorkflowSubmitPDFWithSettings/PMPrinterPrintWithProvider help?
|
||||
// XXX Could PMWorkflowSubmitPDFWithSettings/PMPrinterPrintWithProvider
|
||||
// help?
|
||||
OSStatus status = noErr;
|
||||
PMDestinationType destination;
|
||||
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination);
|
||||
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings,
|
||||
&destination);
|
||||
if (status == noErr) {
|
||||
if (destination == kPMDestinationPrinter || destination == kPMDestinationPreview) {
|
||||
if (destination == kPMDestinationPrinter ||
|
||||
destination == kPMDestinationPreview) {
|
||||
mPrintViaSkPDF = true;
|
||||
} else if (destination == kPMDestinationFile) {
|
||||
AutoCFRelease<CFURLRef> destURL(nullptr);
|
||||
status =
|
||||
::PMSessionCopyDestinationLocation(mPrintSession, mPMPrintSettings, destURL.receive());
|
||||
status = ::PMSessionCopyDestinationLocation(
|
||||
mPrintSession, mPMPrintSettings, destURL.receive());
|
||||
if (status == noErr) {
|
||||
AutoCFRelease<CFStringRef> destPathRef =
|
||||
CFURLCopyFileSystemPath(destURL, kCFURLPOSIXPathStyle);
|
||||
|
@ -139,16 +144,20 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
|
|||
// We don't actually currently support/use kOutputFormatPDF on mac, but
|
||||
// this is for completeness in case we add that (we probably need to in
|
||||
// order to support adding links into saved PDFs, for example).
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"pdf_file"_ns, 1);
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE,
|
||||
u"pdf_file"_ns, 1);
|
||||
} else {
|
||||
PMDestinationType destination;
|
||||
OSStatus status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination);
|
||||
if (status == noErr &&
|
||||
(destination == kPMDestinationFile || destination == kPMDestinationPreview ||
|
||||
destination == kPMDestinationProcessPDF)) {
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"pdf_file"_ns, 1);
|
||||
OSStatus status = ::PMSessionGetDestinationType(
|
||||
mPrintSession, mPMPrintSettings, &destination);
|
||||
if (status == noErr && (destination == kPMDestinationFile ||
|
||||
destination == kPMDestinationPreview ||
|
||||
destination == kPMDestinationProcessPDF)) {
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE,
|
||||
u"pdf_file"_ns, 1);
|
||||
} else {
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"unknown"_ns, 1);
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE,
|
||||
u"unknown"_ns, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,9 +166,9 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage, int32_t aEndPage) {
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(
|
||||
const nsAString& aTitle, const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage, int32_t aEndPage) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
return NS_OK;
|
||||
|
@ -168,7 +177,8 @@ NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle,
|
|||
}
|
||||
|
||||
RefPtr<PrintEndDocumentPromise> nsDeviceContextSpecX::EndDocument() {
|
||||
return nsIDeviceContextSpec::EndDocumentPromiseFromResult(DoEndDocument(), __func__);
|
||||
return nsIDeviceContextSpec::EndDocumentPromiseFromResult(DoEndDocument(),
|
||||
__func__);
|
||||
}
|
||||
|
||||
nsresult nsDeviceContextSpecX::DoEndDocument() {
|
||||
|
@ -183,14 +193,15 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
AutoCFRelease<CFURLRef> pdfURL(nullptr);
|
||||
// Note that the caller is responsible to release pdfURL according to nsILocalFileMac.idl,
|
||||
// even though we didn't follow the Core Foundation naming conventions here (the method
|
||||
// should've been called CopyCFURL).
|
||||
// Note that the caller is responsible to release pdfURL according to
|
||||
// nsILocalFileMac.idl, even though we didn't follow the Core Foundation
|
||||
// naming conventions here (the method should've been called CopyCFURL).
|
||||
nsresult rv = tmpPDFFile->GetCFURL(pdfURL.receive());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PMDestinationType destination;
|
||||
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination);
|
||||
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings,
|
||||
&destination);
|
||||
|
||||
switch (destination) {
|
||||
case kPMDestinationPrinter: {
|
||||
|
@ -200,13 +211,14 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
CFStringRef mimeType = CFSTR("application/pdf");
|
||||
status = ::PMPrinterPrintWithFile(currentPrinter, mPMPrintSettings, mPageFormat, mimeType,
|
||||
pdfURL);
|
||||
status = ::PMPrinterPrintWithFile(currentPrinter, mPMPrintSettings,
|
||||
mPageFormat, mimeType, pdfURL);
|
||||
break;
|
||||
}
|
||||
case kPMDestinationPreview: {
|
||||
// XXXjwatt Or should we use CocoaFileUtils::RevealFileInFinder(pdfURL);
|
||||
AutoCFRelease<CFStringRef> pdfPath = CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
|
||||
AutoCFRelease<CFStringRef> pdfPath =
|
||||
CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
|
||||
NSString* path = (NSString*)CFStringRef(pdfPath);
|
||||
NSWorkspace* ws = [NSWorkspace sharedWorkspace];
|
||||
[ws openFile:path];
|
||||
|
@ -214,8 +226,8 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
|||
}
|
||||
case kPMDestinationFile: {
|
||||
AutoCFRelease<CFURLRef> destURL(nullptr);
|
||||
status =
|
||||
::PMSessionCopyDestinationLocation(mPrintSession, mPMPrintSettings, destURL.receive());
|
||||
status = ::PMSessionCopyDestinationLocation(
|
||||
mPrintSession, mPMPrintSettings, destURL.receive());
|
||||
if (status == noErr) {
|
||||
AutoCFRelease<CFStringRef> sourcePathRef =
|
||||
CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
|
||||
|
@ -234,12 +246,14 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
|||
if ([fileManager fileExistsAtPath:sourcePath]) {
|
||||
NSURL* src = static_cast<NSURL*>(CFURLRef(pdfURL));
|
||||
NSURL* dest = static_cast<NSURL*>(CFURLRef(destURL));
|
||||
bool ok = [fileManager replaceItemAtURL:dest
|
||||
withItemAtURL:src
|
||||
backupItemName:nil
|
||||
options:NSFileManagerItemReplacementUsingNewMetadataOnly
|
||||
resultingItemURL:nil
|
||||
error:nil];
|
||||
bool ok = [fileManager
|
||||
replaceItemAtURL:dest
|
||||
withItemAtURL:src
|
||||
backupItemName:nil
|
||||
options:
|
||||
NSFileManagerItemReplacementUsingNewMetadataOnly
|
||||
resultingItemURL:nil
|
||||
error:nil];
|
||||
if (!ok) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -261,8 +275,8 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft, double* aBottom,
|
||||
double* aRight) {
|
||||
void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft,
|
||||
double* aBottom, double* aRight) {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
PMRect paperRect;
|
||||
|
@ -286,7 +300,8 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
|
|||
#ifdef MOZ_ENABLE_SKIA_PDF
|
||||
if (mPrintViaSkPDF) {
|
||||
// TODO: Add support for stream printing via SkPDF if we enable that again.
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTempFile));
|
||||
nsresult rv =
|
||||
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTempFile));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
nsAutoCString tempPath("tmp-printing.pdf");
|
||||
mTempFile->AppendNative(tempPath);
|
||||
|
@ -298,6 +313,6 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
|
|||
}
|
||||
#endif
|
||||
|
||||
return PrintTargetCG::CreateOrNull(mOutputStream, mPrintSession, mPageFormat, mPMPrintSettings,
|
||||
size);
|
||||
return PrintTargetCG::CreateOrNull(mOutputStream, mPrintSession, mPageFormat,
|
||||
mPMPrintSettings, size);
|
||||
}
|
||||
|
|
|
@ -49,24 +49,29 @@ nsDragService::nsDragService()
|
|||
|
||||
nsDragService::~nsDragService() {}
|
||||
|
||||
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSIntRegion>& aRegion,
|
||||
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode,
|
||||
const Maybe<CSSIntRegion>& aRegion,
|
||||
NSPoint* aDragPoint) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
|
||||
|
||||
LayoutDeviceIntRect dragRect(0, 0, 20, 20);
|
||||
NSImage* image = ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect);
|
||||
NSImage* image =
|
||||
ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect);
|
||||
if (!image) {
|
||||
// if no image was returned, just draw a rectangle
|
||||
NSSize size;
|
||||
size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
|
||||
size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
|
||||
size.width =
|
||||
nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
|
||||
size.height =
|
||||
nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
|
||||
image = [NSImage imageWithSize:size
|
||||
flipped:YES
|
||||
drawingHandler:^BOOL(NSRect dstRect) {
|
||||
[[NSColor grayColor] set];
|
||||
NSBezierPath* path = [NSBezierPath bezierPathWithRect:dstRect];
|
||||
NSBezierPath* path =
|
||||
[NSBezierPath bezierPathWithRect:dstRect];
|
||||
[path setLineWidth:2.0];
|
||||
[path stroke];
|
||||
return YES;
|
||||
|
@ -85,8 +90,10 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
||||
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSIntRegion>& aRegion,
|
||||
CSSIntPoint aPoint, LayoutDeviceIntRect* aDragRect) {
|
||||
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode,
|
||||
const Maybe<CSSIntRegion>& aRegion,
|
||||
CSSIntPoint aPoint,
|
||||
LayoutDeviceIntRect* aDragRect) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
|
||||
|
@ -97,8 +104,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
|||
if (pc && (!aDragRect->width || !aDragRect->height)) {
|
||||
// just use some suitable defaults
|
||||
int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor);
|
||||
aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x), pc->CSSPixelsToDevPixels(aPoint.y), size,
|
||||
size);
|
||||
aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x),
|
||||
pc->CSSPixelsToDevPixels(aPoint.y), size, size);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) || !surface) return nil;
|
||||
|
@ -106,21 +113,23 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
|||
uint32_t width = aDragRect->width;
|
||||
uint32_t height = aDragRect->height;
|
||||
|
||||
RefPtr<DataSourceSurface> dataSurface =
|
||||
Factory::CreateDataSourceSurface(IntSize(width, height), SurfaceFormat::B8G8R8A8);
|
||||
RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(
|
||||
IntSize(width, height), SurfaceFormat::B8G8R8A8);
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
|
||||
BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride, dataSurface->GetFormat());
|
||||
BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride,
|
||||
dataSurface->GetFormat());
|
||||
if (!dt) {
|
||||
dataSurface->Unmap();
|
||||
return nil;
|
||||
}
|
||||
|
||||
dt->FillRect(gfx::Rect(0, 0, width, height), SurfacePattern(surface, ExtendMode::CLAMP),
|
||||
dt->FillRect(gfx::Rect(0, 0, width, height),
|
||||
SurfacePattern(surface, ExtendMode::CLAMP),
|
||||
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
|
||||
|
||||
NSBitmapImageRep* imageRep =
|
||||
|
@ -140,7 +149,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
|||
uint8_t* src = map.mData + i * map.mStride;
|
||||
for (uint32_t j = 0; j < width; ++j) {
|
||||
// Reduce transparency overall by multipying by a factor. Remember, Alpha
|
||||
// is premultipled here. Also, Quartz likes RGBA, so do that translation as well.
|
||||
// is premultipled here. Also, Quartz likes RGBA, so do that translation
|
||||
// as well.
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
|
||||
dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
|
||||
|
@ -158,8 +168,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
|||
}
|
||||
dataSurface->Unmap();
|
||||
|
||||
NSImage* image =
|
||||
[[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor, height / scaleFactor)];
|
||||
NSImage* image = [[NSImage alloc]
|
||||
initWithSize:NSMakeSize(width / scaleFactor, height / scaleFactor)];
|
||||
[image addRepresentation:imageRep];
|
||||
[imageRep release];
|
||||
|
||||
|
@ -168,9 +178,9 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
||||
nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
||||
const Maybe<CSSIntRegion>& aRegion,
|
||||
uint32_t aActionType) {
|
||||
nsresult nsDragService::InvokeDragSessionImpl(
|
||||
nsIArray* aTransferableArray, const Maybe<CSSIntRegion>& aRegion,
|
||||
uint32_t aActionType) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
|
@ -178,10 +188,11 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
|||
#endif
|
||||
|
||||
if (!gLastDragView) {
|
||||
// gLastDragView is non-null between -[ChildView mouseDown:] and -[ChildView mouseUp:].
|
||||
// If we get here with gLastDragView being null, that means that the mouse button has already
|
||||
// been released. In that case we need to abort the drag because the OS won't know where to drop
|
||||
// whatever's being dragged, and we might end up with a stuck drag & drop session.
|
||||
// gLastDragView is non-null between -[ChildView mouseDown:] and -[ChildView
|
||||
// mouseUp:]. If we get here with gLastDragView being null, that means that
|
||||
// the mouse button has already been released. In that case we need to abort
|
||||
// the drag because the OS won't know where to drop whatever's being
|
||||
// dragged, and we might end up with a stuck drag & drop session.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -205,7 +216,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
|||
gDraggedTransferables->GetLength(&count);
|
||||
|
||||
for (uint32_t j = 0; j < count; j++) {
|
||||
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(aTransferableArray, j);
|
||||
nsCOMPtr<nsITransferable> currentTransferable =
|
||||
do_QueryElementAt(aTransferableArray, j);
|
||||
if (!currentTransferable) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -234,7 +246,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
|||
localDragRect.origin.x = draggingPoint.x;
|
||||
localDragRect.origin.y = draggingPoint.y - localDragRect.size.height;
|
||||
|
||||
NSDraggingItem* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
|
||||
NSDraggingItem* dragItem =
|
||||
[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
|
||||
[pbItem release];
|
||||
[dragItem setDraggingFrame:localDragRect contents:image];
|
||||
|
||||
|
@ -242,7 +255,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
|||
nsBaseDragService::OpenDragPopup();
|
||||
|
||||
NSDraggingSession* draggingSession = [mNativeDragView
|
||||
beginDraggingSessionWithItems:[NSArray arrayWithObject:[dragItem autorelease]]
|
||||
beginDraggingSessionWithItems:[NSArray
|
||||
arrayWithObject:[dragItem autorelease]]
|
||||
event:mNativeDragEvent
|
||||
source:mNativeDragView];
|
||||
draggingSession.animatesToStartingPositionsOnCancelOrFail =
|
||||
|
@ -261,24 +275,26 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// get flavor list that includes all acceptable flavors (including ones obtained through
|
||||
// conversion)
|
||||
// get flavor list that includes all acceptable flavors (including ones
|
||||
// obtained through conversion)
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// if this drag originated within Mozilla we should just use the cached data from
|
||||
// when the drag started if possible
|
||||
// if this drag originated within Mozilla we should just use the cached data
|
||||
// from when the drag started if possible
|
||||
if (mDataItems) {
|
||||
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, aItemIndex);
|
||||
nsCOMPtr<nsITransferable> currentTransferable =
|
||||
do_QueryElementAt(mDataItems, aItemIndex);
|
||||
if (currentTransferable) {
|
||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||
nsCString& flavorStr = flavors[i];
|
||||
|
||||
nsCOMPtr<nsISupports> dataSupports;
|
||||
rv = currentTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(dataSupports));
|
||||
rv = currentTransferable->GetTransferData(flavorStr.get(),
|
||||
getter_AddRefs(dataSupports));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aTransferable->SetTransferData(flavorStr.get(), dataSupports);
|
||||
return NS_OK; // maybe try to fill in more types? Is there a point?
|
||||
|
@ -304,7 +320,8 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
|
|||
|
||||
// now check the actual clipboard for data
|
||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable, flavors[i], item);
|
||||
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable,
|
||||
flavors[i], item);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -327,7 +344,8 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
|
|||
uint32_t dataItemsCount;
|
||||
mDataItems->GetLength(&dataItemsCount);
|
||||
for (unsigned int i = 0; i < dataItemsCount; i++) {
|
||||
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, i);
|
||||
nsCOMPtr<nsITransferable> currentTransferable =
|
||||
do_QueryElementAt(mDataItems, i);
|
||||
if (!currentTransferable) continue;
|
||||
|
||||
nsTArray<nsCString> flavors;
|
||||
|
@ -352,7 +370,8 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
|
|||
type = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
||||
} else if (dataFlavor.EqualsLiteral(kHTMLMime)) {
|
||||
type = [UTIHelper stringFromPboardType:NSPasteboardTypeHTML];
|
||||
} else if (dataFlavor.EqualsLiteral(kURLMime) || dataFlavor.EqualsLiteral(kURLDataMime)) {
|
||||
} else if (dataFlavor.EqualsLiteral(kURLMime) ||
|
||||
dataFlavor.EqualsLiteral(kURLDataMime)) {
|
||||
type = [UTIHelper stringFromPboardType:kPublicUrlPboardType];
|
||||
} else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) {
|
||||
type = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
|
||||
|
@ -362,9 +381,10 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
|
|||
type = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
|
||||
}
|
||||
|
||||
NSString* availableType =
|
||||
[globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
|
||||
if (availableType && nsCocoaUtils::IsValidPasteboardType(availableType, allowFileURL)) {
|
||||
NSString* availableType = [globalDragPboard
|
||||
availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
|
||||
if (availableType &&
|
||||
nsCocoaUtils::IsValidPasteboardType(availableType, allowFileURL)) {
|
||||
*_retval = true;
|
||||
}
|
||||
|
||||
|
@ -396,19 +416,22 @@ nsDragService::GetNumDropItems(uint32_t* aNumItems) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDragService::UpdateDragImage(nsINode* aImage, int32_t aImageX, int32_t aImageY) {
|
||||
nsDragService::UpdateDragImage(nsINode* aImage, int32_t aImageX,
|
||||
int32_t aImageY) {
|
||||
nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY);
|
||||
mDragImageChanged = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoint) {
|
||||
void nsDragService::DragMovedWithView(NSDraggingSession* aSession,
|
||||
NSPoint aPoint) {
|
||||
aPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y);
|
||||
|
||||
// XXX It feels like we should be using the backing scale factor at aPoint
|
||||
// rather than the initial drag view, but I've seen no ill effects of this.
|
||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
|
||||
LayoutDeviceIntPoint devPoint = nsCocoaUtils::CocoaPointsToDevPixels(aPoint, scaleFactor);
|
||||
LayoutDeviceIntPoint devPoint =
|
||||
nsCocoaUtils::CocoaPointsToDevPixels(aPoint, scaleFactor);
|
||||
|
||||
// If the image has changed, call enumerateDraggingItemsWithOptions to get
|
||||
// the item being dragged and update its image.
|
||||
|
@ -422,32 +445,39 @@ void nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoin
|
|||
}
|
||||
|
||||
if (pc) {
|
||||
void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) =
|
||||
^(NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
|
||||
// We never add more than one item right now, but check just in case.
|
||||
if (idx > 0) {
|
||||
return;
|
||||
}
|
||||
void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) = ^(
|
||||
NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
|
||||
// We never add more than one item right now, but check just in case.
|
||||
if (idx > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsPoint pt =
|
||||
LayoutDevicePixel::ToAppUnits(devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
|
||||
CSSIntPoint screenPoint = CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
|
||||
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
|
||||
nsPoint pt = LayoutDevicePixel::ToAppUnits(
|
||||
devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
|
||||
CSSIntPoint screenPoint =
|
||||
CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
|
||||
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
|
||||
|
||||
// Create a new image; if one isn't returned don't change the current one.
|
||||
LayoutDeviceIntRect newRect;
|
||||
NSImage* image = ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
|
||||
if (image) {
|
||||
NSRect draggingRect = nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
|
||||
[draggingItem setDraggingFrame:draggingRect contents:image];
|
||||
}
|
||||
};
|
||||
// Create a new image; if one isn't returned don't change the current
|
||||
// one.
|
||||
LayoutDeviceIntRect newRect;
|
||||
NSImage* image =
|
||||
ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
|
||||
if (image) {
|
||||
NSRect draggingRect =
|
||||
nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
|
||||
[draggingItem setDraggingFrame:draggingRect contents:image];
|
||||
}
|
||||
};
|
||||
|
||||
[aSession enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
|
||||
forView:nil
|
||||
classes:[NSArray arrayWithObject:[NSPasteboardItem class]]
|
||||
searchOptions:@{}
|
||||
usingBlock:changeImageBlock];
|
||||
[aSession
|
||||
enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
|
||||
forView:nil
|
||||
classes:[NSArray
|
||||
arrayWithObject:
|
||||
[NSPasteboardItem class]]
|
||||
searchOptions:@{}
|
||||
usingBlock:changeImageBlock];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,9 +59,11 @@ static void SetShowHiddenFileState(NSSavePanel* panel) {
|
|||
if (gCallSecretHiddenFileAPI) {
|
||||
// invoke a method to get a Cocoa-internal nav view
|
||||
SEL navViewSelector = @selector(_navView);
|
||||
NSMethodSignature* navViewSignature = [panel methodSignatureForSelector:navViewSelector];
|
||||
NSMethodSignature* navViewSignature =
|
||||
[panel methodSignatureForSelector:navViewSelector];
|
||||
if (!navViewSignature) return;
|
||||
NSInvocation* navViewInvocation = [NSInvocation invocationWithMethodSignature:navViewSignature];
|
||||
NSInvocation* navViewInvocation =
|
||||
[NSInvocation invocationWithMethodSignature:navViewSignature];
|
||||
[navViewInvocation setSelector:navViewSelector];
|
||||
[navViewInvocation setTarget:panel];
|
||||
[navViewInvocation invoke];
|
||||
|
@ -90,27 +92,32 @@ nsFilePicker::nsFilePicker() : mSelectedTypeIndex(0) {}
|
|||
|
||||
nsFilePicker::~nsFilePicker() {}
|
||||
|
||||
void nsFilePicker::InitNative(nsIWidget* aParent, const nsAString& aTitle) { mTitle = aTitle; }
|
||||
void nsFilePicker::InitNative(nsIWidget* aParent, const nsAString& aTitle) {
|
||||
mTitle = aTitle;
|
||||
}
|
||||
|
||||
NSView* nsFilePicker::GetAccessoryView() {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSView* accessoryView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease];
|
||||
NSView* accessoryView =
|
||||
[[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease];
|
||||
|
||||
// Set a label's default value.
|
||||
NSString* label = @"Format:";
|
||||
|
||||
// Try to get the localized string.
|
||||
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
nsCOMPtr<nsIStringBundleService> sbs =
|
||||
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
nsresult rv =
|
||||
sbs->CreateBundle("chrome://global/locale/filepicker.properties", getter_AddRefs(bundle));
|
||||
nsresult rv = sbs->CreateBundle(
|
||||
"chrome://global/locale/filepicker.properties", getter_AddRefs(bundle));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoString locaLabel;
|
||||
rv = bundle->GetStringFromName("formatLabel", locaLabel);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
label = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get())
|
||||
length:locaLabel.Length()];
|
||||
label = [NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get())
|
||||
length:locaLabel.Length()];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,8 +134,9 @@ NSView* nsFilePicker::GetAccessoryView() {
|
|||
[textField sizeToFit];
|
||||
|
||||
// set up popup button
|
||||
NSPopUpButton* popupButton = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)
|
||||
pullsDown:NO] autorelease];
|
||||
NSPopUpButton* popupButton =
|
||||
[[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)
|
||||
pullsDown:NO] autorelease];
|
||||
uint32_t numMenuItems = mTitles.Length();
|
||||
for (uint32_t i = 0; i < numMenuItems; i++) {
|
||||
const nsString& currentTitle = mTitles[i];
|
||||
|
@ -136,11 +144,13 @@ NSView* nsFilePicker::GetAccessoryView() {
|
|||
if (currentTitle.IsEmpty()) {
|
||||
const nsString& currentFilter = mFilters[i];
|
||||
titleString =
|
||||
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentFilter.get())
|
||||
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(
|
||||
currentFilter.get())
|
||||
length:currentFilter.Length()];
|
||||
} else {
|
||||
titleString =
|
||||
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentTitle.get())
|
||||
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(
|
||||
currentTitle.get())
|
||||
length:currentTitle.Length()];
|
||||
}
|
||||
[popupButton addItemWithTitle:titleString];
|
||||
|
@ -149,28 +159,34 @@ NSView* nsFilePicker::GetAccessoryView() {
|
|||
if (mSelectedTypeIndex >= 0 && (uint32_t)mSelectedTypeIndex < numMenuItems)
|
||||
[popupButton selectItemAtIndex:mSelectedTypeIndex];
|
||||
[popupButton setTag:kSaveTypeControlTag];
|
||||
[popupButton sizeToFit]; // we have to do sizeToFit to get the height calculated for us
|
||||
// This is just a default width that works well, doesn't truncate the vast majority of
|
||||
// things that might end up in the menu.
|
||||
[popupButton sizeToFit]; // we have to do sizeToFit to get the height
|
||||
// calculated for us
|
||||
// This is just a default width that works well, doesn't truncate the vast
|
||||
// majority of things that might end up in the menu.
|
||||
[popupButton setFrameSize:NSMakeSize(180, [popupButton frame].size.height)];
|
||||
|
||||
// position everything based on control sizes with kAccessoryViewPadding pix padding
|
||||
// on each side kAccessoryViewPadding pix horizontal padding between controls
|
||||
// position everything based on control sizes with kAccessoryViewPadding pix
|
||||
// padding on each side kAccessoryViewPadding pix horizontal padding between
|
||||
// controls
|
||||
float greatestHeight = [textField frame].size.height;
|
||||
if ([popupButton frame].size.height > greatestHeight)
|
||||
greatestHeight = [popupButton frame].size.height;
|
||||
float totalViewHeight = greatestHeight + kAccessoryViewPadding * 2;
|
||||
float totalViewWidth =
|
||||
[textField frame].size.width + [popupButton frame].size.width + kAccessoryViewPadding * 3;
|
||||
float totalViewWidth = [textField frame].size.width +
|
||||
[popupButton frame].size.width +
|
||||
kAccessoryViewPadding * 3;
|
||||
[accessoryView setFrameSize:NSMakeSize(totalViewWidth, totalViewHeight)];
|
||||
|
||||
float textFieldOriginY =
|
||||
((greatestHeight - [textField frame].size.height) / 2 + 1) + kAccessoryViewPadding;
|
||||
[textField setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)];
|
||||
((greatestHeight - [textField frame].size.height) / 2 + 1) +
|
||||
kAccessoryViewPadding;
|
||||
[textField
|
||||
setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)];
|
||||
|
||||
float popupOriginX = [textField frame].size.width + kAccessoryViewPadding * 2;
|
||||
float popupOriginY =
|
||||
((greatestHeight - [popupButton frame].size.height) / 2) + kAccessoryViewPadding;
|
||||
((greatestHeight - [popupButton frame].size.height) / 2) +
|
||||
kAccessoryViewPadding;
|
||||
[popupButton setFrameOrigin:NSMakePoint(popupOriginX, popupOriginY)];
|
||||
|
||||
[accessoryView addSubview:textField];
|
||||
|
@ -255,9 +271,10 @@ static void UpdatePanelFileTypes(NSOpenPanel* aPanel, NSArray* aFilters) {
|
|||
}
|
||||
@end
|
||||
|
||||
// Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in the dialog.
|
||||
nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
|
||||
nsCOMArray<nsIFile>& outFiles) {
|
||||
// Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in
|
||||
// the dialog.
|
||||
nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(
|
||||
bool inAllowMultiple, nsCOMArray<nsIFile>& outFiles) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
ResultCode retVal = nsIFilePicker::returnCancel;
|
||||
|
@ -308,10 +325,11 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
|
|||
[observer setOpenPanel:thePanel];
|
||||
[observer setFilePicker:this];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:observer
|
||||
selector:@selector(menuChangedItem:)
|
||||
name:NSMenuWillSendActionNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:observer
|
||||
selector:@selector(menuChangedItem:)
|
||||
name:NSMenuWillSendActionNotification
|
||||
object:nil];
|
||||
|
||||
UpdatePanelFileTypes(thePanel, filters);
|
||||
result = [thePanel runModal];
|
||||
|
@ -343,7 +361,8 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
|
|||
nsCOMPtr<nsIFile> localFile;
|
||||
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
|
||||
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)url))) {
|
||||
if (macLocalFile &&
|
||||
NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)url))) {
|
||||
outFiles.AppendObject(localFile);
|
||||
}
|
||||
}
|
||||
|
@ -355,10 +374,13 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(nsIFilePicker::returnOK);
|
||||
}
|
||||
|
||||
// Use OpenPanel to do a GetFolder. Returns |returnOK| if the user presses OK in the dialog.
|
||||
// Use OpenPanel to do a GetFolder. Returns |returnOK| if the user presses OK in
|
||||
// the dialog.
|
||||
nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
|
||||
NS_ASSERTION(
|
||||
outFile,
|
||||
"this protected member function expects a null initialized out pointer");
|
||||
|
||||
ResultCode retVal = nsIFilePicker::returnCancel;
|
||||
NSOpenPanel* thePanel = [NSOpenPanel openPanel];
|
||||
|
@ -394,7 +416,8 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
|
|||
nsCOMPtr<nsIFile> localFile;
|
||||
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
|
||||
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)theURL))) {
|
||||
if (macLocalFile &&
|
||||
NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)theURL))) {
|
||||
*outFile = localFile;
|
||||
NS_ADDREF(*outFile);
|
||||
retVal = returnOK;
|
||||
|
@ -409,7 +432,9 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
|
|||
// Returns |returnOK| if the user presses OK in the dialog.
|
||||
nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
|
||||
NS_ASSERTION(
|
||||
outFile,
|
||||
"this protected member function expects a null initialized out pointer");
|
||||
|
||||
ResultCode retVal = nsIFilePicker::returnCancel;
|
||||
NSSavePanel* thePanel = [NSSavePanel savePanel];
|
||||
|
@ -423,8 +448,9 @@ nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
|
|||
[thePanel setAccessoryView:accessoryView];
|
||||
|
||||
// set up default file name
|
||||
NSString* defaultFilename = [NSString stringWithCharacters:(const unichar*)mDefaultFilename.get()
|
||||
length:mDefaultFilename.Length()];
|
||||
NSString* defaultFilename =
|
||||
[NSString stringWithCharacters:(const unichar*)mDefaultFilename.get()
|
||||
length:mDefaultFilename.Length()];
|
||||
|
||||
// Set up the allowed type. This prevents the extension from being selected.
|
||||
NSString* extension = defaultFilename.pathExtension;
|
||||
|
@ -440,12 +466,13 @@ nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
|
|||
// trying to add a non-default extension. To avoid the confusion, we ensure
|
||||
// that all extensions are shown in the panel if the remaining extension is
|
||||
// known by the OS.
|
||||
NSString* fileName = [[defaultFilename lastPathComponent] stringByDeletingPathExtension];
|
||||
NSString* fileName =
|
||||
[[defaultFilename lastPathComponent] stringByDeletingPathExtension];
|
||||
NSString* otherExtension = fileName.pathExtension;
|
||||
if (otherExtension.length != 0) {
|
||||
// There's another extension here. Get the UTI.
|
||||
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
|
||||
(CFStringRef)otherExtension, NULL);
|
||||
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(
|
||||
kUTTagClassFilenameExtension, (CFStringRef)otherExtension, NULL);
|
||||
if (type) {
|
||||
if (!CFStringHasPrefix(type, CFSTR("dyn."))) {
|
||||
// We have a UTI, otherwise the type would have a "dyn." prefix. Ensure
|
||||
|
@ -480,11 +507,13 @@ nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
|
|||
nsCOMPtr<nsIFile> localFile;
|
||||
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
|
||||
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)fileURL))) {
|
||||
if (macLocalFile &&
|
||||
NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)fileURL))) {
|
||||
*outFile = localFile;
|
||||
NS_ADDREF(*outFile);
|
||||
// We tell if we are replacing or not by just looking to see if the file exists.
|
||||
// The user could not have hit OK and not meant to replace the file.
|
||||
// We tell if we are replacing or not by just looking to see if the file
|
||||
// exists. The user could not have hit OK and not meant to replace the
|
||||
// file.
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
|
||||
retVal = returnReplace;
|
||||
else
|
||||
|
@ -505,7 +534,8 @@ NSArray* nsFilePicker::GetFilterList() {
|
|||
}
|
||||
|
||||
if (mFilters.Length() <= (uint32_t)mSelectedTypeIndex) {
|
||||
NS_WARNING("An out of range index has been selected. Using the first index instead.");
|
||||
NS_WARNING("An out of range index has been selected. Using the first index "
|
||||
"instead.");
|
||||
mSelectedTypeIndex = 0;
|
||||
}
|
||||
|
||||
|
@ -522,17 +552,21 @@ NSArray* nsFilePicker::GetFilterList() {
|
|||
// in the format "ext" by NSOpenPanel. So we need to filter some characters.
|
||||
NSMutableString* filterString = [[[NSMutableString alloc]
|
||||
initWithString:[NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(filterWide.get())
|
||||
length:filterWide.Length()]] autorelease];
|
||||
NSCharacterSet* set = [NSCharacterSet characterSetWithCharactersInString:@". *"];
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
filterWide.get())
|
||||
length:filterWide.Length()]]
|
||||
autorelease];
|
||||
NSCharacterSet* set =
|
||||
[NSCharacterSet characterSetWithCharactersInString:@". *"];
|
||||
NSRange range = [filterString rangeOfCharacterFromSet:set];
|
||||
while (range.length) {
|
||||
[filterString replaceCharactersInRange:range withString:@""];
|
||||
range = [filterString rangeOfCharacterFromSet:set];
|
||||
}
|
||||
|
||||
return
|
||||
[[[NSArray alloc] initWithArray:[filterString componentsSeparatedByString:@";"]] autorelease];
|
||||
return [[[NSArray alloc]
|
||||
initWithArray:[filterString componentsSeparatedByString:@";"]]
|
||||
autorelease];
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
@ -546,8 +580,10 @@ void nsFilePicker::SetDialogTitle(const nsString& inTitle, id aPanel) {
|
|||
length:inTitle.Length()]];
|
||||
|
||||
if (!mOkButtonLabel.IsEmpty()) {
|
||||
[aPanel setPrompt:[NSString stringWithCharacters:(const unichar*)mOkButtonLabel.get()
|
||||
length:mOkButtonLabel.Length()]];
|
||||
[aPanel
|
||||
setPrompt:[NSString
|
||||
stringWithCharacters:(const unichar*)mOkButtonLabel.get()
|
||||
length:mOkButtonLabel.Length()]];
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
|
@ -562,9 +598,9 @@ NSString* nsFilePicker::PanelDefaultDirectory() {
|
|||
if (mDisplayDirectory) {
|
||||
nsAutoString pathStr;
|
||||
mDisplayDirectory->GetPath(pathStr);
|
||||
directory =
|
||||
[[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get())
|
||||
length:pathStr.Length()] autorelease];
|
||||
directory = [[[NSString alloc]
|
||||
initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get())
|
||||
length:pathStr.Length()] autorelease];
|
||||
}
|
||||
return directory;
|
||||
|
||||
|
@ -602,7 +638,9 @@ NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString) { return NS_ERROR_FAILURE; }
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// The default extension to use for files
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension) {
|
||||
|
@ -610,7 +648,9 @@ NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension) { return NS_OK; }
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Append an entry to the filters array
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -47,18 +47,22 @@ void nsLookAndFeel::NativeInit() {
|
|||
}
|
||||
|
||||
static nscolor GetColorFromNSColor(NSColor* aColor) {
|
||||
NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
||||
NSColor* deviceColor =
|
||||
[aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
||||
return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0),
|
||||
(unsigned int)(deviceColor.greenComponent * 255.0),
|
||||
(unsigned int)(deviceColor.blueComponent * 255.0),
|
||||
(unsigned int)(deviceColor.alphaComponent * 255.0));
|
||||
}
|
||||
|
||||
static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor, float alpha) {
|
||||
NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
||||
static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor,
|
||||
float alpha) {
|
||||
NSColor* deviceColor =
|
||||
[aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
||||
return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0),
|
||||
(unsigned int)(deviceColor.greenComponent * 255.0),
|
||||
(unsigned int)(deviceColor.blueComponent * 255.0), (unsigned int)(alpha * 255.0));
|
||||
(unsigned int)(deviceColor.blueComponent * 255.0),
|
||||
(unsigned int)(alpha * 255.0));
|
||||
}
|
||||
|
||||
// Turns an opaque selection color into a partially transparent selection color,
|
||||
|
@ -74,11 +78,12 @@ static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor, float alpha)
|
|||
// whereas white text on dark blue (which what you get if you mix
|
||||
// partially-transparent light blue with the black textbox background) has much
|
||||
// better contrast.
|
||||
nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor, ColorScheme aScheme) {
|
||||
nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor,
|
||||
ColorScheme aScheme) {
|
||||
if (aScheme == ColorScheme::Dark) {
|
||||
// When we use a dark selection color, we do not change alpha because we do
|
||||
// not use dark selection in content. The dark system color is appropriate for
|
||||
// Firefox UI without needing to adjust its alpha.
|
||||
// not use dark selection in content. The dark system color is appropriate
|
||||
// for Firefox UI without needing to adjust its alpha.
|
||||
return aColor;
|
||||
}
|
||||
uint16_t hue, sat, value;
|
||||
|
@ -100,7 +105,8 @@ nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor, ColorScheme aS
|
|||
return resultColor;
|
||||
}
|
||||
|
||||
nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor& aColor) {
|
||||
nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme,
|
||||
nscolor& aColor) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK
|
||||
|
||||
NSAppearance.currentAppearance = NSAppearanceForColorScheme(aScheme);
|
||||
|
@ -108,18 +114,19 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
|||
nscolor color = 0;
|
||||
switch (aID) {
|
||||
case ColorID::Infobackground:
|
||||
color = aScheme == ColorScheme::Light ? NS_RGB(0xdd, 0xdd, 0xdd)
|
||||
: GetColorFromNSColor(NSColor.windowBackgroundColor);
|
||||
color = aScheme == ColorScheme::Light
|
||||
? NS_RGB(0xdd, 0xdd, 0xdd)
|
||||
: GetColorFromNSColor(NSColor.windowBackgroundColor);
|
||||
break;
|
||||
case ColorID::Highlight:
|
||||
color = ProcessSelectionBackground(GetColorFromNSColor(NSColor.selectedTextBackgroundColor),
|
||||
aScheme);
|
||||
color = ProcessSelectionBackground(
|
||||
GetColorFromNSColor(NSColor.selectedTextBackgroundColor), aScheme);
|
||||
break;
|
||||
// This is used to gray out the selection when it's not focused. Used with
|
||||
// nsISelectionController::SELECTION_DISABLED.
|
||||
case ColorID::TextSelectDisabledBackground:
|
||||
color = ProcessSelectionBackground(GetColorFromNSColor(NSColor.secondarySelectedControlColor),
|
||||
aScheme);
|
||||
color = ProcessSelectionBackground(
|
||||
GetColorFromNSColor(NSColor.secondarySelectedControlColor), aScheme);
|
||||
break;
|
||||
case ColorID::MozMenuhoverdisabled:
|
||||
aColor = NS_TRANSPARENT;
|
||||
|
@ -158,23 +165,26 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
|||
//
|
||||
// css2 system colors http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
|
||||
//
|
||||
// It's really hard to effectively map these to the Appearance Manager properly,
|
||||
// since they are modeled word for word after the win32 system colors and don't have any
|
||||
// real counterparts in the Mac world. I'm sure we'll be tweaking these for
|
||||
// years to come.
|
||||
// It's really hard to effectively map these to the Appearance Manager
|
||||
// properly, since they are modeled word for word after the win32 system
|
||||
// colors and don't have any real counterparts in the Mac world. I'm sure
|
||||
// we'll be tweaking these for years to come.
|
||||
//
|
||||
// Thanks to mpt26@student.canterbury.ac.nz for the hardcoded values that form the defaults
|
||||
// Thanks to mpt26@student.canterbury.ac.nz for the hardcoded values that
|
||||
// form the defaults
|
||||
// if querying the Appearance Manager fails ;)
|
||||
//
|
||||
case ColorID::MozMacDefaultbuttontext:
|
||||
color = NS_RGB(0xFF, 0xFF, 0xFF);
|
||||
break;
|
||||
case ColorID::MozButtonactivetext:
|
||||
// Pre-macOS 12, pressed buttons were filled with the highlight color and the text was white.
|
||||
// Starting with macOS 12, pressed (non-default) buttons are filled with medium gray and the
|
||||
// text color is the same as in the non-pressed state.
|
||||
color = nsCocoaFeatures::OnMontereyOrLater() ? GetColorFromNSColor(NSColor.controlTextColor)
|
||||
: NS_RGB(0xFF, 0xFF, 0xFF);
|
||||
// Pre-macOS 12, pressed buttons were filled with the highlight color and
|
||||
// the text was white. Starting with macOS 12, pressed (non-default)
|
||||
// buttons are filled with medium gray and the text color is the same as
|
||||
// in the non-pressed state.
|
||||
color = nsCocoaFeatures::OnMontereyOrLater()
|
||||
? GetColorFromNSColor(NSColor.controlTextColor)
|
||||
: NS_RGB(0xFF, 0xFF, 0xFF);
|
||||
break;
|
||||
case ColorID::Menutext:
|
||||
case ColorID::Infotext:
|
||||
|
@ -209,18 +219,22 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
|||
break;
|
||||
case ColorID::Buttonshadow:
|
||||
case ColorID::Threeddarkshadow:
|
||||
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID) : NS_RGB(0xDC, 0xDC, 0xDC);
|
||||
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID)
|
||||
: NS_RGB(0xDC, 0xDC, 0xDC);
|
||||
break;
|
||||
case ColorID::Threedshadow:
|
||||
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID) : NS_RGB(0xE0, 0xE0, 0xE0);
|
||||
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID)
|
||||
: NS_RGB(0xE0, 0xE0, 0xE0);
|
||||
break;
|
||||
case ColorID::Threedface:
|
||||
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID) : NS_RGB(0xF0, 0xF0, 0xF0);
|
||||
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID)
|
||||
: NS_RGB(0xF0, 0xF0, 0xF0);
|
||||
break;
|
||||
case ColorID::Threedlightshadow:
|
||||
case ColorID::Buttonborder:
|
||||
case ColorID::MozDisabledfield:
|
||||
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID) : NS_RGB(0xDA, 0xDA, 0xDA);
|
||||
color = aScheme == ColorScheme::Dark ? *GenericDarkColor(aID)
|
||||
: NS_RGB(0xDA, 0xDA, 0xDA);
|
||||
break;
|
||||
case ColorID::Menu:
|
||||
color = GetColorFromNSColor(NSColor.textBackgroundColor);
|
||||
|
@ -248,7 +262,8 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
|||
color = GetColorFromNSColor(NSColor.controlTextColor);
|
||||
break;
|
||||
case ColorID::MozMacFocusring:
|
||||
color = GetColorFromNSColorWithCustomAlpha(NSColor.keyboardFocusIndicatorColor, 0.48);
|
||||
color = GetColorFromNSColorWithCustomAlpha(
|
||||
NSColor.keyboardFocusIndicatorColor, 0.48);
|
||||
break;
|
||||
case ColorID::MozMacMenutextdisable:
|
||||
color = NS_RGB(0x98, 0x98, 0x98);
|
||||
|
@ -266,11 +281,13 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
|||
break;
|
||||
case ColorID::MozEventreerow:
|
||||
// Background color of even list rows.
|
||||
color = GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[0]);
|
||||
color =
|
||||
GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[0]);
|
||||
break;
|
||||
case ColorID::MozOddtreerow:
|
||||
// Background color of odd list rows.
|
||||
color = GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[1]);
|
||||
color =
|
||||
GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[1]);
|
||||
break;
|
||||
case ColorID::MozNativehyperlinktext:
|
||||
color = GetColorFromNSColor(NSColor.linkColor);
|
||||
|
@ -281,13 +298,16 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
|||
case ColorID::MozMacTooltip:
|
||||
case ColorID::MozMacMenupopup:
|
||||
case ColorID::MozMacMenuitem:
|
||||
color = aScheme == ColorScheme::Light ? NS_RGB(0xf6, 0xf6, 0xf6) : NS_RGB(0x28, 0x28, 0x28);
|
||||
color = aScheme == ColorScheme::Light ? NS_RGB(0xf6, 0xf6, 0xf6)
|
||||
: NS_RGB(0x28, 0x28, 0x28);
|
||||
break;
|
||||
case ColorID::MozMacSourceList:
|
||||
color = aScheme == ColorScheme::Light ? NS_RGB(0xf6, 0xf6, 0xf6) : NS_RGB(0x2d, 0x2d, 0x2d);
|
||||
color = aScheme == ColorScheme::Light ? NS_RGB(0xf6, 0xf6, 0xf6)
|
||||
: NS_RGB(0x2d, 0x2d, 0x2d);
|
||||
break;
|
||||
case ColorID::MozMacSourceListSelection:
|
||||
color = aScheme == ColorScheme::Light ? NS_RGB(0xd3, 0xd3, 0xd3) : NS_RGB(0x2d, 0x2d, 0x2d);
|
||||
color = aScheme == ColorScheme::Light ? NS_RGB(0xd3, 0xd3, 0xd3)
|
||||
: NS_RGB(0x2d, 0x2d, 0x2d);
|
||||
break;
|
||||
case ColorID::MozMacActiveMenuitem:
|
||||
case ColorID::MozMacActiveSourceListSelection:
|
||||
|
@ -298,7 +318,8 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
|||
case ColorID::Inactivecaption:
|
||||
case ColorID::Activecaption: {
|
||||
if (aScheme == ColorScheme::Light &&
|
||||
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast) {
|
||||
NSWorkspace.sharedWorkspace
|
||||
.accessibilityDisplayShouldIncreaseContrast) {
|
||||
// This has better contrast than the stand-in colors.
|
||||
aColor = GetColorFromNSColor(NSColor.windowBackgroundColor);
|
||||
return NS_OK;
|
||||
|
@ -410,11 +431,13 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
|
|||
aResult = NS_ALERT_TOP;
|
||||
break;
|
||||
case IntID::TabFocusModel:
|
||||
aResult = [NSApp isFullKeyboardAccessEnabled] ? nsIContent::eTabFocus_any
|
||||
: nsIContent::eTabFocus_textControlsMask;
|
||||
aResult = [NSApp isFullKeyboardAccessEnabled]
|
||||
? nsIContent::eTabFocus_any
|
||||
: nsIContent::eTabFocus_textControlsMask;
|
||||
break;
|
||||
case IntID::ScrollToClick: {
|
||||
aResult = [[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"];
|
||||
aResult = [[NSUserDefaults standardUserDefaults]
|
||||
boolForKey:@"AppleScrollerPagingBehavior"];
|
||||
} break;
|
||||
case IntID::ChosenMenuItemsShouldBlink:
|
||||
aResult = 1;
|
||||
|
@ -444,19 +467,24 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
|
|||
aResult = SystemWantsDarkTheme();
|
||||
break;
|
||||
case IntID::PrefersReducedMotion:
|
||||
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion;
|
||||
aResult =
|
||||
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion;
|
||||
break;
|
||||
case IntID::PrefersReducedTransparency:
|
||||
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceTransparency;
|
||||
aResult = NSWorkspace.sharedWorkspace
|
||||
.accessibilityDisplayShouldReduceTransparency;
|
||||
break;
|
||||
case IntID::InvertedColors:
|
||||
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldInvertColors;
|
||||
aResult =
|
||||
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldInvertColors;
|
||||
break;
|
||||
case IntID::UseAccessibilityTheme:
|
||||
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast;
|
||||
aResult = NSWorkspace.sharedWorkspace
|
||||
.accessibilityDisplayShouldIncreaseContrast;
|
||||
break;
|
||||
case IntID::VideoDynamicRange: {
|
||||
// If the platform says it supports HDR, then we claim to support video-dynamic-range.
|
||||
// If the platform says it supports HDR, then we claim to support
|
||||
// video-dynamic-range.
|
||||
gfxPlatform* platform = gfxPlatform::GetPlatform();
|
||||
MOZ_ASSERT(platform);
|
||||
aResult = platform->SupportsHDR();
|
||||
|
@ -487,7 +515,8 @@ nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
|
|||
aResult = 2.0f;
|
||||
break;
|
||||
case FloatID::CursorScale: {
|
||||
id uaDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.universalaccess"];
|
||||
id uaDefaults = [[NSUserDefaults alloc]
|
||||
initWithSuiteName:@"com.apple.universalaccess"];
|
||||
float f = [uaDefaults floatForKey:@"mouseDriverCursorSize"];
|
||||
[uaDefaults release];
|
||||
aResult = f > 0.0 ? f : 1.0; // default to 1.0 if value not available
|
||||
|
@ -504,24 +533,29 @@ nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
|
|||
}
|
||||
|
||||
bool nsLookAndFeel::SystemWantsDarkTheme() {
|
||||
// This returns true if the macOS system appearance is set to dark mode, false otherwise.
|
||||
NSAppearanceName aquaOrDarkAqua = [NSApp.effectiveAppearance
|
||||
bestMatchFromAppearancesWithNames:@[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
|
||||
// This returns true if the macOS system appearance is set to dark mode, false
|
||||
// otherwise.
|
||||
NSAppearanceName aquaOrDarkAqua =
|
||||
[NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:@[
|
||||
NSAppearanceNameAqua, NSAppearanceNameDarkAqua
|
||||
]];
|
||||
return [aquaOrDarkAqua isEqualToString:NSAppearanceNameDarkAqua];
|
||||
}
|
||||
|
||||
/*static*/
|
||||
bool nsLookAndFeel::IsSystemOrientationRTL() {
|
||||
NSWindow* window = [[NSWindow alloc] initWithContentRect:NSZeroRect
|
||||
styleMask:NSWindowStyleMaskBorderless
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
NSWindow* window =
|
||||
[[NSWindow alloc] initWithContentRect:NSZeroRect
|
||||
styleMask:NSWindowStyleMaskBorderless
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
auto direction = window.windowTitlebarLayoutDirection;
|
||||
[window release];
|
||||
return direction == NSUserInterfaceLayoutDirectionRightToLeft;
|
||||
}
|
||||
|
||||
bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName, gfxFontStyle& aFontStyle) {
|
||||
bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName,
|
||||
gfxFontStyle& aFontStyle) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsAutoCString name;
|
||||
|
@ -535,8 +569,10 @@ bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName, gfxFontStyle&
|
|||
|
||||
void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
||||
if ([[NSWorkspace sharedWorkspace]
|
||||
respondsToSelector:@selector(accessibilityDisplayShouldInvertColors)]) {
|
||||
bool val = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldInvertColors];
|
||||
respondsToSelector:@selector
|
||||
(accessibilityDisplayShouldInvertColors)]) {
|
||||
bool val =
|
||||
[[NSWorkspace sharedWorkspace] accessibilityDisplayShouldInvertColors];
|
||||
Telemetry::ScalarSet(Telemetry::ScalarID::A11Y_INVERT_COLORS, val);
|
||||
}
|
||||
}
|
||||
|
@ -553,14 +589,16 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
|||
- (instancetype)init {
|
||||
self = [super init];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(colorsChanged)
|
||||
name:NSControlTintDidChangeNotification
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(colorsChanged)
|
||||
name:NSSystemColorsDidChangeNotification
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(colorsChanged)
|
||||
name:NSControlTintDidChangeNotification
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(colorsChanged)
|
||||
name:NSSystemColorsDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[NSWorkspace.sharedWorkspace.notificationCenter
|
||||
addObserver:self
|
||||
|
@ -568,10 +606,11 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
|||
name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(scrollbarsChanged)
|
||||
name:NSPreferredScrollerStyleDidChangeNotification
|
||||
object:nil];
|
||||
[NSNotificationCenter.defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(scrollbarsChanged)
|
||||
name:NSPreferredScrollerStyleDidChangeNotification
|
||||
object:nil];
|
||||
[NSDistributedNotificationCenter.defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(scrollbarsChanged)
|
||||
|
@ -595,7 +634,10 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
|||
forKeyPath:@"effectiveAppearance"
|
||||
options:0
|
||||
context:nil];
|
||||
[NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:0 context:nil];
|
||||
[NSApp addObserver:self
|
||||
forKeyPath:@"effectiveAppearance"
|
||||
options:0
|
||||
context:nil];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -607,7 +649,10 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
|||
if ([keyPath isEqualToString:@"effectiveAppearance"]) {
|
||||
[self entireThemeChanged];
|
||||
} else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
[super observeValueForKeyPath:keyPath
|
||||
ofObject:object
|
||||
change:change
|
||||
context:context];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -620,11 +665,12 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
|||
}
|
||||
|
||||
- (void)mediaQueriesChanged {
|
||||
// Changing`Invert Colors` sends AccessibilityDisplayOptionsDidChangeNotifications.
|
||||
// We monitor that setting via telemetry, so call into that
|
||||
// recording method here.
|
||||
// Changing`Invert Colors` sends
|
||||
// AccessibilityDisplayOptionsDidChangeNotifications. We monitor that setting
|
||||
// via telemetry, so call into that recording method here.
|
||||
nsLookAndFeel::RecordAccessibilityTelemetry();
|
||||
LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::MediaQueriesOnly);
|
||||
LookAndFeel::NotifyChangedAllWindows(
|
||||
widget::ThemeChangeKind::MediaQueriesOnly);
|
||||
}
|
||||
|
||||
- (void)colorsChanged {
|
||||
|
@ -632,9 +678,12 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
|||
}
|
||||
|
||||
- (void)cachedValuesChanged {
|
||||
// We only need to re-cache (and broadcast) updated LookAndFeel values, so that they're
|
||||
// up-to-date the next time they're queried. No further change handling is needed.
|
||||
// TODO: Add a change hint for this which avoids the unnecessary media query invalidation.
|
||||
LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::MediaQueriesOnly);
|
||||
// We only need to re-cache (and broadcast) updated LookAndFeel values, so
|
||||
// that they're up-to-date the next time they're queried. No further change
|
||||
// handling is needed.
|
||||
// TODO: Add a change hint for this which avoids the unnecessary media query
|
||||
// invalidation.
|
||||
LookAndFeel::NotifyChangedAllWindows(
|
||||
widget::ThemeChangeKind::MediaQueriesOnly);
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
|
||||
/*! @category nsMacCursor (PrivateMethods)
|
||||
@abstract Private methods internal to the nsMacCursor class.
|
||||
@discussion <code>nsMacCursor</code> is effectively an abstract class. It does not define
|
||||
complete behaviour in and of itself, the subclasses defined in this file provide the useful
|
||||
implementations.
|
||||
@discussion <code>nsMacCursor</code> is effectively an abstract class. It
|
||||
does not define complete behaviour in and of itself, the subclasses defined
|
||||
in this file provide the useful implementations.
|
||||
*/
|
||||
@interface nsMacCursor (PrivateMethods)
|
||||
|
||||
|
@ -27,56 +27,62 @@
|
|||
|
||||
/*! @method numFrames
|
||||
@abstract Query the number of frames in this cursor's animation.
|
||||
@discussion Returns the number of frames in this cursor's animation. Static cursors return 1.
|
||||
@discussion Returns the number of frames in this cursor's animation. Static
|
||||
cursors return 1.
|
||||
*/
|
||||
- (int)numFrames;
|
||||
|
||||
/*! @method createTimer
|
||||
@abstract Create a Timer to use to animate the cursor.
|
||||
@discussion Creates an instance of <code>NSTimer</code> which is used to drive the cursor
|
||||
animation. This method should only be called for cursors that are animated.
|
||||
@discussion Creates an instance of <code>NSTimer</code> which is used to
|
||||
drive the cursor animation. This method should only be called for cursors
|
||||
that are animated.
|
||||
*/
|
||||
- (void)createTimer;
|
||||
|
||||
/*! @method destroyTimer
|
||||
@abstract Destroy any timer instance associated with this cursor.
|
||||
@discussion Invalidates and releases any <code>NSTimer</code> instance associated with this
|
||||
cursor.
|
||||
@discussion Invalidates and releases any <code>NSTimer</code> instance
|
||||
associated with this cursor.
|
||||
*/
|
||||
- (void)destroyTimer;
|
||||
/*! @method destroyTimer
|
||||
@abstract Destroy any timer instance associated with this cursor.
|
||||
@discussion Invalidates and releases any <code>NSTimer</code> instance associated with this
|
||||
cursor.
|
||||
@discussion Invalidates and releases any <code>NSTimer</code> instance
|
||||
associated with this cursor.
|
||||
*/
|
||||
|
||||
/*! @method advanceAnimatedCursor:
|
||||
@abstract Method called by animation timer to perform animation.
|
||||
@discussion Called by an animated cursor's associated timer to advance the animation to the next
|
||||
frame. Determines which frame should occur next and sets the cursor to that frame.
|
||||
@discussion Called by an animated cursor's associated timer to advance the
|
||||
animation to the next frame. Determines which frame should occur next and
|
||||
sets the cursor to that frame.
|
||||
@param aTimer the timer causing the animation
|
||||
*/
|
||||
- (void)advanceAnimatedCursor:(NSTimer*)aTimer;
|
||||
|
||||
/*! @method setFrame:
|
||||
@abstract Sets the current cursor, using an index to determine which frame in the animation to
|
||||
display.
|
||||
@discussion Sets the current cursor. The frame index determines which frame is shown if the
|
||||
cursor is animated. Frames and numbered from <code>0</code> to <code>-[nsMacCursor numFrames] -
|
||||
1</code>. A static cursor has a single frame, numbered 0.
|
||||
@param aFrameIndex the index indicating which frame from the animation to display
|
||||
@abstract Sets the current cursor, using an index to determine which frame
|
||||
in the animation to display.
|
||||
@discussion Sets the current cursor. The frame index determines which frame
|
||||
is shown if the cursor is animated. Frames and numbered from <code>0</code>
|
||||
to <code>-[nsMacCursor numFrames] - 1</code>. A static cursor has a single
|
||||
frame, numbered 0.
|
||||
@param aFrameIndex the index indicating which frame from the animation
|
||||
to display
|
||||
*/
|
||||
- (void)setFrame:(int)aFrameIndex;
|
||||
|
||||
@end
|
||||
|
||||
/*! @class nsCocoaCursor
|
||||
@abstract Implementation of <code>nsMacCursor</code> that uses Cocoa <code>NSCursor</code>
|
||||
instances.
|
||||
@discussion Displays a static or animated cursor, using Cocoa <code>NSCursor</code> instances.
|
||||
These can be either built-in <code>NSCursor</code> instances, or custom <code>NSCursor</code>s
|
||||
created from images. When more than one <code>NSCursor</code> is provided, the cursor will use
|
||||
these as animation frames.
|
||||
@abstract Implementation of <code>nsMacCursor</code> that uses Cocoa
|
||||
<code>NSCursor</code> instances.
|
||||
@discussion Displays a static or animated cursor, using Cocoa
|
||||
<code>NSCursor</code> instances. These can be either built-in
|
||||
<code>NSCursor</code> instances, or custom <code>NSCursor</code>s created
|
||||
from images. When more than one <code>NSCursor</code> is provided, the cursor
|
||||
will use these as animation frames.
|
||||
*/
|
||||
@interface nsCocoaCursor : nsMacCursor {
|
||||
@private
|
||||
|
@ -85,13 +91,16 @@
|
|||
}
|
||||
|
||||
/*! @method initWithFrames:
|
||||
@abstract Create an animated cursor by specifying the frames to use for the animation.
|
||||
@discussion Creates a cursor that will animate by cycling through the given frames. Each element
|
||||
of the array must be an instance of <code>NSCursor</code>
|
||||
@param aCursorFrames an array of <code>NSCursor</code>, representing the frames of an
|
||||
animated cursor, in the order they should be played.
|
||||
@abstract Create an animated cursor by specifying the frames to use for
|
||||
the animation.
|
||||
@discussion Creates a cursor that will animate by cycling through the given
|
||||
frames. Each element of the array must be an instance of
|
||||
<code>NSCursor</code>
|
||||
@param aCursorFrames an array of <code>NSCursor</code>, representing
|
||||
the frames of an animated cursor, in the order they should be played.
|
||||
@param aType the corresponding <code>nsCursor</code> constant
|
||||
@result an instance of <code>nsCocoaCursor</code> that will animate the given cursor frames
|
||||
@result an instance of <code>nsCocoaCursor</code> that will animate the
|
||||
given cursor frames
|
||||
*/
|
||||
- (id)initWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType;
|
||||
|
||||
|
@ -106,18 +115,22 @@
|
|||
- (id)initWithCursor:(NSCursor*)aCursor type:(nsCursor)aType;
|
||||
|
||||
/*! @method initWithImageNamed:hotSpot:
|
||||
@abstract Create a cursor by specifying the name of an image resource to use for the cursor
|
||||
and a hotspot.
|
||||
@discussion Creates a cursor by loading the named image using the <code>+[NSImage
|
||||
imageNamed:]</code> method. <p>The image must be compatible with any restrictions laid down by
|
||||
<code>NSCursor</code>. These vary by operating system version.</p> <p>The hotspot precisely
|
||||
determines the point where the user clicks when using the cursor.</p>
|
||||
@abstract Create a cursor by specifying the name of an image resource to
|
||||
use for the cursor and a hotspot.
|
||||
@discussion Creates a cursor by loading the named image using the
|
||||
<code>+[NSImage imageNamed:]</code> method. <p>The image must be compatible
|
||||
with any restrictions laid down by <code>NSCursor</code>. These vary by
|
||||
operating system version.</p> <p>The hotspot precisely determines the point
|
||||
where the user clicks when using the cursor.</p>
|
||||
@param aCursor the name of the image to use for the cursor
|
||||
@param aPoint the point within the cursor to use as the hotspot
|
||||
@param aType the corresponding <code>nsCursor</code> constant
|
||||
@result an instance of <code>nsCocoaCursor</code> that uses the given image and hotspot
|
||||
@result an instance of <code>nsCocoaCursor</code> that uses the given
|
||||
image and hotspot
|
||||
*/
|
||||
- (id)initWithImageNamed:(NSString*)aCursorImage hotSpot:(NSPoint)aPoint type:(nsCursor)aType;
|
||||
- (id)initWithImageNamed:(NSString*)aCursorImage
|
||||
hotSpot:(NSPoint)aPoint
|
||||
type:(nsCursor)aType;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -126,7 +139,8 @@
|
|||
+ (nsMacCursor*)cursorWithCursor:(NSCursor*)aCursor type:(nsCursor)aType {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
return [[[nsCocoaCursor alloc] initWithCursor:aCursor type:aType] autorelease];
|
||||
return [[[nsCocoaCursor alloc] initWithCursor:aCursor
|
||||
type:aType] autorelease];
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
@ -136,7 +150,8 @@
|
|||
type:(nsCursor)aType {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
return [[[nsCocoaCursor alloc] initWithImageNamed:aCursorImage hotSpot:aPoint
|
||||
return [[[nsCocoaCursor alloc] initWithImageNamed:aCursorImage
|
||||
hotSpot:aPoint
|
||||
type:aType] autorelease];
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
|
@ -145,12 +160,14 @@
|
|||
+ (nsMacCursor*)cursorWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
return [[[nsCocoaCursor alloc] initWithFrames:aCursorFrames type:aType] autorelease];
|
||||
return [[[nsCocoaCursor alloc] initWithFrames:aCursorFrames
|
||||
type:aType] autorelease];
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
||||
+ (NSCursor*)cocoaCursorWithImageNamed:(NSString*)imageName hotSpot:(NSPoint)aPoint {
|
||||
+ (NSCursor*)cocoaCursorWithImageNamed:(NSString*)imageName
|
||||
hotSpot:(NSPoint)aPoint {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsCOMPtr<nsIFile> resDir;
|
||||
|
@ -174,22 +191,26 @@
|
|||
pathToImage = [pathToImage stringByAppendingPathExtension:@"png"];
|
||||
pathToHiDpiImage = [pathToHiDpiImage stringByAppendingPathExtension:@"png"];
|
||||
|
||||
cursorImage = [[[NSImage alloc] initWithContentsOfFile:pathToImage] autorelease];
|
||||
cursorImage =
|
||||
[[[NSImage alloc] initWithContentsOfFile:pathToImage] autorelease];
|
||||
if (!cursorImage) goto INIT_FAILURE;
|
||||
|
||||
// Note 1: There are a few different ways to get a hidpi image via
|
||||
// initWithContentsOfFile. We let the OS handle this here: when the
|
||||
// file basename ends in "@2x", it will be displayed at native resolution
|
||||
// instead of being pixel-doubled. See bug 784909 comment 7 for alternates ways.
|
||||
// instead of being pixel-doubled. See bug 784909 comment 7 for alternates
|
||||
// ways.
|
||||
//
|
||||
// Note 2: The OS is picky, and will ignore the hidpi representation
|
||||
// unless it is exactly twice the size of the lowdpi image.
|
||||
hiDpiCursorImage = [[[NSImage alloc] initWithContentsOfFile:pathToHiDpiImage] autorelease];
|
||||
hiDpiCursorImage =
|
||||
[[[NSImage alloc] initWithContentsOfFile:pathToHiDpiImage] autorelease];
|
||||
if (hiDpiCursorImage) {
|
||||
NSImageRep* imageRep = [[hiDpiCursorImage representations] objectAtIndex:0];
|
||||
[cursorImage addRepresentation:imageRep];
|
||||
}
|
||||
return [[[NSCursor alloc] initWithImage:cursorImage hotSpot:aPoint] autorelease];
|
||||
return [[[NSCursor alloc] initWithImage:cursorImage
|
||||
hotSpot:aPoint] autorelease];
|
||||
|
||||
INIT_FAILURE:
|
||||
NS_WARNING("Problem getting path to cursor image file!");
|
||||
|
@ -236,11 +257,12 @@ INIT_FAILURE:
|
|||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
if (!mTimer) {
|
||||
mTimer = [[NSTimer scheduledTimerWithTimeInterval:0.25
|
||||
target:self
|
||||
selector:@selector(advanceAnimatedCursor:)
|
||||
userInfo:nil
|
||||
repeats:YES] retain];
|
||||
mTimer = [[NSTimer
|
||||
scheduledTimerWithTimeInterval:0.25
|
||||
target:self
|
||||
selector:@selector(advanceAnimatedCursor:)
|
||||
userInfo:nil
|
||||
repeats:YES] retain];
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
|
@ -316,11 +338,15 @@ INIT_FAILURE:
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
||||
- (id)initWithImageNamed:(NSString*)aCursorImage hotSpot:(NSPoint)aPoint type:(nsCursor)aType {
|
||||
- (id)initWithImageNamed:(NSString*)aCursorImage
|
||||
hotSpot:(NSPoint)aPoint
|
||||
type:(nsCursor)aType {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
return [self initWithCursor:[nsMacCursor cocoaCursorWithImageNamed:aCursorImage hotSpot:aPoint]
|
||||
type:aType];
|
||||
return
|
||||
[self initWithCursor:[nsMacCursor cocoaCursorWithImageNamed:aCursorImage
|
||||
hotSpot:aPoint]
|
||||
type:aType];
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ NS_IMPL_ISUPPORTS(nsMacDockSupport, nsIMacDockSupport, nsITaskbarProgress)
|
|||
@synthesize fractionValue = mFractionValue;
|
||||
|
||||
- (void)drawRect:(NSRect)aRect {
|
||||
// Erase the background behind this view, i.e. cut a rectangle hole in the icon.
|
||||
// Erase the background behind this view, i.e. cut a rectangle hole in the
|
||||
// icon.
|
||||
[[NSColor clearColor] set];
|
||||
NSRectFill(self.bounds);
|
||||
|
||||
|
@ -103,7 +104,8 @@ NS_IMETHODIMP
|
|||
nsMacDockSupport::ActivateApplication(bool aIgnoreOtherApplications) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:aIgnoreOtherApplications];
|
||||
[[NSApplication sharedApplication]
|
||||
activateIgnoringOtherApps:aIgnoreOtherApplications];
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
|
@ -118,9 +120,11 @@ nsMacDockSupport::SetBadgeText(const nsAString& aBadgeText) {
|
|||
if (aBadgeText.IsEmpty())
|
||||
[tile setBadgeLabel:nil];
|
||||
else
|
||||
[tile setBadgeLabel:[NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(mBadgeText.get())
|
||||
length:mBadgeText.Length()]];
|
||||
[tile
|
||||
setBadgeLabel:[NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
mBadgeText.get())
|
||||
length:mBadgeText.Length()]];
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
|
@ -133,8 +137,8 @@ nsMacDockSupport::GetBadgeText(nsAString& aBadgeText) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState, uint64_t aCurrentValue,
|
||||
uint64_t aMaxValue) {
|
||||
nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState,
|
||||
uint64_t aCurrentValue, uint64_t aMaxValue) {
|
||||
NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED);
|
||||
if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) {
|
||||
NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
|
||||
|
@ -162,22 +166,26 @@ nsresult nsMacDockSupport::UpdateDockTile() {
|
|||
// Create the following NSView hierarchy:
|
||||
// * mDockTileWrapperView (NSView)
|
||||
// * imageView (NSImageView) <- has the application icon
|
||||
// * mProgressDockOverlayView (MOZProgressDockOverlayView) <- draws the progress bar
|
||||
// * mProgressDockOverlayView (MOZProgressDockOverlayView) <- draws the
|
||||
// progress bar
|
||||
|
||||
mDockTileWrapperView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)];
|
||||
mDockTileWrapperView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
mDockTileWrapperView =
|
||||
[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 32, 32)];
|
||||
mDockTileWrapperView.autoresizingMask =
|
||||
NSViewWidthSizable | NSViewHeightSizable;
|
||||
|
||||
NSImageView* imageView = [[NSImageView alloc] initWithFrame:[mDockTileWrapperView bounds]];
|
||||
NSImageView* imageView =
|
||||
[[NSImageView alloc] initWithFrame:[mDockTileWrapperView bounds]];
|
||||
imageView.image = [NSImage imageNamed:@"NSApplicationIcon"];
|
||||
imageView.imageScaling = NSImageScaleAxesIndependently;
|
||||
imageView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
[mDockTileWrapperView addSubview:imageView];
|
||||
|
||||
mProgressDockOverlayView =
|
||||
[[MOZProgressDockOverlayView alloc] initWithFrame:NSMakeRect(1, 3, 30, 4)];
|
||||
mProgressDockOverlayView.autoresizingMask = NSViewMinXMargin | NSViewWidthSizable |
|
||||
NSViewMaxXMargin | NSViewMinYMargin |
|
||||
NSViewHeightSizable | NSViewMaxYMargin;
|
||||
mProgressDockOverlayView = [[MOZProgressDockOverlayView alloc]
|
||||
initWithFrame:NSMakeRect(1, 3, 30, 4)];
|
||||
mProgressDockOverlayView.autoresizingMask =
|
||||
NSViewMinXMargin | NSViewWidthSizable | NSViewMaxXMargin |
|
||||
NSViewMinYMargin | NSViewHeightSizable | NSViewMaxYMargin;
|
||||
[mDockTileWrapperView addSubview:mProgressDockOverlayView];
|
||||
}
|
||||
if (NSApp.dockTile.contentView != mDockTileWrapperView) {
|
||||
|
@ -205,21 +213,23 @@ nsresult nsMacDockSupport::UpdateDockTile() {
|
|||
extern "C" {
|
||||
// Private CFURL API used by the Dock.
|
||||
CFPropertyListRef _CFURLCopyPropertyListRepresentation(CFURLRef url);
|
||||
CFURLRef _CFURLCreateFromPropertyListRepresentation(CFAllocatorRef alloc,
|
||||
CFPropertyListRef pListRepresentation);
|
||||
CFURLRef _CFURLCreateFromPropertyListRepresentation(
|
||||
CFAllocatorRef alloc, CFPropertyListRef pListRepresentation);
|
||||
} // extern "C"
|
||||
|
||||
namespace {
|
||||
|
||||
const NSArray* const browserAppNames =
|
||||
[NSArray arrayWithObjects:@"Firefox.app", @"Firefox Beta.app", @"Firefox Nightly.app",
|
||||
@"Safari.app", @"WebKit.app", @"Google Chrome.app",
|
||||
@"Google Chrome Canary.app", @"Chromium.app", @"Opera.app", nil];
|
||||
const NSArray* const browserAppNames = [NSArray
|
||||
arrayWithObjects:@"Firefox.app", @"Firefox Beta.app",
|
||||
@"Firefox Nightly.app", @"Safari.app", @"WebKit.app",
|
||||
@"Google Chrome.app", @"Google Chrome Canary.app",
|
||||
@"Chromium.app", @"Opera.app", nil];
|
||||
|
||||
constexpr NSString* const kDockDomainName = @"com.apple.dock";
|
||||
// See https://developer.apple.com/documentation/devicemanagement/dock
|
||||
constexpr NSString* const kDockPersistentAppsKey = @"persistent-apps";
|
||||
// See https://developer.apple.com/documentation/devicemanagement/dock/staticitem
|
||||
// See
|
||||
// https://developer.apple.com/documentation/devicemanagement/dock/staticitem
|
||||
constexpr NSString* const kDockTileDataKey = @"tile-data";
|
||||
constexpr NSString* const kDockFileDataKey = @"file-data";
|
||||
|
||||
|
@ -247,7 +257,8 @@ NSString* GetPathForApp(NSDictionary* aPersistantApp) {
|
|||
// Some special tiles may not have DockFileData but we can ignore those.
|
||||
return nil;
|
||||
}
|
||||
NSURL* url = CFBridgingRelease(_CFURLCreateFromPropertyListRepresentation(NULL, fileData));
|
||||
NSURL* url = CFBridgingRelease(
|
||||
_CFURLCreateFromPropertyListRepresentation(NULL, fileData));
|
||||
if (!url) {
|
||||
return nil;
|
||||
}
|
||||
|
@ -257,7 +268,8 @@ NSString* GetPathForApp(NSDictionary* aPersistantApp) {
|
|||
// The only reliable way to get our changes to take effect seems to be to use
|
||||
// `kill`.
|
||||
void RefreshDock(NSDictionary* aDockPlist) {
|
||||
[[NSUserDefaults standardUserDefaults] setPersistentDomain:aDockPlist forName:kDockDomainName];
|
||||
[[NSUserDefaults standardUserDefaults] setPersistentDomain:aDockPlist
|
||||
forName:kDockDomainName];
|
||||
NSRunningApplication* dockApp = [[NSRunningApplication
|
||||
runningApplicationsWithBundleIdentifier:@"com.apple.dock"] firstObject];
|
||||
if (!dockApp) {
|
||||
|
@ -276,8 +288,8 @@ nsresult nsMacDockSupport::GetIsAppInDock(bool* aIsInDock) {
|
|||
|
||||
*aIsInDock = false;
|
||||
|
||||
NSDictionary* dockPlist =
|
||||
[[NSUserDefaults standardUserDefaults] persistentDomainForName:kDockDomainName];
|
||||
NSDictionary* dockPlist = [[NSUserDefaults standardUserDefaults]
|
||||
persistentDomainForName:kDockDomainName];
|
||||
if (!dockPlist) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -302,22 +314,22 @@ nsresult nsMacDockSupport::GetIsAppInDock(bool* aIsInDock) {
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
|
||||
const nsAString& aAppToReplacePath,
|
||||
bool* aIsInDock) {
|
||||
nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(
|
||||
const nsAString& aAppPath, const nsAString& aAppToReplacePath,
|
||||
bool* aIsInDock) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
MOZ_ASSERT(aAppPath != aAppToReplacePath || !aAppPath.IsEmpty());
|
||||
|
||||
*aIsInDock = false;
|
||||
|
||||
NSString* appPath =
|
||||
!aAppPath.IsEmpty() ? nsCocoaUtils::ToNSString(aAppPath) : [[NSBundle mainBundle] bundlePath];
|
||||
NSString* appPath = !aAppPath.IsEmpty() ? nsCocoaUtils::ToNSString(aAppPath)
|
||||
: [[NSBundle mainBundle] bundlePath];
|
||||
NSString* appToReplacePath = nsCocoaUtils::ToNSString(aAppToReplacePath);
|
||||
|
||||
NSMutableDictionary* dockPlist =
|
||||
[NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults]
|
||||
persistentDomainForName:kDockDomainName]];
|
||||
NSMutableDictionary* dockPlist = [NSMutableDictionary
|
||||
dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults]
|
||||
persistentDomainForName:kDockDomainName]];
|
||||
if (!dockPlist) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -335,11 +347,13 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
|
|||
NSUInteger toReplaceAppIndex = NSNotFound;
|
||||
NSUInteger lastBrowserAppIndex = NSNotFound;
|
||||
for (NSUInteger index = 0; index < [persistentApps count]; ++index) {
|
||||
NSString* persistentAppPath = GetPathForApp([persistentApps objectAtIndex:index]);
|
||||
NSString* persistentAppPath =
|
||||
GetPathForApp([persistentApps objectAtIndex:index]);
|
||||
|
||||
if ([persistentAppPath isEqualToString:appPath]) {
|
||||
preexistingAppIndex = index;
|
||||
} else if (appToReplacePath && [persistentAppPath isEqualToString:appToReplacePath]) {
|
||||
} else if (appToReplacePath &&
|
||||
[persistentAppPath isEqualToString:appToReplacePath]) {
|
||||
toReplaceAppIndex = index;
|
||||
} else {
|
||||
NSString* appName = [appPath lastPathComponent];
|
||||
|
@ -381,14 +395,16 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
|
|||
NSDictionary* newDockTile = nullptr;
|
||||
{
|
||||
NSURL* appUrl = [NSURL fileURLWithPath:appPath isDirectory:YES];
|
||||
NSDictionary* dict =
|
||||
CFBridgingRelease(_CFURLCopyPropertyListRepresentation((__bridge CFURLRef)appUrl));
|
||||
NSDictionary* dict = CFBridgingRelease(
|
||||
_CFURLCopyPropertyListRepresentation((__bridge CFURLRef)appUrl));
|
||||
if (!dict) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
NSDictionary* dockTileData = [NSDictionary dictionaryWithObject:dict forKey:kDockFileDataKey];
|
||||
NSDictionary* dockTileData =
|
||||
[NSDictionary dictionaryWithObject:dict forKey:kDockFileDataKey];
|
||||
if (dockTileData) {
|
||||
newDockTile = [NSDictionary dictionaryWithObject:dockTileData forKey:kDockTileDataKey];
|
||||
newDockTile = [NSDictionary dictionaryWithObject:dockTileData
|
||||
forKey:kDockTileDataKey];
|
||||
}
|
||||
if (!newDockTile) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -397,7 +413,8 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
|
|||
|
||||
// Update the Dock:
|
||||
if (toReplaceAppIndex != NSNotFound) {
|
||||
[persistentApps replaceObjectAtIndex:toReplaceAppIndex withObject:newDockTile];
|
||||
[persistentApps replaceObjectAtIndex:toReplaceAppIndex
|
||||
withObject:newDockTile];
|
||||
} else {
|
||||
NSUInteger index;
|
||||
if (sameNameAppIndex != NSNotFound) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset:
|
||||
* 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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
|
||||
|
@ -24,16 +25,19 @@ nsMacFinderProgress::~nsMacFinderProgress() {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacFinderProgress::Init(const nsAString& path,
|
||||
nsIMacFinderProgressCanceledCallback* cancellationCallback) {
|
||||
nsMacFinderProgress::Init(
|
||||
const nsAString& path,
|
||||
nsIMacFinderProgressCanceledCallback* cancellationCallback) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSURL* pathUrl = [NSURL
|
||||
fileURLWithPath:[NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(path.BeginReading())
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
path.BeginReading())
|
||||
length:path.Length()]];
|
||||
NSDictionary* userInfo = @{
|
||||
@"NSProgressFileOperationKindKey" : @"NSProgressFileOperationKindDownloading",
|
||||
@"NSProgressFileOperationKindKey" :
|
||||
@"NSProgressFileOperationKindDownloading",
|
||||
@"NSProgressFileURLKey" : pathUrl
|
||||
};
|
||||
|
||||
|
@ -41,13 +45,14 @@ nsMacFinderProgress::Init(const nsAString& path,
|
|||
mProgress.kind = NSProgressKindFile;
|
||||
mProgress.cancellable = YES;
|
||||
|
||||
nsMainThreadPtrHandle<nsIMacFinderProgressCanceledCallback> cancellationCallbackHandle(
|
||||
new nsMainThreadPtrHolder<nsIMacFinderProgressCanceledCallback>(
|
||||
"MacFinderProgress::CancellationCallback", cancellationCallback));
|
||||
nsMainThreadPtrHandle<nsIMacFinderProgressCanceledCallback>
|
||||
cancellationCallbackHandle(
|
||||
new nsMainThreadPtrHolder<nsIMacFinderProgressCanceledCallback>(
|
||||
"MacFinderProgress::CancellationCallback", cancellationCallback));
|
||||
|
||||
mProgress.cancellationHandler = ^{
|
||||
NS_DispatchToMainThread(
|
||||
NS_NewRunnableFunction("MacFinderProgress::Canceled", [cancellationCallbackHandle] {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"MacFinderProgress::Canceled", [cancellationCallbackHandle] {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
cancellationCallbackHandle->Canceled();
|
||||
}));
|
||||
|
@ -61,7 +66,8 @@ nsMacFinderProgress::Init(const nsAString& path,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacFinderProgress::UpdateProgress(uint64_t currentProgress, uint64_t totalProgress) {
|
||||
nsMacFinderProgress::UpdateProgress(uint64_t currentProgress,
|
||||
uint64_t totalProgress) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
if (mProgress) {
|
||||
mProgress.totalUnitCount = totalProgress;
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
|
||||
NS_IMPL_ISUPPORTS(nsMacSharingService, nsIMacSharingService)
|
||||
|
||||
NSString* const remindersServiceName = @"com.apple.reminders.RemindersShareExtension";
|
||||
NSString* const remindersServiceName =
|
||||
@"com.apple.reminders.RemindersShareExtension";
|
||||
|
||||
// These are some undocumented constants also used by Safari
|
||||
// to let us open the preferences window
|
||||
NSString* const extensionPrefPanePath = @"/System/Library/PreferencePanes/Extensions.prefPane";
|
||||
NSString* const extensionPrefPanePath =
|
||||
@"/System/Library/PreferencePanes/Extensions.prefPane";
|
||||
const UInt32 openSharingSubpaneDescriptorType = 'ptru';
|
||||
NSString* const openSharingSubpaneActionKey = @"action";
|
||||
NSString* const openSharingSubpaneActionValue = @"revealExtensionPoint";
|
||||
|
@ -31,10 +33,11 @@ NSString* const openSharingSubpaneProtocolValue = @"com.apple.share-services";
|
|||
- (id)name;
|
||||
@end
|
||||
|
||||
// Filter providers that we do not want to expose to the user, because they are duplicates or do not
|
||||
// work correctly within the context
|
||||
// Filter providers that we do not want to expose to the user, because they are
|
||||
// duplicates or do not work correctly within the context
|
||||
static bool ShouldIgnoreProvider(NSString* aProviderName) {
|
||||
return [aProviderName isEqualToString:@"com.apple.share.System.add-to-safari-reading-list"];
|
||||
return [aProviderName
|
||||
isEqualToString:@"com.apple.share.System.add-to-safari-reading-list"];
|
||||
}
|
||||
|
||||
// Clean up the activity once the share is complete
|
||||
|
@ -61,7 +64,8 @@ static bool ShouldIgnoreProvider(NSString* aProviderName) {
|
|||
mShareActivity = nil;
|
||||
}
|
||||
|
||||
- (void)sharingService:(NSSharingService*)sharingService didShareItems:(NSArray*)items {
|
||||
- (void)sharingService:(NSSharingService*)sharingService
|
||||
didShareItems:(NSArray*)items {
|
||||
[self cleanup];
|
||||
}
|
||||
|
||||
|
@ -80,16 +84,18 @@ static bool ShouldIgnoreProvider(NSString* aProviderName) {
|
|||
|
||||
static NSString* NSImageToBase64(const NSImage* aImage) {
|
||||
CGImageRef cgRef = [aImage CGImageForProposedRect:nil context:nil hints:nil];
|
||||
NSBitmapImageRep* bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:cgRef];
|
||||
NSBitmapImageRep* bitmapRep =
|
||||
[[NSBitmapImageRep alloc] initWithCGImage:cgRef];
|
||||
[bitmapRep setSize:[aImage size]];
|
||||
NSData* imageData = [bitmapRep representationUsingType:NSPNGFileType properties:@{}];
|
||||
NSData* imageData = [bitmapRep representationUsingType:NSPNGFileType
|
||||
properties:@{}];
|
||||
NSString* base64Encoded = [imageData base64EncodedStringWithOptions:0];
|
||||
[bitmapRep release];
|
||||
return [NSString stringWithFormat:@"data:image/png;base64,%@", base64Encoded];
|
||||
}
|
||||
|
||||
static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj, const char* aKey,
|
||||
NSString* aVal) {
|
||||
static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj,
|
||||
const char* aKey, NSString* aVal) {
|
||||
nsAutoString strVal;
|
||||
mozilla::CopyCocoaStringToXPCOMString(aVal, strVal);
|
||||
JS::Rooted<JSString*> title(aCx, JS_NewUCStringCopyZ(aCx, strVal.get()));
|
||||
|
@ -97,8 +103,9 @@ static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj, const c
|
|||
JS_SetProperty(aCx, aObj, aKey, attVal);
|
||||
}
|
||||
|
||||
nsresult nsMacSharingService::GetSharingProviders(const nsAString& aPageUrl, JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aResult) {
|
||||
nsresult nsMacSharingService::GetSharingProviders(
|
||||
const nsAString& aPageUrl, JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aResult) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSURL* url = nsCocoaUtils::ToNSURL(aPageUrl);
|
||||
|
@ -135,18 +142,20 @@ NS_IMETHODIMP
|
|||
nsMacSharingService::OpenSharingPreferences() {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSURL* prefPaneURL = [NSURL fileURLWithPath:extensionPrefPanePath isDirectory:YES];
|
||||
NSURL* prefPaneURL = [NSURL fileURLWithPath:extensionPrefPanePath
|
||||
isDirectory:YES];
|
||||
NSDictionary* args = @{
|
||||
openSharingSubpaneActionKey : openSharingSubpaneActionValue,
|
||||
openSharingSubpaneProtocolKey : openSharingSubpaneProtocolValue
|
||||
};
|
||||
NSData* data = [NSPropertyListSerialization dataWithPropertyList:args
|
||||
format:NSPropertyListXMLFormat_v1_0
|
||||
options:0
|
||||
error:nil];
|
||||
NSAppleEventDescriptor* descriptor =
|
||||
[[NSAppleEventDescriptor alloc] initWithDescriptorType:openSharingSubpaneDescriptorType
|
||||
data:data];
|
||||
NSData* data = [NSPropertyListSerialization
|
||||
dataWithPropertyList:args
|
||||
format:NSPropertyListXMLFormat_v1_0
|
||||
options:0
|
||||
error:nil];
|
||||
NSAppleEventDescriptor* descriptor = [[NSAppleEventDescriptor alloc]
|
||||
initWithDescriptorType:openSharingSubpaneDescriptorType
|
||||
data:data];
|
||||
|
||||
[[NSWorkspace sharedWorkspace] openURLs:@[ prefPaneURL ]
|
||||
withAppBundleIdentifier:nil
|
||||
|
@ -161,19 +170,21 @@ nsMacSharingService::OpenSharingPreferences() {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacSharingService::ShareUrl(const nsAString& aServiceName, const nsAString& aPageUrl,
|
||||
nsMacSharingService::ShareUrl(const nsAString& aServiceName,
|
||||
const nsAString& aPageUrl,
|
||||
const nsAString& aPageTitle) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSString* serviceName = nsCocoaUtils::ToNSString(aServiceName);
|
||||
NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl);
|
||||
NSString* pageTitle = nsCocoaUtils::ToNSString(aPageTitle);
|
||||
NSSharingService* service = [NSSharingService sharingServiceNamed:serviceName];
|
||||
NSSharingService* service =
|
||||
[NSSharingService sharingServiceNamed:serviceName];
|
||||
|
||||
// Reminders fetch its data from an activity, not the share data
|
||||
if ([[service name] isEqual:remindersServiceName]) {
|
||||
NSUserActivity* shareActivity =
|
||||
[[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
||||
NSUserActivity* shareActivity = [[NSUserActivity alloc]
|
||||
initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
||||
|
||||
if ([pageUrl.scheme hasPrefix:@"http"]) {
|
||||
[shareActivity setWebpageURL:pageUrl];
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
NS_IMPL_ISUPPORTS(nsMacUserActivityUpdater, nsIMacUserActivityUpdater)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAString& aPageTitle,
|
||||
nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl,
|
||||
const nsAString& aPageTitle,
|
||||
nsIBaseWindow* aWindow) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
if (gfxPlatform::IsHeadless()) {
|
||||
|
@ -27,8 +28,8 @@ nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAStr
|
|||
}
|
||||
|
||||
NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl);
|
||||
if (!pageUrl ||
|
||||
(![pageUrl.scheme isEqualToString:@"https"] && ![pageUrl.scheme isEqualToString:@"http"])) {
|
||||
if (!pageUrl || (![pageUrl.scheme isEqualToString:@"https"] &&
|
||||
![pageUrl.scheme isEqualToString:@"http"])) {
|
||||
[cocoaWin.userActivity invalidate];
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -38,8 +39,8 @@ nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAStr
|
|||
pageTitle = pageUrl.absoluteString;
|
||||
}
|
||||
|
||||
NSUserActivity* userActivity =
|
||||
[[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
||||
NSUserActivity* userActivity = [[NSUserActivity alloc]
|
||||
initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
||||
userActivity.webpageURL = pageUrl;
|
||||
userActivity.title = pageTitle;
|
||||
cocoaWin.userActivity = userActivity;
|
||||
|
|
|
@ -13,25 +13,28 @@
|
|||
#include "nsObjCExceptions.h"
|
||||
|
||||
// Find the path to the app with the given bundleIdentifier, if any.
|
||||
// Note that the OS will return the path to the newest binary, if there is more than one.
|
||||
// The determination of 'newest' is complex and beyond the scope of this comment.
|
||||
// Note that the OS will return the path to the newest binary, if there is more
|
||||
// than one. The determination of 'newest' is complex and beyond the scope of
|
||||
// this comment.
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMacWebAppUtils, nsIMacWebAppUtils)
|
||||
|
||||
NS_IMETHODIMP nsMacWebAppUtils::PathForAppWithIdentifier(const nsAString& bundleIdentifier,
|
||||
nsAString& outPath) {
|
||||
NS_IMETHODIMP nsMacWebAppUtils::PathForAppWithIdentifier(
|
||||
const nsAString& bundleIdentifier, nsAString& outPath) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
outPath.Truncate();
|
||||
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
// note that the result of this expression might be nil, meaning no matching app was found.
|
||||
// note that the result of this expression might be nil, meaning no matching
|
||||
// app was found.
|
||||
NSString* temp = [[NSWorkspace sharedWorkspace]
|
||||
absolutePathForAppBundleWithIdentifier:
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
((nsString)bundleIdentifier).get())
|
||||
length:((nsString)bundleIdentifier).Length()]];
|
||||
[NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
((nsString)bundleIdentifier).get())
|
||||
length:((nsString)bundleIdentifier).Length()]];
|
||||
|
||||
if (temp) {
|
||||
// Copy out the resultant absolute path into outPath if non-nil.
|
||||
|
@ -43,18 +46,20 @@ NS_IMETHODIMP nsMacWebAppUtils::PathForAppWithIdentifier(const nsAString& bundle
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMacWebAppUtils::LaunchAppWithIdentifier(const nsAString& bundleIdentifier) {
|
||||
NS_IMETHODIMP nsMacWebAppUtils::LaunchAppWithIdentifier(
|
||||
const nsAString& bundleIdentifier) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
// Note this might return false, meaning the app wasnt launched for some reason.
|
||||
// Note this might return false, meaning the app wasnt launched for some
|
||||
// reason.
|
||||
BOOL success = [[NSWorkspace sharedWorkspace]
|
||||
launchAppWithBundleIdentifier:[NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
((nsString)bundleIdentifier)
|
||||
.get())
|
||||
length:((nsString)bundleIdentifier).Length()]
|
||||
launchAppWithBundleIdentifier:
|
||||
[NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
((nsString)bundleIdentifier).get())
|
||||
length:((nsString)bundleIdentifier).Length()]
|
||||
options:(NSWorkspaceLaunchOptions)0
|
||||
additionalEventParamDescriptor:nil
|
||||
launchIdentifier:NULL];
|
||||
|
@ -64,7 +69,8 @@ NS_IMETHODIMP nsMacWebAppUtils::LaunchAppWithIdentifier(const nsAString& bundleI
|
|||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMacWebAppUtils::TrashApp(const nsAString& path, nsITrashAppCallback* aCallback) {
|
||||
NS_IMETHODIMP nsMacWebAppUtils::TrashApp(const nsAString& path,
|
||||
nsITrashAppCallback* aCallback) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
if (NS_WARN_IF(!aCallback)) {
|
||||
|
@ -74,11 +80,13 @@ NS_IMETHODIMP nsMacWebAppUtils::TrashApp(const nsAString& path, nsITrashAppCallb
|
|||
nsCOMPtr<nsITrashAppCallback> callback = aCallback;
|
||||
|
||||
NSString* tempString =
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(((nsString)path).get())
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
((nsString)path).get())
|
||||
length:path.Length()];
|
||||
|
||||
[[NSWorkspace sharedWorkspace]
|
||||
recycleURLs:[NSArray arrayWithObject:[NSURL fileURLWithPath:tempString]]
|
||||
recycleURLs:[NSArray
|
||||
arrayWithObject:[NSURL fileURLWithPath:tempString]]
|
||||
completionHandler:^(NSDictionary* newURLs, NSError* error) {
|
||||
nsresult rv = (error == nil) ? NS_OK : NS_ERROR_FAILURE;
|
||||
callback->TrashAppFinished(rv);
|
||||
|
|
|
@ -41,10 +41,11 @@ BOOL gSomeMenuBarPainted = NO;
|
|||
// defined in nsCocoaWindow.mm.
|
||||
extern BOOL sTouchBarIsInitialized;
|
||||
|
||||
// We keep references to the first quit and pref item content nodes we find, which
|
||||
// will be from the hidden window. We use these when the document for the current
|
||||
// window does not have a quit or pref item. We don't need strong refs here because
|
||||
// these items are always strong ref'd by their owning menu bar (instance variable).
|
||||
// We keep references to the first quit and pref item content nodes we find,
|
||||
// which will be from the hidden window. We use these when the document for the
|
||||
// current window does not have a quit or pref item. We don't need strong refs
|
||||
// here because these items are always strong ref'd by their owning menu bar
|
||||
// (instance variable).
|
||||
static nsIContent* sAboutItemContent = nullptr;
|
||||
static nsIContent* sPrefItemContent = nullptr;
|
||||
static nsIContent* sAccountItemContent = nullptr;
|
||||
|
@ -140,8 +141,9 @@ void nsMenuBarX::ConstructNativeMenus() {
|
|||
for (nsIContent* menuContent = mContent->GetFirstChild(); menuContent;
|
||||
menuContent = menuContent->GetNextSibling()) {
|
||||
if (menuContent->IsXULElement(nsGkAtoms::menu)) {
|
||||
InsertMenuAtIndex(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, menuContent->AsElement()),
|
||||
GetMenuCount());
|
||||
InsertMenuAtIndex(
|
||||
MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, menuContent->AsElement()),
|
||||
GetMenuCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +158,8 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
|
|||
|
||||
nsCOMPtr<nsIStringBundle> stringBundle;
|
||||
|
||||
nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
nsCOMPtr<nsIStringBundleService> bundleSvc =
|
||||
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
bundleSvc->CreateBundle("chrome://global/locale/fallbackMenubar.properties",
|
||||
getter_AddRefs(stringBundle));
|
||||
|
||||
|
@ -173,8 +176,10 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
|
|||
stringBundle->GetStringFromName(labelProp, labelUTF16);
|
||||
stringBundle->GetStringFromName(keyProp, keyUTF16);
|
||||
|
||||
NSString* labelStr = [NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(labelUTF16).get()];
|
||||
NSString* keyStr = [NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(keyUTF16).get()];
|
||||
NSString* labelStr =
|
||||
[NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(labelUTF16).get()];
|
||||
NSString* keyStr =
|
||||
[NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(keyUTF16).get()];
|
||||
|
||||
if (!nsMenuBarX::sNativeEventTarget) {
|
||||
nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init];
|
||||
|
@ -182,12 +187,14 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
|
|||
|
||||
sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain];
|
||||
if (!mApplicationMenuDelegate) {
|
||||
mApplicationMenuDelegate = [[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
|
||||
mApplicationMenuDelegate =
|
||||
[[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
|
||||
}
|
||||
sApplicationMenu.delegate = mApplicationMenuDelegate;
|
||||
NSMenuItem* quitMenuItem = [[[NSMenuItem alloc] initWithTitle:labelStr
|
||||
action:@selector(menuItemHit:)
|
||||
keyEquivalent:keyStr] autorelease];
|
||||
NSMenuItem* quitMenuItem =
|
||||
[[[NSMenuItem alloc] initWithTitle:labelStr
|
||||
action:@selector(menuItemHit:)
|
||||
keyEquivalent:keyStr] autorelease];
|
||||
quitMenuItem.target = nsMenuBarX::sNativeEventTarget;
|
||||
quitMenuItem.tag = eCommand_ID_Quit;
|
||||
[sApplicationMenu addItem:quitMenuItem];
|
||||
|
@ -201,7 +208,8 @@ uint32_t nsMenuBarX::GetMenuCount() { return mMenuArray.Length(); }
|
|||
bool nsMenuBarX::MenuContainsAppMenu() {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
return (mNativeMenu.numberOfItems > 0 && [mNativeMenu itemAtIndex:0].submenu == sApplicationMenu);
|
||||
return (mNativeMenu.numberOfItems > 0 &&
|
||||
[mNativeMenu itemAtIndex:0].submenu == sApplicationMenu);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
@ -220,8 +228,9 @@ void nsMenuBarX::InsertMenuAtIndex(RefPtr<nsMenuX>&& aMenu, uint32_t aIndex) {
|
|||
|
||||
// Hook the new Application menu up to the menu bar.
|
||||
NSMenu* mainMenu = NSApp.mainMenu;
|
||||
NS_ASSERTION(mainMenu.numberOfItems > 0,
|
||||
"Main menu does not have any items, something is terribly wrong!");
|
||||
NS_ASSERTION(
|
||||
mainMenu.numberOfItems > 0,
|
||||
"Main menu does not have any items, something is terribly wrong!");
|
||||
[mainMenu itemAtIndex:0].submenu = sApplicationMenu;
|
||||
}
|
||||
|
||||
|
@ -230,7 +239,8 @@ void nsMenuBarX::InsertMenuAtIndex(RefPtr<nsMenuX>&& aMenu, uint32_t aIndex) {
|
|||
|
||||
// hook up submenus
|
||||
RefPtr<nsIContent> menuContent = aMenu->Content();
|
||||
if (menuContent->GetChildCount() > 0 && !nsMenuUtilsX::NodeIsHiddenOrCollapsed(menuContent)) {
|
||||
if (menuContent->GetChildCount() > 0 &&
|
||||
!nsMenuUtilsX::NodeIsHiddenOrCollapsed(menuContent)) {
|
||||
MenuChildChangedVisibility(MenuChild(aMenu), true);
|
||||
}
|
||||
|
||||
|
@ -263,11 +273,14 @@ void nsMenuBarX::RemoveMenuAtIndex(uint32_t aIndex) {
|
|||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
void nsMenuBarX::ObserveAttributeChanged(mozilla::dom::Document* aDocument, nsIContent* aContent,
|
||||
void nsMenuBarX::ObserveAttributeChanged(mozilla::dom::Document* aDocument,
|
||||
nsIContent* aContent,
|
||||
nsAtom* aAttribute) {}
|
||||
|
||||
void nsMenuBarX::ObserveContentRemoved(mozilla::dom::Document* aDocument, nsIContent* aContainer,
|
||||
nsIContent* aChild, nsIContent* aPreviousSibling) {
|
||||
void nsMenuBarX::ObserveContentRemoved(mozilla::dom::Document* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
nsIContent* aPreviousSibling) {
|
||||
nsINode* parent = NODE_FROM(aContainer, aDocument);
|
||||
MOZ_ASSERT(parent);
|
||||
const Maybe<uint32_t> index = parent->ComputeIndexOf(aPreviousSibling);
|
||||
|
@ -275,7 +288,8 @@ void nsMenuBarX::ObserveContentRemoved(mozilla::dom::Document* aDocument, nsICon
|
|||
RemoveMenuAtIndex(index.isSome() ? *index + 1u : 0u);
|
||||
}
|
||||
|
||||
void nsMenuBarX::ObserveContentInserted(mozilla::dom::Document* aDocument, nsIContent* aContainer,
|
||||
void nsMenuBarX::ObserveContentInserted(mozilla::dom::Document* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild) {
|
||||
InsertMenuAtIndex(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aChild),
|
||||
aContainer->ComputeIndexOf(aChild).valueOr(UINT32_MAX));
|
||||
|
@ -285,7 +299,8 @@ void nsMenuBarX::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
|
|||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
NSString* locationString =
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading())
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||
aIndexString.BeginReading())
|
||||
length:aIndexString.Length()];
|
||||
NSArray* indexes = [locationString componentsSeparatedByString:@"|"];
|
||||
unsigned int indexCount = indexes.count;
|
||||
|
@ -329,7 +344,9 @@ void nsMenuBarX::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
|
|||
}
|
||||
RefPtr<nsIContent> content = targetMenu->match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->Content();
|
||||
});
|
||||
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
|
||||
visible++;
|
||||
if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) {
|
||||
|
@ -408,8 +425,9 @@ nsresult nsMenuBarX::Paint() {
|
|||
// We have to keep the same menu item for the Application menu so we keep
|
||||
// passing it along.
|
||||
NSMenu* outgoingMenu = NSApp.mainMenu;
|
||||
NS_ASSERTION(outgoingMenu.numberOfItems > 0,
|
||||
"Main menu does not have any items, something is terribly wrong!");
|
||||
NS_ASSERTION(
|
||||
outgoingMenu.numberOfItems > 0,
|
||||
"Main menu does not have any items, something is terribly wrong!");
|
||||
|
||||
NSMenuItem* appMenuItem = [[outgoingMenu itemAtIndex:0] retain];
|
||||
[outgoingMenu removeItemAtIndex:0];
|
||||
|
@ -456,8 +474,10 @@ bool nsMenuBarX::PerformKeyEquivalent(NSEvent* aEvent) {
|
|||
return [mNativeMenu performSuperKeyEquivalent:aEvent];
|
||||
}
|
||||
|
||||
void nsMenuBarX::MenuChildChangedVisibility(const MenuChild& aChild, bool aIsVisible) {
|
||||
MOZ_RELEASE_ASSERT(aChild.is<RefPtr<nsMenuX>>(), "nsMenuBarX only has nsMenuX children");
|
||||
void nsMenuBarX::MenuChildChangedVisibility(const MenuChild& aChild,
|
||||
bool aIsVisible) {
|
||||
MOZ_RELEASE_ASSERT(aChild.is<RefPtr<nsMenuX>>(),
|
||||
"nsMenuBarX only has nsMenuX children");
|
||||
const RefPtr<nsMenuX>& child = aChild.as<RefPtr<nsMenuX>>();
|
||||
NSMenuItem* item = child->NativeNSMenuItem();
|
||||
if (aIsVisible) {
|
||||
|
@ -475,8 +495,9 @@ NSInteger nsMenuBarX::CalculateNativeInsertionPoint(nsMenuX* aChild) {
|
|||
return insertionPoint;
|
||||
}
|
||||
// Only count items that are inside a menu.
|
||||
// XXXmstange Not sure what would cause free-standing items. Maybe for collapsed/hidden menus?
|
||||
// In that case, an nsMenuX::IsVisible() method would be better.
|
||||
// XXXmstange Not sure what would cause free-standing items. Maybe for
|
||||
// collapsed/hidden menus? In that case, an nsMenuX::IsVisible() method
|
||||
// would be better.
|
||||
if (currMenu->NativeNSMenuItem().menu) {
|
||||
insertionPoint++;
|
||||
}
|
||||
|
@ -486,10 +507,12 @@ NSInteger nsMenuBarX::CalculateNativeInsertionPoint(nsMenuX* aChild) {
|
|||
|
||||
// Hide the item in the menu by setting the 'hidden' attribute. Returns it so
|
||||
// the caller can hang onto it if they so choose.
|
||||
RefPtr<Element> nsMenuBarX::HideItem(mozilla::dom::Document* aDocument, const nsAString& aID) {
|
||||
RefPtr<Element> nsMenuBarX::HideItem(mozilla::dom::Document* aDocument,
|
||||
const nsAString& aID) {
|
||||
RefPtr<Element> menuElement = aDocument->GetElementById(aID);
|
||||
if (menuElement) {
|
||||
menuElement->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, u"true"_ns, false);
|
||||
menuElement->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, u"true"_ns,
|
||||
false);
|
||||
}
|
||||
return menuElement;
|
||||
}
|
||||
|
@ -536,7 +559,8 @@ void nsMenuBarX::AquifyMenuBar() {
|
|||
}
|
||||
|
||||
// for creating menu items destined for the Application menu
|
||||
NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString& aNodeID,
|
||||
NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu,
|
||||
const nsAString& aNodeID,
|
||||
SEL aAction, int aTag,
|
||||
NativeMenuItemTarget* aTarget) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
@ -553,8 +577,8 @@ NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString&
|
|||
|
||||
// Check collapsed rather than hidden since the app menu items are always
|
||||
// hidden in AquifyMenuBar.
|
||||
if (menuItem->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed, nsGkAtoms::_true,
|
||||
eCaseMatters)) {
|
||||
if (menuItem->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed,
|
||||
nsGkAtoms::_true, eCaseMatters)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
@ -577,20 +601,23 @@ NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString&
|
|||
nsAutoString keyChar(u" "_ns);
|
||||
keyElement->GetAttr(nsGkAtoms::key, keyChar);
|
||||
if (!keyChar.EqualsLiteral(" ")) {
|
||||
keyEquiv = [[NSString stringWithCharacters:reinterpret_cast<const unichar*>(keyChar.get())
|
||||
length:keyChar.Length()] lowercaseString];
|
||||
keyEquiv = [[NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(keyChar.get())
|
||||
length:keyChar.Length()] lowercaseString];
|
||||
}
|
||||
// now grab the key equivalent modifiers
|
||||
nsAutoString modifiersStr;
|
||||
keyElement->GetAttr(nsGkAtoms::modifiers, modifiersStr);
|
||||
uint8_t geckoModifiers = nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr);
|
||||
macKeyModifiers = nsMenuUtilsX::MacModifiersForGeckoModifiers(geckoModifiers);
|
||||
uint8_t geckoModifiers =
|
||||
nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr);
|
||||
macKeyModifiers =
|
||||
nsMenuUtilsX::MacModifiersForGeckoModifiers(geckoModifiers);
|
||||
}
|
||||
}
|
||||
// get the label into NSString-form
|
||||
NSString* labelString =
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(label.get())
|
||||
length:label.Length()];
|
||||
NSString* labelString = [NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(label.get())
|
||||
length:label.Length()];
|
||||
|
||||
if (!labelString) {
|
||||
labelString = @"";
|
||||
|
@ -634,7 +661,8 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
= Preferences... = <- menu_preferences
|
||||
= Account Settings = <- menu_accountmgr Only on Thunderbird
|
||||
========================
|
||||
= Services > = <- menu_mac_services <- (do not define key equivalent)
|
||||
= Services > = <- menu_mac_services <- (do not define key
|
||||
equivalent)
|
||||
========================
|
||||
= Hide App = <- menu_mac_hide_app
|
||||
= Hide Others = <- menu_mac_hide_others
|
||||
|
@ -646,34 +674,37 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
========================
|
||||
|
||||
If any of them are ommitted from the application's DOM, we just don't add
|
||||
them. We always add a "Quit" item, but if an app developer does not provide a
|
||||
DOM node with the right ID for the Quit item, we add it in English. App
|
||||
developers need only add each node with a label and a key equivalent (if they
|
||||
want one). Other attributes are optional. Like so:
|
||||
them. We always add a "Quit" item, but if an app developer does not provide
|
||||
a DOM node with the right ID for the Quit item, we add it in English. App
|
||||
developers need only add each node with a label and a key equivalent (if
|
||||
they want one). Other attributes are optional. Like so:
|
||||
|
||||
<menuitem id="menu_preferences"
|
||||
label="&preferencesCmdMac.label;"
|
||||
key="open_prefs_key"/>
|
||||
|
||||
We need to use this system for localization purposes, until we have a better way
|
||||
to define the Application menu to be used on Mac OS X.
|
||||
We need to use this system for localization purposes, until we have a better
|
||||
way to define the Application menu to be used on Mac OS X.
|
||||
*/
|
||||
|
||||
if (sApplicationMenu) {
|
||||
if (!mApplicationMenuDelegate) {
|
||||
mApplicationMenuDelegate = [[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
|
||||
mApplicationMenuDelegate =
|
||||
[[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
|
||||
}
|
||||
sApplicationMenu.delegate = mApplicationMenuDelegate;
|
||||
|
||||
// This code reads attributes we are going to care about from the DOM elements
|
||||
// This code reads attributes we are going to care about from the DOM
|
||||
// elements
|
||||
|
||||
NSMenuItem* itemBeingAdded = nil;
|
||||
BOOL addAboutSeparator = FALSE;
|
||||
BOOL addPrefsSeparator = FALSE;
|
||||
|
||||
// Add the About menu item
|
||||
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"aboutName"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_About, nsMenuBarX::sNativeEventTarget);
|
||||
itemBeingAdded = CreateNativeAppMenuItem(
|
||||
aMenu, u"aboutName"_ns, @selector(menuItemHit:), eCommand_ID_About,
|
||||
nsMenuBarX::sNativeEventTarget);
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
[itemBeingAdded release];
|
||||
|
@ -688,8 +719,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
}
|
||||
|
||||
// Add the Preferences menu item
|
||||
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"menu_preferences"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_Prefs, nsMenuBarX::sNativeEventTarget);
|
||||
itemBeingAdded = CreateNativeAppMenuItem(
|
||||
aMenu, u"menu_preferences"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_Prefs, nsMenuBarX::sNativeEventTarget);
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
[itemBeingAdded release];
|
||||
|
@ -699,8 +731,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
}
|
||||
|
||||
// Add the Account Settings menu item. This is Thunderbird only
|
||||
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"menu_accountmgr"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_Account, nsMenuBarX::sNativeEventTarget);
|
||||
itemBeingAdded = CreateNativeAppMenuItem(
|
||||
aMenu, u"menu_accountmgr"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_Account, nsMenuBarX::sNativeEventTarget);
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
[itemBeingAdded release];
|
||||
|
@ -713,7 +746,8 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
}
|
||||
|
||||
// Add Services menu item
|
||||
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"menu_mac_services"_ns, nil, 0, nil);
|
||||
itemBeingAdded =
|
||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_services"_ns, nil, 0, nil);
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
|
||||
|
@ -732,9 +766,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
BOOL addHideShowSeparator = FALSE;
|
||||
|
||||
// Add menu item to hide this application
|
||||
itemBeingAdded =
|
||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_hide_app"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_HideApp, nsMenuBarX::sNativeEventTarget);
|
||||
itemBeingAdded = CreateNativeAppMenuItem(
|
||||
aMenu, u"menu_mac_hide_app"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_HideApp, nsMenuBarX::sNativeEventTarget);
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
[itemBeingAdded release];
|
||||
|
@ -744,9 +778,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
}
|
||||
|
||||
// Add menu item to hide other applications
|
||||
itemBeingAdded =
|
||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_hide_others"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_HideOthers, nsMenuBarX::sNativeEventTarget);
|
||||
itemBeingAdded = CreateNativeAppMenuItem(
|
||||
aMenu, u"menu_mac_hide_others"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_HideOthers, nsMenuBarX::sNativeEventTarget);
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
[itemBeingAdded release];
|
||||
|
@ -756,9 +790,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
}
|
||||
|
||||
// Add menu item to show all applications
|
||||
itemBeingAdded =
|
||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_show_all"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_ShowAll, nsMenuBarX::sNativeEventTarget);
|
||||
itemBeingAdded = CreateNativeAppMenuItem(
|
||||
aMenu, u"menu_mac_show_all"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_ShowAll, nsMenuBarX::sNativeEventTarget);
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
[itemBeingAdded release];
|
||||
|
@ -775,9 +809,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
BOOL addTouchBarSeparator = NO;
|
||||
|
||||
// Add Touch Bar customization menu item.
|
||||
itemBeingAdded =
|
||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_touch_bar"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_TouchBar, nsMenuBarX::sNativeEventTarget);
|
||||
itemBeingAdded = CreateNativeAppMenuItem(
|
||||
aMenu, u"menu_mac_touch_bar"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_TouchBar, nsMenuBarX::sNativeEventTarget);
|
||||
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
|
@ -797,9 +831,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
}
|
||||
|
||||
// Add quit menu item
|
||||
itemBeingAdded =
|
||||
CreateNativeAppMenuItem(aMenu, u"menu_FileQuitItem"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_Quit, nsMenuBarX::sNativeEventTarget);
|
||||
itemBeingAdded = CreateNativeAppMenuItem(
|
||||
aMenu, u"menu_FileQuitItem"_ns, @selector(menuItemHit:),
|
||||
eCommand_ID_Quit, nsMenuBarX::sNativeEventTarget);
|
||||
if (itemBeingAdded) {
|
||||
[sApplicationMenu addItem:itemBeingAdded];
|
||||
[itemBeingAdded release];
|
||||
|
@ -807,9 +841,10 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
|||
} else {
|
||||
// the current application does not have a DOM node for "Quit". Add one
|
||||
// anyway, in English.
|
||||
NSMenuItem* defaultQuitItem = [[[NSMenuItem alloc] initWithTitle:@"Quit"
|
||||
action:@selector(menuItemHit:)
|
||||
keyEquivalent:@"q"] autorelease];
|
||||
NSMenuItem* defaultQuitItem =
|
||||
[[[NSMenuItem alloc] initWithTitle:@"Quit"
|
||||
action:@selector(menuItemHit:)
|
||||
keyEquivalent:@"q"] autorelease];
|
||||
defaultQuitItem.target = nsMenuBarX::sNativeEventTarget;
|
||||
defaultQuitItem.tag = eCommand_ID_Quit;
|
||||
[sApplicationMenu addItem:defaultQuitItem];
|
||||
|
@ -860,9 +895,9 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
|||
[super performKeyEquivalent:aEvent];
|
||||
gMenuItemsExecuteCommands = YES; // return to default
|
||||
|
||||
// Return YES if we invoked a command and there is now no key window or we changed
|
||||
// the first responder. In this case we do not want to propagate the event because
|
||||
// we don't want it handled again.
|
||||
// Return YES if we invoked a command and there is now no key window or we
|
||||
// changed the first responder. In this case we do not want to propagate the
|
||||
// event because we don't want it handled again.
|
||||
if (!NSApp.keyWindow || NSApp.keyWindow.firstResponder != firstResponder) {
|
||||
return YES;
|
||||
}
|
||||
|
@ -898,7 +933,8 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
|||
|
||||
nsMenuGroupOwnerX* menuGroupOwner = nullptr;
|
||||
nsMenuBarX* menuBar = nullptr;
|
||||
MOZMenuItemRepresentedObject* representedObject = nativeMenuItem.representedObject;
|
||||
MOZMenuItemRepresentedObject* representedObject =
|
||||
nativeMenuItem.representedObject;
|
||||
|
||||
if (representedObject) {
|
||||
menuGroupOwner = representedObject.menuGroupOwner;
|
||||
|
@ -914,13 +950,15 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
|||
[(MenuDelegate*)menu.delegate menu:menu willActivateItem:nativeMenuItem];
|
||||
}
|
||||
|
||||
// Get the modifier flags and button for this menu item activation. The menu system does not pass
|
||||
// an NSEvent to our action selector, but we can query the current NSEvent instead. The current
|
||||
// NSEvent can be a key event or a mouseup event, depending on how the menu item is activated.
|
||||
NSEventModifierFlags modifierFlags = NSApp.currentEvent ? NSApp.currentEvent.modifierFlags : 0;
|
||||
mozilla::MouseButton button = NSApp.currentEvent
|
||||
? nsCocoaUtils::ButtonForEvent(NSApp.currentEvent)
|
||||
: mozilla::MouseButton::ePrimary;
|
||||
// Get the modifier flags and button for this menu item activation. The menu
|
||||
// system does not pass an NSEvent to our action selector, but we can query
|
||||
// the current NSEvent instead. The current NSEvent can be a key event or a
|
||||
// mouseup event, depending on how the menu item is activated.
|
||||
NSEventModifierFlags modifierFlags =
|
||||
NSApp.currentEvent ? NSApp.currentEvent.modifierFlags : 0;
|
||||
mozilla::MouseButton button =
|
||||
NSApp.currentEvent ? nsCocoaUtils::ButtonForEvent(NSApp.currentEvent)
|
||||
: mozilla::MouseButton::ePrimary;
|
||||
|
||||
// Do special processing if this is for an app-global command.
|
||||
if (tag == eCommand_ID_About) {
|
||||
|
@ -968,13 +1006,15 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
|||
if (menuBar && menuBar->mQuitItemContent) {
|
||||
mostSpecificContent = menuBar->mQuitItemContent;
|
||||
}
|
||||
// If we have some content for quit we execute it. Otherwise we send a native app terminate
|
||||
// message. If you want to stop a quit from happening, provide quit content and return
|
||||
// the event as unhandled.
|
||||
// If we have some content for quit we execute it. Otherwise we send a
|
||||
// native app terminate message. If you want to stop a quit from happening,
|
||||
// provide quit content and return the event as unhandled.
|
||||
if (mostSpecificContent) {
|
||||
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags, button);
|
||||
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags,
|
||||
button);
|
||||
} else {
|
||||
nsCOMPtr<nsIAppStartup> appStartup = mozilla::components::AppStartup::Service();
|
||||
nsCOMPtr<nsIAppStartup> appStartup =
|
||||
mozilla::components::AppStartup::Service();
|
||||
if (appStartup) {
|
||||
bool userAllowedQuit = true;
|
||||
appStartup->Quit(nsIAppStartup::eAttemptQuit, 0, &userAllowedQuit);
|
||||
|
@ -986,12 +1026,13 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
|||
// given the commandID, look it up in our hashtable and dispatch to
|
||||
// that menu item.
|
||||
if (menuGroupOwner) {
|
||||
if (RefPtr<nsMenuItemX> menuItem =
|
||||
menuGroupOwner->GetMenuItemForCommandID(static_cast<uint32_t>(tag))) {
|
||||
if (RefPtr<nsMenuItemX> menuItem = menuGroupOwner->GetMenuItemForCommandID(
|
||||
static_cast<uint32_t>(tag))) {
|
||||
if (nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest) {
|
||||
menuItem->DoCommand(modifierFlags, button);
|
||||
} else if (RefPtr<nsMenuX> menu = menuItem->ParentMenu()) {
|
||||
menu->ActivateItemAfterClosing(std::move(menuItem), modifierFlags, button);
|
||||
menu->ActivateItemAfterClosing(std::move(menuItem), modifierFlags,
|
||||
button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1041,7 +1082,9 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
|||
- (NSMenuItem*)addItemWithTitle:(NSString*)aString
|
||||
action:(SEL)aSelector
|
||||
keyEquivalent:(NSString*)aKeyEquiv {
|
||||
NSMenuItem* newItem = [super addItemWithTitle:aString action:aSelector keyEquivalent:aKeyEquiv];
|
||||
NSMenuItem* newItem = [super addItemWithTitle:aString
|
||||
action:aSelector
|
||||
keyEquivalent:aKeyEquiv];
|
||||
[self _overrideClassOfMenuItem:newItem];
|
||||
return newItem;
|
||||
}
|
||||
|
|
|
@ -26,13 +26,16 @@ using namespace mozilla;
|
|||
|
||||
NS_IMPL_ISUPPORTS(nsMenuGroupOwnerX, nsIObserver, nsIMutationObserver)
|
||||
|
||||
nsMenuGroupOwnerX::nsMenuGroupOwnerX(mozilla::dom::Element* aElement, nsMenuBarX* aMenuBarIfMenuBar)
|
||||
nsMenuGroupOwnerX::nsMenuGroupOwnerX(mozilla::dom::Element* aElement,
|
||||
nsMenuBarX* aMenuBarIfMenuBar)
|
||||
: mContent(aElement), mMenuBar(aMenuBarIfMenuBar) {
|
||||
mRepresentedObject = [[MOZMenuItemRepresentedObject alloc] initWithMenuGroupOwner:this];
|
||||
mRepresentedObject =
|
||||
[[MOZMenuItemRepresentedObject alloc] initWithMenuGroupOwner:this];
|
||||
}
|
||||
|
||||
nsMenuGroupOwnerX::~nsMenuGroupOwnerX() {
|
||||
MOZ_ASSERT(mContentToObserverTable.Count() == 0, "have outstanding mutation observers!\n");
|
||||
MOZ_ASSERT(mContentToObserverTable.Count() == 0,
|
||||
"have outstanding mutation observers!\n");
|
||||
[mRepresentedObject setMenuGroupOwner:nullptr];
|
||||
[mRepresentedObject release];
|
||||
}
|
||||
|
@ -41,11 +44,11 @@ nsMenuGroupOwnerX::~nsMenuGroupOwnerX() {
|
|||
// nsIMutationObserver
|
||||
//
|
||||
|
||||
void nsMenuGroupOwnerX::CharacterDataWillChange(nsIContent* aContent,
|
||||
const CharacterDataChangeInfo&) {}
|
||||
void nsMenuGroupOwnerX::CharacterDataWillChange(
|
||||
nsIContent* aContent, const CharacterDataChangeInfo&) {}
|
||||
|
||||
void nsMenuGroupOwnerX::CharacterDataChanged(nsIContent* aContent, const CharacterDataChangeInfo&) {
|
||||
}
|
||||
void nsMenuGroupOwnerX::CharacterDataChanged(nsIContent* aContent,
|
||||
const CharacterDataChangeInfo&) {}
|
||||
|
||||
void nsMenuGroupOwnerX::ContentAppended(nsIContent* aFirstNewContent) {
|
||||
for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
|
||||
|
@ -55,10 +58,13 @@ void nsMenuGroupOwnerX::ContentAppended(nsIContent* aFirstNewContent) {
|
|||
|
||||
void nsMenuGroupOwnerX::NodeWillBeDestroyed(nsINode* aNode) {}
|
||||
|
||||
void nsMenuGroupOwnerX::AttributeWillChange(dom::Element* aElement, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute, int32_t aModType) {}
|
||||
void nsMenuGroupOwnerX::AttributeWillChange(dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute,
|
||||
int32_t aModType) {}
|
||||
|
||||
void nsMenuGroupOwnerX::AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
|
||||
void nsMenuGroupOwnerX::AttributeChanged(dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aOldValue) {
|
||||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
||||
|
@ -68,7 +74,8 @@ void nsMenuGroupOwnerX::AttributeChanged(dom::Element* aElement, int32_t aNameSp
|
|||
}
|
||||
}
|
||||
|
||||
void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling) {
|
||||
void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild,
|
||||
nsIContent* aPreviousSibling) {
|
||||
nsIContent* container = aChild->GetParent();
|
||||
if (!container) {
|
||||
return;
|
||||
|
@ -77,7 +84,8 @@ void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild, nsIContent* aPrevious
|
|||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
||||
nsChangeObserver* obs = LookupContentChangeObserver(container);
|
||||
if (obs) {
|
||||
obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild, aPreviousSibling);
|
||||
obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild,
|
||||
aPreviousSibling);
|
||||
} else if (container != mContent) {
|
||||
// We do a lookup on the parent container in case things were removed
|
||||
// under a "menupopup" item. That is basically a wrapper for the contents
|
||||
|
@ -86,7 +94,8 @@ void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild, nsIContent* aPrevious
|
|||
if (parent) {
|
||||
obs = LookupContentChangeObserver(parent);
|
||||
if (obs) {
|
||||
obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild, aPreviousSibling);
|
||||
obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild,
|
||||
aPreviousSibling);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,18 +127,18 @@ void nsMenuGroupOwnerX::ContentInserted(nsIContent* aChild) {
|
|||
|
||||
void nsMenuGroupOwnerX::ParentChainChanged(nsIContent* aContent) {}
|
||||
|
||||
void nsMenuGroupOwnerX::ARIAAttributeDefaultWillChange(mozilla::dom::Element* aElement,
|
||||
nsAtom* aAttribute, int32_t aModType) {}
|
||||
void nsMenuGroupOwnerX::ARIAAttributeDefaultWillChange(
|
||||
mozilla::dom::Element* aElement, nsAtom* aAttribute, int32_t aModType) {}
|
||||
|
||||
void nsMenuGroupOwnerX::ARIAAttributeDefaultChanged(mozilla::dom::Element* aElement,
|
||||
nsAtom* aAttribute, int32_t aModType) {}
|
||||
void nsMenuGroupOwnerX::ARIAAttributeDefaultChanged(
|
||||
mozilla::dom::Element* aElement, nsAtom* aAttribute, int32_t aModType) {}
|
||||
|
||||
// For change management, we don't use a |nsSupportsHashtable| because
|
||||
// we know that the lifetime of all these items is bounded by the
|
||||
// lifetime of the menubar. No need to add any more strong refs to the
|
||||
// picture because the containment hierarchy already uses strong refs.
|
||||
void nsMenuGroupOwnerX::RegisterForContentChanges(nsIContent* aContent,
|
||||
nsChangeObserver* aMenuObject) {
|
||||
void nsMenuGroupOwnerX::RegisterForContentChanges(
|
||||
nsIContent* aContent, nsChangeObserver* aMenuObject) {
|
||||
if (!mContentToObserverTable.Contains(aContent)) {
|
||||
aContent->AddMutationObserver(this);
|
||||
}
|
||||
|
@ -158,7 +167,8 @@ void nsMenuGroupOwnerX::UnregisterForLocaleChanges() {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMenuGroupOwnerX::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) {
|
||||
nsMenuGroupOwnerX::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData) {
|
||||
if (mMenuBar && !strcmp(aTopic, "intl:app-locales-changed")) {
|
||||
// Rebuild the menu with the new locale strings.
|
||||
mMenuBar->SetNeedsRebuild();
|
||||
|
@ -166,7 +176,8 @@ nsMenuGroupOwnerX::Observe(nsISupports* aSubject, const char* aTopic, const char
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsChangeObserver* nsMenuGroupOwnerX::LookupContentChangeObserver(nsIContent* aContent) {
|
||||
nsChangeObserver* nsMenuGroupOwnerX::LookupContentChangeObserver(
|
||||
nsIContent* aContent) {
|
||||
nsChangeObserver* result;
|
||||
if (mContentToObserverTable.Get(aContent, &result)) {
|
||||
return result;
|
||||
|
@ -206,7 +217,8 @@ nsMenuItemX* nsMenuGroupOwnerX::GetMenuItemForCommandID(uint32_t aCommandID) {
|
|||
}
|
||||
|
||||
@implementation MOZMenuItemRepresentedObject {
|
||||
nsMenuGroupOwnerX* mMenuGroupOwner; // weak, cleared by nsMenuGroupOwnerX's destructor
|
||||
nsMenuGroupOwnerX*
|
||||
mMenuGroupOwner; // weak, cleared by nsMenuGroupOwnerX's destructor
|
||||
}
|
||||
|
||||
- (id)initWithMenuGroupOwner:(nsMenuGroupOwnerX*)aMenuGroupOwner {
|
||||
|
|
|
@ -62,8 +62,8 @@ void nsMenuItemIconX::SetupIcon(nsIContent* aContent) {
|
|||
|
||||
bool shouldHaveIcon = StartIconLoad(aContent);
|
||||
if (!shouldHaveIcon) {
|
||||
// There is no icon for this menu item, as an error occurred while loading it.
|
||||
// An icon might have been set earlier or the place holder icon may have
|
||||
// There is no icon for this menu item, as an error occurred while loading
|
||||
// it. An icon might have been set earlier or the place holder icon may have
|
||||
// been set. Clear it.
|
||||
if (mIconImage) {
|
||||
[mIconImage release];
|
||||
|
@ -73,8 +73,9 @@ void nsMenuItemIconX::SetupIcon(nsIContent* aContent) {
|
|||
}
|
||||
|
||||
if (!mIconImage) {
|
||||
// Set a placeholder icon, so that the menuitem reserves space for the icon during the load and
|
||||
// there is no sudden shift once the icon finishes loading.
|
||||
// Set a placeholder icon, so that the menuitem reserves space for the icon
|
||||
// during the load and there is no sudden shift once the icon finishes
|
||||
// loading.
|
||||
NSSize iconSize = NSMakeSize(kIconSize, kIconSize);
|
||||
mIconImage = [[MOZIconHelper placeholderIconWithSize:iconSize] retain];
|
||||
}
|
||||
|
@ -100,7 +101,8 @@ already_AddRefed<nsIURI> nsMenuItemIconX::GetIconURI(nsIContent* aContent) {
|
|||
// First, look at the content node's "image" attribute.
|
||||
nsAutoString imageURIString;
|
||||
bool hasImageAttr =
|
||||
aContent->IsElement() && aContent->AsElement()->GetAttr(nsGkAtoms::image, imageURIString);
|
||||
aContent->IsElement() &&
|
||||
aContent->AsElement()->GetAttr(nsGkAtoms::image, imageURIString);
|
||||
|
||||
if (hasImageAttr) {
|
||||
// Use the URL from the image attribute.
|
||||
|
@ -121,7 +123,8 @@ already_AddRefed<nsIURI> nsMenuItemIconX::GetIconURI(nsIContent* aContent) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<const ComputedStyle> sc = nsComputedDOMStyle::GetComputedStyle(aContent->AsElement());
|
||||
RefPtr<const ComputedStyle> sc =
|
||||
nsComputedDOMStyle::GetComputedStyle(aContent->AsElement());
|
||||
if (!sc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -149,11 +152,12 @@ nsresult nsMenuItemIconX::OnComplete(imgIContainer* aImage) {
|
|||
mIconImage = nil;
|
||||
}
|
||||
RefPtr<nsPresContext> pc = mPresContext.get();
|
||||
mIconImage = [[MOZIconHelper iconImageFromImageContainer:aImage
|
||||
withSize:NSMakeSize(kIconSize, kIconSize)
|
||||
presContext:pc
|
||||
computedStyle:mComputedStyle
|
||||
scaleFactor:0.0f] retain];
|
||||
mIconImage = [[MOZIconHelper
|
||||
iconImageFromImageContainer:aImage
|
||||
withSize:NSMakeSize(kIconSize, kIconSize)
|
||||
presContext:pc
|
||||
computedStyle:mComputedStyle
|
||||
scaleFactor:0.0f] retain];
|
||||
mComputedStyle = nullptr;
|
||||
mPresContext = nullptr;
|
||||
|
||||
|
|
|
@ -26,14 +26,19 @@ using namespace mozilla;
|
|||
using mozilla::dom::CallerType;
|
||||
using mozilla::dom::Event;
|
||||
|
||||
nsMenuItemX::nsMenuItemX(nsMenuX* aParent, const nsString& aLabel, EMenuItemType aItemType,
|
||||
nsMenuItemX::nsMenuItemX(nsMenuX* aParent, const nsString& aLabel,
|
||||
EMenuItemType aItemType,
|
||||
nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aNode)
|
||||
: mContent(aNode), mType(aItemType), mMenuParent(aParent), mMenuGroupOwner(aMenuGroupOwner) {
|
||||
: mContent(aNode),
|
||||
mType(aItemType),
|
||||
mMenuParent(aParent),
|
||||
mMenuGroupOwner(aMenuGroupOwner) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
MOZ_COUNT_CTOR(nsMenuItemX);
|
||||
|
||||
MOZ_RELEASE_ASSERT(mContent->IsElement(), "nsMenuItemX should only be created for elements");
|
||||
MOZ_RELEASE_ASSERT(mContent->IsElement(),
|
||||
"nsMenuItemX should only be created for elements");
|
||||
NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one!");
|
||||
|
||||
mMenuGroupOwner->RegisterForContentChanges(mContent, this);
|
||||
|
@ -57,28 +62,29 @@ nsMenuItemX::nsMenuItemX(nsMenuX* aParent, const nsString& aLabel, EMenuItemType
|
|||
}
|
||||
}
|
||||
|
||||
// decide enabled state based on command content if it exists, otherwise do it based
|
||||
// on our own content
|
||||
// decide enabled state based on command content if it exists, otherwise do it
|
||||
// based on our own content
|
||||
bool isEnabled;
|
||||
if (mCommandElement) {
|
||||
isEnabled = !mCommandElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
isEnabled = !mCommandElement->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
|
||||
} else {
|
||||
isEnabled = !mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
isEnabled = !mContent->AsElement()->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
|
||||
}
|
||||
|
||||
// set up the native menu item
|
||||
if (mType == eSeparatorMenuItemType) {
|
||||
mNativeMenuItem = [[NSMenuItem separatorItem] retain];
|
||||
} else {
|
||||
NSString* newCocoaLabelString = nsMenuUtilsX::GetTruncatedCocoaLabel(aLabel);
|
||||
NSString* newCocoaLabelString =
|
||||
nsMenuUtilsX::GetTruncatedCocoaLabel(aLabel);
|
||||
mNativeMenuItem = [[NSMenuItem alloc] initWithTitle:newCocoaLabelString
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
|
||||
mIsChecked = mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
mIsChecked = mContent->AsElement()->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::checked, nsGkAtoms::_true, eCaseMatters);
|
||||
|
||||
mNativeMenuItem.enabled = isEnabled;
|
||||
mNativeMenuItem.state = mIsChecked ? NSOnState : NSOffState;
|
||||
|
@ -141,9 +147,11 @@ nsresult nsMenuItemX::SetChecked(bool aIsChecked) {
|
|||
// update the content model. This will also handle unchecking our siblings
|
||||
// if we are a radiomenu
|
||||
if (mIsChecked) {
|
||||
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, u"true"_ns, true);
|
||||
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
||||
u"true"_ns, true);
|
||||
} else {
|
||||
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked, true);
|
||||
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
||||
true);
|
||||
}
|
||||
|
||||
// update native menu item
|
||||
|
@ -158,10 +166,13 @@ EMenuItemType nsMenuItemX::GetMenuItemType() { return mType; }
|
|||
|
||||
// Executes the "cached" javaScript command.
|
||||
// Returns NS_OK if the command was executed properly, otherwise an error code.
|
||||
void nsMenuItemX::DoCommand(NSEventModifierFlags aModifierFlags, int16_t aButton) {
|
||||
void nsMenuItemX::DoCommand(NSEventModifierFlags aModifierFlags,
|
||||
int16_t aButton) {
|
||||
// flip "checked" state if we're a checkbox menu, or an un-checked radio menu
|
||||
if (mType == eCheckboxMenuItemType || (mType == eRadioMenuItemType && !mIsChecked)) {
|
||||
if (!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocheck,
|
||||
if (mType == eCheckboxMenuItemType ||
|
||||
(mType == eRadioMenuItemType && !mIsChecked)) {
|
||||
if (!mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
|
||||
nsGkAtoms::autocheck,
|
||||
nsGkAtoms::_false, eCaseMatters)) {
|
||||
SetChecked(!mIsChecked);
|
||||
}
|
||||
|
@ -171,7 +182,8 @@ void nsMenuItemX::DoCommand(NSEventModifierFlags aModifierFlags, int16_t aButton
|
|||
nsMenuUtilsX::DispatchCommandTo(mContent, aModifierFlags, aButton);
|
||||
}
|
||||
|
||||
nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventDefaultCalled) {
|
||||
nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName,
|
||||
bool* preventDefaultCalled) {
|
||||
if (!mContent) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -181,7 +193,8 @@ nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventD
|
|||
|
||||
// create DOM event
|
||||
ErrorResult rv;
|
||||
RefPtr<Event> event = parentDoc->CreateEvent(u"Events"_ns, CallerType::System, rv);
|
||||
RefPtr<Event> event =
|
||||
parentDoc->CreateEvent(u"Events"_ns, CallerType::System, rv);
|
||||
if (rv.Failed()) {
|
||||
NS_WARNING("Failed to create Event");
|
||||
return rv.StealNSResult();
|
||||
|
@ -192,7 +205,8 @@ nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventD
|
|||
event->SetTrusted(true);
|
||||
|
||||
// send DOM event
|
||||
*preventDefaultCalled = mContent->DispatchEvent(*event, CallerType::System, rv);
|
||||
*preventDefaultCalled =
|
||||
mContent->DispatchEvent(*event, CallerType::System, rv);
|
||||
if (rv.Failed()) {
|
||||
NS_WARNING("Failed to send DOM event via EventTarget");
|
||||
return rv.StealNSResult();
|
||||
|
@ -220,9 +234,10 @@ void nsMenuItemX::UncheckRadioSiblings(nsIContent* aCheckedContent) {
|
|||
sibling = sibling->GetNextSibling()) {
|
||||
if (sibling != aCheckedContent && sibling->IsElement()) { // skip this node
|
||||
// if the current sibling is in the same group, clear it
|
||||
if (sibling->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, myGroupName,
|
||||
eCaseMatters)) {
|
||||
sibling->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, u"false"_ns, true);
|
||||
if (sibling->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
||||
myGroupName, eCaseMatters)) {
|
||||
sibling->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
||||
u"false"_ns, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +251,8 @@ void nsMenuItemX::SetKeyEquiv() {
|
|||
mContent->AsElement()->GetAttr(nsGkAtoms::key, keyValue);
|
||||
|
||||
if (!keyValue.IsEmpty() && mContent->GetUncomposedDoc()) {
|
||||
dom::Element* keyContent = mContent->GetUncomposedDoc()->GetElementById(keyValue);
|
||||
dom::Element* keyContent =
|
||||
mContent->GetUncomposedDoc()->GetElementById(keyValue);
|
||||
if (keyContent) {
|
||||
nsAutoString keyChar;
|
||||
bool hasKey = keyContent->GetAttr(nsGkAtoms::key, keyChar);
|
||||
|
@ -244,7 +260,8 @@ void nsMenuItemX::SetKeyEquiv() {
|
|||
if (!hasKey || keyChar.IsEmpty()) {
|
||||
nsAutoString keyCodeName;
|
||||
keyContent->GetAttr(nsGkAtoms::keycode, keyCodeName);
|
||||
uint32_t charCode = nsCocoaUtils::ConvertGeckoNameToMacCharCode(keyCodeName);
|
||||
uint32_t charCode =
|
||||
nsCocoaUtils::ConvertGeckoNameToMacCharCode(keyCodeName);
|
||||
if (charCode) {
|
||||
keyChar.Assign(charCode);
|
||||
} else {
|
||||
|
@ -254,13 +271,16 @@ void nsMenuItemX::SetKeyEquiv() {
|
|||
|
||||
nsAutoString modifiersStr;
|
||||
keyContent->GetAttr(nsGkAtoms::modifiers, modifiersStr);
|
||||
uint8_t modifiers = nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr);
|
||||
uint8_t modifiers =
|
||||
nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr);
|
||||
|
||||
unsigned int macModifiers = nsMenuUtilsX::MacModifiersForGeckoModifiers(modifiers);
|
||||
unsigned int macModifiers =
|
||||
nsMenuUtilsX::MacModifiersForGeckoModifiers(modifiers);
|
||||
mNativeMenuItem.keyEquivalentModifierMask = macModifiers;
|
||||
|
||||
NSString* keyEquivalent = [[NSString stringWithCharacters:(unichar*)keyChar.get()
|
||||
length:keyChar.Length()] lowercaseString];
|
||||
NSString* keyEquivalent =
|
||||
[[NSString stringWithCharacters:(unichar*)keyChar.get()
|
||||
length:keyChar.Length()] lowercaseString];
|
||||
if ([keyEquivalent isEqualToString:@" "]) {
|
||||
mNativeMenuItem.keyEquivalent = @"";
|
||||
} else {
|
||||
|
@ -279,7 +299,8 @@ void nsMenuItemX::SetKeyEquiv() {
|
|||
|
||||
void nsMenuItemX::Dump(uint32_t aIndent) const {
|
||||
printf("%*s - item [%p] %-16s <%s>\n", aIndent * 2, "", this,
|
||||
mType == eSeparatorMenuItemType ? "----" : [mNativeMenuItem.title UTF8String],
|
||||
mType == eSeparatorMenuItemType ? "----"
|
||||
: [mNativeMenuItem.title UTF8String],
|
||||
NS_ConvertUTF16toUTF8(mContent->NodeName()).get());
|
||||
}
|
||||
|
||||
|
@ -287,7 +308,8 @@ void nsMenuItemX::Dump(uint32_t aIndent) const {
|
|||
// nsChangeObserver
|
||||
//
|
||||
|
||||
void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aContent,
|
||||
void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument,
|
||||
nsIContent* aContent,
|
||||
nsAtom* aAttribute) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
|
@ -300,17 +322,20 @@ void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent*
|
|||
// if we're a radio menu, uncheck our sibling radio items. No need to
|
||||
// do any of this if we're just a normal check menu.
|
||||
if (mType == eRadioMenuItemType &&
|
||||
mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
|
||||
mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
|
||||
nsGkAtoms::checked,
|
||||
nsGkAtoms::_true, eCaseMatters)) {
|
||||
UncheckRadioSiblings(mContent);
|
||||
}
|
||||
mMenuParent->SetRebuild(true);
|
||||
} else if (aAttribute == nsGkAtoms::hidden || aAttribute == nsGkAtoms::collapsed) {
|
||||
} else if (aAttribute == nsGkAtoms::hidden ||
|
||||
aAttribute == nsGkAtoms::collapsed) {
|
||||
bool isVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent);
|
||||
if (isVisible != mIsVisible) {
|
||||
mIsVisible = isVisible;
|
||||
RefPtr<nsMenuItemX> self = this;
|
||||
mMenuParent->MenuChildChangedVisibility(nsMenuParentX::MenuChild(self), isVisible);
|
||||
mMenuParent->MenuChildChangedVisibility(nsMenuParentX::MenuChild(self),
|
||||
isVisible);
|
||||
if (mIsVisible) {
|
||||
SetupIcon();
|
||||
}
|
||||
|
@ -328,7 +353,8 @@ void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent*
|
|||
SetupIcon();
|
||||
} else if (aAttribute == nsGkAtoms::disabled) {
|
||||
mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
|
||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
|
||||
eCaseMatters);
|
||||
}
|
||||
} else if (aContent == mCommandElement) {
|
||||
// the only thing that really matters when the menu isn't showing is the
|
||||
|
@ -342,15 +368,17 @@ void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent*
|
|||
if (!commandDisabled.Equals(menuDisabled)) {
|
||||
// The menu's disabled state needs to be updated to match the command.
|
||||
if (commandDisabled.IsEmpty()) {
|
||||
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
|
||||
mContent->AsElement()->UnsetAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::disabled, true);
|
||||
} else {
|
||||
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandDisabled,
|
||||
true);
|
||||
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
commandDisabled, true);
|
||||
}
|
||||
}
|
||||
// now we sync our native menu item with the command DOM node
|
||||
mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
|
||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
|
||||
eCaseMatters);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,8 +390,10 @@ bool IsMenuStructureElement(nsIContent* aContent) {
|
|||
nsGkAtoms::menuseparator);
|
||||
}
|
||||
|
||||
void nsMenuItemX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aContainer,
|
||||
nsIContent* aChild, nsIContent* aPreviousSibling) {
|
||||
void nsMenuItemX::ObserveContentRemoved(dom::Document* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
nsIContent* aPreviousSibling) {
|
||||
MOZ_RELEASE_ASSERT(mMenuGroupOwner);
|
||||
MOZ_RELEASE_ASSERT(mMenuParent);
|
||||
|
||||
|
@ -376,7 +406,8 @@ void nsMenuItemX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aC
|
|||
}
|
||||
}
|
||||
|
||||
void nsMenuItemX::ObserveContentInserted(dom::Document* aDocument, nsIContent* aContainer,
|
||||
void nsMenuItemX::ObserveContentInserted(dom::Document* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild) {
|
||||
MOZ_RELEASE_ASSERT(mMenuParent);
|
||||
|
||||
|
@ -390,7 +421,8 @@ void nsMenuItemX::ObserveContentInserted(dom::Document* aDocument, nsIContent* a
|
|||
|
||||
void nsMenuItemX::SetupIcon() {
|
||||
if (mType != eRegularMenuItemType) {
|
||||
// Don't support icons on checkbox and radio menuitems, for consistency with Windows & Linux.
|
||||
// Don't support icons on checkbox and radio menuitems, for consistency with
|
||||
// Windows & Linux.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -398,4 +430,6 @@ void nsMenuItemX::SetupIcon() {
|
|||
mNativeMenuItem.image = mIcon->GetIconImage();
|
||||
}
|
||||
|
||||
void nsMenuItemX::IconUpdated() { mNativeMenuItem.image = mIcon->GetIconImage(); }
|
||||
void nsMenuItemX::IconUpdated() {
|
||||
mNativeMenuItem.image = mIcon->GetIconImage();
|
||||
}
|
||||
|
|
|
@ -28,7 +28,8 @@ using namespace mozilla;
|
|||
bool nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest = false;
|
||||
|
||||
void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
|
||||
NSEventModifierFlags aModifierFlags, int16_t aButton) {
|
||||
NSEventModifierFlags aModifierFlags,
|
||||
int16_t aButton) {
|
||||
MOZ_ASSERT(aTargetContent, "null ptr");
|
||||
|
||||
dom::Document* doc = aTargetContent->OwnerDoc();
|
||||
|
@ -43,8 +44,9 @@ void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
|
|||
|
||||
IgnoredErrorResult rv;
|
||||
event->InitCommandEvent(u"command"_ns, true, true,
|
||||
nsGlobalWindowInner::Cast(doc->GetInnerWindow()), 0, ctrlKey, altKey,
|
||||
shiftKey, cmdKey, aButton, nullptr, 0, rv);
|
||||
nsGlobalWindowInner::Cast(doc->GetInnerWindow()), 0,
|
||||
ctrlKey, altKey, shiftKey, cmdKey, aButton, nullptr,
|
||||
0, rv);
|
||||
if (!rv.Failed()) {
|
||||
event->SetTrusted(true);
|
||||
aTargetContent->DispatchEvent(*event);
|
||||
|
@ -55,17 +57,19 @@ void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
|
|||
NSString* nsMenuUtilsX::GetTruncatedCocoaLabel(const nsString& itemLabel) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
// We want to truncate long strings to some reasonable pixel length but there is no
|
||||
// good API for doing that which works for all OS versions and architectures. For now
|
||||
// we'll do nothing for consistency and depend on good user interface design to limit
|
||||
// string lengths.
|
||||
return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(itemLabel.get())
|
||||
length:itemLabel.Length()];
|
||||
// We want to truncate long strings to some reasonable pixel length but there
|
||||
// is no good API for doing that which works for all OS versions and
|
||||
// architectures. For now we'll do nothing for consistency and depend on good
|
||||
// user interface design to limit string lengths.
|
||||
return [NSString
|
||||
stringWithCharacters:reinterpret_cast<const unichar*>(itemLabel.get())
|
||||
length:itemLabel.Length()];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(const nsString& modifiersAttribute) {
|
||||
uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(
|
||||
const nsString& modifiersAttribute) {
|
||||
uint8_t modifiers = knsMenuItemNoModifier;
|
||||
char* str = ToNewCString(modifiersAttribute);
|
||||
char* newStr;
|
||||
|
@ -87,7 +91,8 @@ uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(const nsString& modifiersAt
|
|||
return modifiers;
|
||||
}
|
||||
|
||||
unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(uint8_t geckoModifiers) {
|
||||
unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(
|
||||
uint8_t geckoModifiers) {
|
||||
unsigned int macModifiers = 0;
|
||||
|
||||
if (geckoModifiers & knsMenuItemShiftModifier) {
|
||||
|
@ -109,7 +114,8 @@ unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(uint8_t geckoModifiers)
|
|||
nsMenuBarX* nsMenuUtilsX::GetHiddenWindowMenuBar() {
|
||||
nsIWidget* hiddenWindowWidgetNoCOMPtr = nsCocoaUtils::GetHiddenWindowWidget();
|
||||
if (hiddenWindowWidgetNoCOMPtr) {
|
||||
return static_cast<nsCocoaWindow*>(hiddenWindowWidgetNoCOMPtr)->GetMenuBar();
|
||||
return static_cast<nsCocoaWindow*>(hiddenWindowWidgetNoCOMPtr)
|
||||
->GetMenuBar();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -123,9 +129,9 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
|
|||
// app-modal dialogs and Gecko-modal dialogs that open above them. So what
|
||||
// we return here isn't always released before it needs to be added to
|
||||
// another menu. See bmo bug 468393.
|
||||
NSMenuItem* standardEditMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Edit"
|
||||
action:nil
|
||||
keyEquivalent:@""] autorelease];
|
||||
NSMenuItem* standardEditMenuItem =
|
||||
[[[NSMenuItem alloc] initWithTitle:@"Edit" action:nil
|
||||
keyEquivalent:@""] autorelease];
|
||||
NSMenu* standardEditMenu = [[NSMenu alloc] initWithTitle:@"Edit"];
|
||||
standardEditMenuItem.submenu = standardEditMenu;
|
||||
[standardEditMenu release];
|
||||
|
@ -176,9 +182,10 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
|
|||
[deleteItem release];
|
||||
|
||||
// Add Select All
|
||||
NSMenuItem* selectAllItem = [[NSMenuItem alloc] initWithTitle:@"Select All"
|
||||
action:@selector(selectAll:)
|
||||
keyEquivalent:@"a"];
|
||||
NSMenuItem* selectAllItem =
|
||||
[[NSMenuItem alloc] initWithTitle:@"Select All"
|
||||
action:@selector(selectAll:)
|
||||
keyEquivalent:@"a"];
|
||||
[standardEditMenu addItem:selectAllItem];
|
||||
[selectAllItem release];
|
||||
|
||||
|
@ -188,16 +195,19 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
|
|||
}
|
||||
|
||||
bool nsMenuUtilsX::NodeIsHiddenOrCollapsed(nsIContent* aContent) {
|
||||
return aContent->IsElement() &&
|
||||
(aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden, nsGkAtoms::_true,
|
||||
eCaseMatters) ||
|
||||
aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed,
|
||||
nsGkAtoms::_true, eCaseMatters));
|
||||
return aContent->IsElement() && (aContent->AsElement()->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::hidden,
|
||||
nsGkAtoms::_true, eCaseMatters) ||
|
||||
aContent->AsElement()->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::collapsed,
|
||||
nsGkAtoms::_true, eCaseMatters));
|
||||
}
|
||||
|
||||
NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString* aLocationString,
|
||||
NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu,
|
||||
NSString* aLocationString,
|
||||
bool aIsMenuBar) {
|
||||
NSArray<NSString*>* indexes = [aLocationString componentsSeparatedByString:@"|"];
|
||||
NSArray<NSString*>* indexes =
|
||||
[aLocationString componentsSeparatedByString:@"|"];
|
||||
unsigned int pathLength = indexes.count;
|
||||
if (pathLength == 0) {
|
||||
return nil;
|
||||
|
@ -207,7 +217,8 @@ NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString
|
|||
for (unsigned int depth = 0; depth < pathLength; depth++) {
|
||||
NSInteger targetIndex = [indexes objectAtIndex:depth].integerValue;
|
||||
if (aIsMenuBar && depth == 0) {
|
||||
// We remove the application menu from consideration for the top-level menu.
|
||||
// We remove the application menu from consideration for the top-level
|
||||
// menu.
|
||||
targetIndex++;
|
||||
}
|
||||
int itemCount = currentSubmenu.numberOfItems;
|
||||
|
@ -230,20 +241,24 @@ NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString
|
|||
return nil;
|
||||
}
|
||||
|
||||
static void CheckNativeMenuConsistencyImpl(NSMenu* aMenu, std::unordered_set<void*>& aSeenObjects);
|
||||
static void CheckNativeMenuConsistencyImpl(
|
||||
NSMenu* aMenu, std::unordered_set<void*>& aSeenObjects);
|
||||
|
||||
static void CheckNativeMenuItemConsistencyImpl(NSMenuItem* aMenuItem,
|
||||
std::unordered_set<void*>& aSeenObjects) {
|
||||
static void CheckNativeMenuItemConsistencyImpl(
|
||||
NSMenuItem* aMenuItem, std::unordered_set<void*>& aSeenObjects) {
|
||||
bool inserted = aSeenObjects.insert(aMenuItem).second;
|
||||
MOZ_RELEASE_ASSERT(inserted, "Duplicate NSMenuItem object in native menu structure");
|
||||
MOZ_RELEASE_ASSERT(inserted,
|
||||
"Duplicate NSMenuItem object in native menu structure");
|
||||
if (aMenuItem.hasSubmenu) {
|
||||
CheckNativeMenuConsistencyImpl(aMenuItem.submenu, aSeenObjects);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckNativeMenuConsistencyImpl(NSMenu* aMenu, std::unordered_set<void*>& aSeenObjects) {
|
||||
static void CheckNativeMenuConsistencyImpl(
|
||||
NSMenu* aMenu, std::unordered_set<void*>& aSeenObjects) {
|
||||
bool inserted = aSeenObjects.insert(aMenu).second;
|
||||
MOZ_RELEASE_ASSERT(inserted, "Duplicate NSMenu object in native menu structure");
|
||||
MOZ_RELEASE_ASSERT(inserted,
|
||||
"Duplicate NSMenu object in native menu structure");
|
||||
for (NSMenuItem* item in aMenu.itemArray) {
|
||||
CheckNativeMenuItemConsistencyImpl(item, aSeenObjects);
|
||||
}
|
||||
|
@ -278,16 +293,20 @@ static void DumpNativeNSMenuItemImpl(NSMenuItem* aItem, uint32_t aIndent,
|
|||
if (aIndexInParentMenu) {
|
||||
printf("[%d] ", *aIndexInParentMenu);
|
||||
}
|
||||
printf("NSMenuItem [%p] %-16s%s\n", aItem,
|
||||
aItem.isSeparatorItem ? "----"
|
||||
: (aItem.title.length == 0 ? "(no title)" : aItem.title.UTF8String),
|
||||
aItem.hasSubmenu ? " [hasSubmenu]" : "");
|
||||
printf(
|
||||
"NSMenuItem [%p] %-16s%s\n", aItem,
|
||||
aItem.isSeparatorItem
|
||||
? "----"
|
||||
: (aItem.title.length == 0 ? "(no title)" : aItem.title.UTF8String),
|
||||
aItem.hasSubmenu ? " [hasSubmenu]" : "");
|
||||
if (aItem.hasSubmenu) {
|
||||
DumpNativeNSMenuImpl(aItem.submenu, aIndent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void nsMenuUtilsX::DumpNativeMenu(NSMenu* aMenu) { DumpNativeNSMenuImpl(aMenu, 0); }
|
||||
void nsMenuUtilsX::DumpNativeMenu(NSMenu* aMenu) {
|
||||
DumpNativeNSMenuImpl(aMenu, 0);
|
||||
}
|
||||
|
||||
void nsMenuUtilsX::DumpNativeMenuItem(NSMenuItem* aMenuItem) {
|
||||
DumpNativeNSMenuItemImpl(aMenuItem, 0, Nothing());
|
||||
|
|
|
@ -57,20 +57,25 @@ static void SwizzleDynamicIndexingMethods() {
|
|||
nsToolkit::SwizzleMethods([NSMenu class], @selector(_addItem:toTable:),
|
||||
@selector(nsMenuX_NSMenu_addItem:toTable:), true);
|
||||
nsToolkit::SwizzleMethods([NSMenu class], @selector(_removeItem:fromTable:),
|
||||
@selector(nsMenuX_NSMenu_removeItem:fromTable:), true);
|
||||
@selector(nsMenuX_NSMenu_removeItem:fromTable:),
|
||||
true);
|
||||
// On SnowLeopard the Shortcut framework (which contains the
|
||||
// SCTGRLIndex class) is loaded on demand, whenever the user first opens
|
||||
// a menu (which normally hasn't happened yet). So we need to load it
|
||||
// here explicitly.
|
||||
dlopen("/System/Library/PrivateFrameworks/Shortcut.framework/Shortcut", RTLD_LAZY);
|
||||
dlopen("/System/Library/PrivateFrameworks/Shortcut.framework/Shortcut",
|
||||
RTLD_LAZY);
|
||||
Class SCTGRLIndexClass = ::NSClassFromString(@"SCTGRLIndex");
|
||||
nsToolkit::SwizzleMethods(SCTGRLIndexClass, @selector(indexMenuBarDynamically),
|
||||
@selector(nsMenuX_SCTGRLIndex_indexMenuBarDynamically));
|
||||
nsToolkit::SwizzleMethods(
|
||||
SCTGRLIndexClass, @selector(indexMenuBarDynamically),
|
||||
@selector(nsMenuX_SCTGRLIndex_indexMenuBarDynamically));
|
||||
|
||||
Class NSServicesMenuUpdaterClass = ::NSClassFromString(@"_NSServicesMenuUpdater");
|
||||
nsToolkit::SwizzleMethods(NSServicesMenuUpdaterClass,
|
||||
@selector(populateMenu:withServiceEntries:forDisplay:),
|
||||
@selector(nsMenuX_populateMenu:withServiceEntries:forDisplay:));
|
||||
Class NSServicesMenuUpdaterClass =
|
||||
::NSClassFromString(@"_NSServicesMenuUpdater");
|
||||
nsToolkit::SwizzleMethods(
|
||||
NSServicesMenuUpdaterClass,
|
||||
@selector(populateMenu:withServiceEntries:forDisplay:),
|
||||
@selector(nsMenuX_populateMenu:withServiceEntries:forDisplay:));
|
||||
|
||||
gMenuMethodsSwizzled = true;
|
||||
}
|
||||
|
@ -79,7 +84,8 @@ static void SwizzleDynamicIndexingMethods() {
|
|||
// nsMenuX
|
||||
//
|
||||
|
||||
nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aContent)
|
||||
nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner,
|
||||
nsIContent* aContent)
|
||||
: mContent(aContent), mParent(aParent), mMenuGroupOwner(aMenuGroupOwner) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
|
@ -98,7 +104,8 @@ nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsI
|
|||
}
|
||||
mNativeMenu = CreateMenuWithGeckoString(mLabel);
|
||||
|
||||
// register this menu to be notified when changes are made to our content object
|
||||
// register this menu to be notified when changes are made to our content
|
||||
// object
|
||||
NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one");
|
||||
mMenuGroupOwner->RegisterForContentChanges(mContent, this);
|
||||
|
||||
|
@ -111,8 +118,9 @@ nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsI
|
|||
mNativeMenuItem.submenu = mNativeMenu;
|
||||
|
||||
SetEnabled(!mContent->IsElement() ||
|
||||
!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
nsGkAtoms::_true, eCaseMatters));
|
||||
!mContent->AsElement()->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
|
||||
eCaseMatters));
|
||||
|
||||
// We call RebuildMenu here because keyboard commands are dependent upon
|
||||
// native menu items being created. If we only call RebuildMenu when a menu
|
||||
|
@ -168,8 +176,9 @@ nsMenuX::~nsMenuX() {
|
|||
void nsMenuX::DetachFromGroupOwnerRecursive() {
|
||||
if (!mMenuGroupOwner) {
|
||||
// Don't recurse if this subtree is already detached.
|
||||
// This avoids repeated recursion during the destruction of nested nsMenuX structures.
|
||||
// Our invariant is: If we are detached, all of our contents are also detached.
|
||||
// This avoids repeated recursion during the destruction of nested nsMenuX
|
||||
// structures. Our invariant is: If we are detached, all of our contents are
|
||||
// also detached.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -180,8 +189,13 @@ void nsMenuX::DetachFromGroupOwnerRecursive() {
|
|||
|
||||
// Also detach all our children.
|
||||
for (auto& child : mMenuChildren) {
|
||||
child.match([](const RefPtr<nsMenuX>& aMenu) { aMenu->DetachFromGroupOwnerRecursive(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { aMenuItem->DetachFromGroupOwner(); });
|
||||
child.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) {
|
||||
aMenu->DetachFromGroupOwnerRecursive();
|
||||
},
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
aMenuItem->DetachFromGroupOwner();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +213,8 @@ void nsMenuX::OnMenuDidOpen(dom::Element* aPopupElement) {
|
|||
}
|
||||
}
|
||||
|
||||
void nsMenuX::OnMenuWillActivateItem(dom::Element* aPopupElement, dom::Element* aMenuItemElement) {
|
||||
void nsMenuX::OnMenuWillActivateItem(dom::Element* aPopupElement,
|
||||
dom::Element* aMenuItemElement) {
|
||||
RefPtr<nsMenuX> kungFuDeathGrip(this);
|
||||
if (mObserver) {
|
||||
mObserver->OnMenuWillActivateItem(aPopupElement, aMenuItemElement);
|
||||
|
@ -219,12 +234,16 @@ void nsMenuX::AddMenuChild(MenuChild&& aChild) {
|
|||
WillInsertChild(aChild);
|
||||
mMenuChildren.AppendElement(aChild);
|
||||
|
||||
bool isVisible =
|
||||
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); });
|
||||
bool isVisible = aChild.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->IsVisible();
|
||||
});
|
||||
NSMenuItem* nativeItem = aChild.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->NativeNSMenuItem(); });
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->NativeNSMenuItem();
|
||||
});
|
||||
|
||||
if (isVisible) {
|
||||
RemovePlaceholderIfPresent();
|
||||
|
@ -242,9 +261,11 @@ void nsMenuX::InsertMenuChild(MenuChild&& aChild) {
|
|||
size_t insertionIndex = FindInsertionIndex(aChild);
|
||||
mMenuChildren.InsertElementAt(insertionIndex, aChild);
|
||||
|
||||
bool isVisible =
|
||||
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); });
|
||||
bool isVisible = aChild.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->IsVisible();
|
||||
});
|
||||
if (isVisible) {
|
||||
MenuChildChangedVisibility(aChild, true);
|
||||
}
|
||||
|
@ -253,9 +274,11 @@ void nsMenuX::InsertMenuChild(MenuChild&& aChild) {
|
|||
}
|
||||
|
||||
void nsMenuX::RemoveMenuChild(const MenuChild& aChild) {
|
||||
bool isVisible =
|
||||
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); });
|
||||
bool isVisible = aChild.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->IsVisible();
|
||||
});
|
||||
if (isVisible) {
|
||||
MenuChildChangedVisibility(aChild, false);
|
||||
}
|
||||
|
@ -268,16 +291,20 @@ size_t nsMenuX::FindInsertionIndex(const MenuChild& aChild) {
|
|||
nsCOMPtr<nsIContent> menuPopup = GetMenuPopupContent();
|
||||
MOZ_RELEASE_ASSERT(menuPopup);
|
||||
|
||||
RefPtr<nsIContent> insertedContent =
|
||||
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
||||
RefPtr<nsIContent> insertedContent = aChild.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->Content();
|
||||
});
|
||||
|
||||
MOZ_RELEASE_ASSERT(insertedContent->GetParent() == menuPopup);
|
||||
|
||||
// Iterate over menuPopup's children (insertedContent's siblings) until we encounter
|
||||
// insertedContent. At the same time, keep track of the index in mMenuChildren.
|
||||
// Iterate over menuPopup's children (insertedContent's siblings) until we
|
||||
// encounter insertedContent. At the same time, keep track of the index in
|
||||
// mMenuChildren.
|
||||
size_t index = 0;
|
||||
for (nsIContent* child = menuPopup->GetFirstChild(); child && index < mMenuChildren.Length();
|
||||
for (nsIContent* child = menuPopup->GetFirstChild();
|
||||
child && index < mMenuChildren.Length();
|
||||
child = child->GetNextSibling()) {
|
||||
if (child == insertedContent) {
|
||||
break;
|
||||
|
@ -285,7 +312,9 @@ size_t nsMenuX::FindInsertionIndex(const MenuChild& aChild) {
|
|||
|
||||
RefPtr<nsIContent> contentAtIndex = mMenuChildren[index].match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->Content();
|
||||
});
|
||||
if (child == contentAtIndex) {
|
||||
index++;
|
||||
}
|
||||
|
@ -313,7 +342,8 @@ nsresult nsMenuX::GetVisibleItemCount(uint32_t& aCount) {
|
|||
}
|
||||
|
||||
// Only includes visible items. Note that this is provides O(N) access
|
||||
// If you need to iterate or search, consider using GetItemAt and doing your own filtering
|
||||
// If you need to iterate or search, consider using GetItemAt and doing your own
|
||||
// filtering
|
||||
Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
|
||||
uint32_t count = mMenuChildren.Length();
|
||||
if (aPos >= mVisibleItemsCount || aPos >= count) {
|
||||
|
@ -329,9 +359,11 @@ Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
|
|||
uint32_t visibleNodeIndex = 0;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
MenuChild item = *GetItemAt(i);
|
||||
RefPtr<nsIContent> content =
|
||||
item.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
||||
RefPtr<nsIContent> content = item.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->Content();
|
||||
});
|
||||
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
|
||||
if (aPos == visibleNodeIndex) {
|
||||
// we found the visible node we're looking for, return it
|
||||
|
@ -344,11 +376,14 @@ Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
|
|||
return {};
|
||||
}
|
||||
|
||||
Maybe<nsMenuX::MenuChild> nsMenuX::GetItemForElement(Element* aMenuChildElement) {
|
||||
Maybe<nsMenuX::MenuChild> nsMenuX::GetItemForElement(
|
||||
Element* aMenuChildElement) {
|
||||
for (auto& child : mMenuChildren) {
|
||||
RefPtr<nsIContent> content =
|
||||
child.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
||||
RefPtr<nsIContent> content = child.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->Content();
|
||||
});
|
||||
if (content == aMenuChildElement) {
|
||||
return Some(child);
|
||||
}
|
||||
|
@ -397,7 +432,8 @@ void nsMenuX::MenuOpened() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Make sure we fire any pending popupshown / popuphiding / popuphidden events first.
|
||||
// Make sure we fire any pending popupshown / popuphiding / popuphidden events
|
||||
// first.
|
||||
FlushMenuOpenedRunnable();
|
||||
FlushMenuClosedRunnable();
|
||||
|
||||
|
@ -405,10 +441,11 @@ void nsMenuX::MenuOpened() {
|
|||
// Fire popupshowing now.
|
||||
bool approvedToOpen = OnOpen();
|
||||
if (!approvedToOpen) {
|
||||
// We can only stop menus from opening which we open ourselves. We cannot stop menubar root
|
||||
// menus or menu submenus from opening.
|
||||
// For context menus, we can call OnOpen() before we ask the system to open the menu.
|
||||
NS_WARNING("The popupshowing event had preventDefault() called on it, but in MenuOpened() it "
|
||||
// We can only stop menus from opening which we open ourselves. We cannot
|
||||
// stop menubar root menus or menu submenus from opening. For context
|
||||
// menus, we can call OnOpen() before we ask the system to open the menu.
|
||||
NS_WARNING("The popupshowing event had preventDefault() called on it, "
|
||||
"but in MenuOpened() it "
|
||||
"is too late to stop the menu from opening.");
|
||||
}
|
||||
}
|
||||
|
@ -425,10 +462,9 @@ void nsMenuX::MenuOpened() {
|
|||
}
|
||||
|
||||
// Fire the popupshown event in MenuOpenedAsync.
|
||||
// MenuOpened() is called during menuWillOpen, and if cancelTracking is called now, menuDidClose
|
||||
// will not be called.
|
||||
// The runnable object must not hold a strong reference to the nsMenuX, so that there is no
|
||||
// reference cycle.
|
||||
// MenuOpened() is called during menuWillOpen, and if cancelTracking is called
|
||||
// now, menuDidClose will not be called. The runnable object must not hold a
|
||||
// strong reference to the nsMenuX, so that there is no reference cycle.
|
||||
class MenuOpenedAsyncRunnable final : public mozilla::CancelableRunnable {
|
||||
public:
|
||||
explicit MenuOpenedAsyncRunnable(nsMenuX* aMenu)
|
||||
|
@ -470,7 +506,8 @@ void nsMenuX::MenuOpenedAsync() {
|
|||
|
||||
// Open the node.
|
||||
if (mContent->IsElement()) {
|
||||
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::open, u"true"_ns, true);
|
||||
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::open,
|
||||
u"true"_ns, true);
|
||||
}
|
||||
|
||||
RefPtr<nsIContent> popupContent = GetMenuPopupContent();
|
||||
|
@ -482,7 +519,8 @@ void nsMenuX::MenuOpenedAsync() {
|
|||
|
||||
// Fire popupshown.
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetMouseEvent event(true, eXULPopupShown, nullptr, WidgetMouseEvent::eReal);
|
||||
WidgetMouseEvent event(true, eXULPopupShown, nullptr,
|
||||
WidgetMouseEvent::eReal);
|
||||
RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
|
||||
EventDispatcher::Dispatch(dispatchTo, nullptr, &event, nullptr, &status);
|
||||
}
|
||||
|
@ -495,7 +533,8 @@ void nsMenuX::MenuClosed() {
|
|||
// Make sure we fire any pending popupshown events first.
|
||||
FlushMenuOpenedRunnable();
|
||||
|
||||
// If any of our submenus were opened programmatically, make sure they get closed first.
|
||||
// If any of our submenus were opened programmatically, make sure they get
|
||||
// closed first.
|
||||
for (auto& child : mMenuChildren) {
|
||||
if (child.is<RefPtr<nsMenuX>>()) {
|
||||
child.as<RefPtr<nsMenuX>>()->MenuClosed();
|
||||
|
@ -505,11 +544,11 @@ void nsMenuX::MenuClosed() {
|
|||
mIsOpen = false;
|
||||
|
||||
// Do the rest of the MenuClosed work in MenuClosedAsync.
|
||||
// MenuClosed() is called from -[NSMenuDelegate menuDidClose:]. If a menuitem was clicked,
|
||||
// menuDidClose is called *before* menuItemHit for the clicked menu item is called.
|
||||
// This runnable will be canceled if ~nsMenuX runs before the runnable.
|
||||
// The runnable object must not hold a strong reference to the nsMenuX, so that there is no
|
||||
// reference cycle.
|
||||
// MenuClosed() is called from -[NSMenuDelegate menuDidClose:]. If a menuitem
|
||||
// was clicked, menuDidClose is called *before* menuItemHit for the clicked
|
||||
// menu item is called. This runnable will be canceled if ~nsMenuX runs before
|
||||
// the runnable. The runnable object must not hold a strong reference to the
|
||||
// nsMenuX, so that there is no reference cycle.
|
||||
class MenuClosedAsyncRunnable final : public mozilla::CancelableRunnable {
|
||||
public:
|
||||
explicit MenuClosedAsyncRunnable(nsMenuX* aMenu)
|
||||
|
@ -538,7 +577,8 @@ void nsMenuX::MenuClosed() {
|
|||
}
|
||||
|
||||
void nsMenuX::FlushMenuClosedRunnable() {
|
||||
// If any of our submenus have a pending menu closed runnable, make sure those run first.
|
||||
// If any of our submenus have a pending menu closed runnable, make sure those
|
||||
// run first.
|
||||
for (auto& child : mMenuChildren) {
|
||||
if (child.is<RefPtr<nsMenuX>>()) {
|
||||
child.as<RefPtr<nsMenuX>>()->FlushMenuClosedRunnable();
|
||||
|
@ -569,8 +609,10 @@ void nsMenuX::MenuClosedAsync() {
|
|||
nsCOMPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetMouseEvent popupHiding(true, eXULPopupHiding, nullptr, WidgetMouseEvent::eReal);
|
||||
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHiding, nullptr, &status);
|
||||
WidgetMouseEvent popupHiding(true, eXULPopupHiding, nullptr,
|
||||
WidgetMouseEvent::eReal);
|
||||
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHiding, nullptr,
|
||||
&status);
|
||||
|
||||
mIsOpenForGecko = false;
|
||||
|
||||
|
@ -578,8 +620,10 @@ void nsMenuX::MenuClosedAsync() {
|
|||
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
|
||||
}
|
||||
|
||||
WidgetMouseEvent popupHidden(true, eXULPopupHidden, nullptr, WidgetMouseEvent::eReal);
|
||||
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHidden, nullptr, &status);
|
||||
WidgetMouseEvent popupHidden(true, eXULPopupHidden, nullptr,
|
||||
WidgetMouseEvent::eReal);
|
||||
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHidden, nullptr,
|
||||
&status);
|
||||
|
||||
// Notify our observer.
|
||||
if (mObserver && popupContent) {
|
||||
|
@ -587,17 +631,22 @@ void nsMenuX::MenuClosedAsync() {
|
|||
}
|
||||
}
|
||||
|
||||
void nsMenuX::ActivateItemAfterClosing(RefPtr<nsMenuItemX>&& aItem, NSEventModifierFlags aModifiers,
|
||||
void nsMenuX::ActivateItemAfterClosing(RefPtr<nsMenuItemX>&& aItem,
|
||||
NSEventModifierFlags aModifiers,
|
||||
int16_t aButton) {
|
||||
if (mIsOpenForGecko) {
|
||||
// Queue the event into mPendingCommandEvents. We will call aItem->DoCommand in
|
||||
// MenuClosedAsync(). We rely on the assumption that MenuClosedAsync will run soon.
|
||||
mPendingCommandEvents.AppendElement(PendingCommandEvent{std::move(aItem), aModifiers, aButton});
|
||||
// Queue the event into mPendingCommandEvents. We will call aItem->DoCommand
|
||||
// in MenuClosedAsync(). We rely on the assumption that MenuClosedAsync will
|
||||
// run soon.
|
||||
mPendingCommandEvents.AppendElement(
|
||||
PendingCommandEvent{std::move(aItem), aModifiers, aButton});
|
||||
} else {
|
||||
// The menu item was activated outside of a regular open / activate / close sequence.
|
||||
// This happens in multiple cases:
|
||||
// - When a menu item is activated by a keyboard shortcut while all windows are closed
|
||||
// (otherwise those shortcuts go through Gecko's manual keyboard handling)
|
||||
// The menu item was activated outside of a regular open / activate / close
|
||||
// sequence. This happens in multiple cases:
|
||||
// - When a menu item is activated by a keyboard shortcut while all windows
|
||||
// are closed
|
||||
// (otherwise those shortcuts go through Gecko's manual keyboard
|
||||
// handling)
|
||||
// - When a menu item in the Dock menu is clicked
|
||||
// - During native menu tests
|
||||
//
|
||||
|
@ -610,10 +659,11 @@ bool nsMenuX::Close() {
|
|||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (mDidFirePopupshowingAndIsApprovedToOpen && !mIsOpen) {
|
||||
// Close is being called right after this menu was opened, but before MenuOpened() had a chance
|
||||
// to run. Call it here so that we can go through the entire popupshown -> popuphiding ->
|
||||
// popuphidden sequence. Some callers expect to get a popuphidden event even if they close the
|
||||
// popup before it was fully open.
|
||||
// Close is being called right after this menu was opened, but before
|
||||
// MenuOpened() had a chance to run. Call it here so that we can go through
|
||||
// the entire popupshown -> popuphiding -> popuphidden sequence. Some
|
||||
// callers expect to get a popuphidden event even if they close the popup
|
||||
// before it was fully open.
|
||||
MenuOpened();
|
||||
}
|
||||
|
||||
|
@ -623,11 +673,12 @@ bool nsMenuX::Close() {
|
|||
|
||||
if (mIsOpen) {
|
||||
// Close the menu.
|
||||
// We usually don't get here during normal Firefox usage: If the user closes the menu by
|
||||
// clicking an item, or by clicking outside the menu, or by pressing escape, then the menu gets
|
||||
// closed by macOS, and not by a call to nsMenuX::Close().
|
||||
// If we do get here, it's usually because we're running an automated test. Close the menu
|
||||
// without the fade-out animation so that we don't unnecessarily slow down the automated tests.
|
||||
// We usually don't get here during normal Firefox usage: If the user closes
|
||||
// the menu by clicking an item, or by clicking outside the menu, or by
|
||||
// pressing escape, then the menu gets closed by macOS, and not by a call to
|
||||
// nsMenuX::Close(). If we do get here, it's usually because we're running
|
||||
// an automated test. Close the menu without the fade-out animation so that
|
||||
// we don't unnecessarily slow down the automated tests.
|
||||
[mNativeMenu cancelTrackingWithoutAnimation];
|
||||
MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES;
|
||||
|
||||
|
@ -642,7 +693,8 @@ bool nsMenuX::Close() {
|
|||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
void nsMenuX::OnHighlightedItemChanged(const Maybe<uint32_t>& aNewHighlightedIndex) {
|
||||
void nsMenuX::OnHighlightedItemChanged(
|
||||
const Maybe<uint32_t>& aNewHighlightedIndex) {
|
||||
if (mHighlightedItemIndex == aNewHighlightedIndex) {
|
||||
return;
|
||||
}
|
||||
|
@ -651,16 +703,16 @@ void nsMenuX::OnHighlightedItemChanged(const Maybe<uint32_t>& aNewHighlightedInd
|
|||
Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*mHighlightedItemIndex);
|
||||
if (target && target->is<RefPtr<nsMenuItemX>>()) {
|
||||
bool handlerCalledPreventDefault; // but we don't actually care
|
||||
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(u"DOMMenuItemInactive"_ns,
|
||||
&handlerCalledPreventDefault);
|
||||
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(
|
||||
u"DOMMenuItemInactive"_ns, &handlerCalledPreventDefault);
|
||||
}
|
||||
}
|
||||
if (aNewHighlightedIndex) {
|
||||
Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*aNewHighlightedIndex);
|
||||
if (target && target->is<RefPtr<nsMenuItemX>>()) {
|
||||
bool handlerCalledPreventDefault; // but we don't actually care
|
||||
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(u"DOMMenuItemActive"_ns,
|
||||
&handlerCalledPreventDefault);
|
||||
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(
|
||||
u"DOMMenuItemActive"_ns, &handlerCalledPreventDefault);
|
||||
}
|
||||
}
|
||||
mHighlightedItemIndex = aNewHighlightedIndex;
|
||||
|
@ -672,21 +724,25 @@ void nsMenuX::OnWillActivateItem(NSMenuItem* aItem) {
|
|||
}
|
||||
|
||||
if (mMenuGroupOwner && mObserver) {
|
||||
nsMenuItemX* item = mMenuGroupOwner->GetMenuItemForCommandID(uint32_t(aItem.tag));
|
||||
nsMenuItemX* item =
|
||||
mMenuGroupOwner->GetMenuItemForCommandID(uint32_t(aItem.tag));
|
||||
if (item && item->Content()->IsElement()) {
|
||||
RefPtr<dom::Element> itemElement = item->Content()->AsElement();
|
||||
if (nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent()) {
|
||||
mObserver->OnMenuWillActivateItem(popupContent->AsElement(), itemElement);
|
||||
mObserver->OnMenuWillActivateItem(popupContent->AsElement(),
|
||||
itemElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flushes style.
|
||||
static NSUserInterfaceLayoutDirection DirectionForElement(dom::Element* aElement) {
|
||||
// Get the direction from the computed style so that inheritance into submenus is respected.
|
||||
// aElement may not have a frame.
|
||||
RefPtr<const ComputedStyle> sc = nsComputedDOMStyle::GetComputedStyle(aElement);
|
||||
static NSUserInterfaceLayoutDirection DirectionForElement(
|
||||
dom::Element* aElement) {
|
||||
// Get the direction from the computed style so that inheritance into submenus
|
||||
// is respected. aElement may not have a frame.
|
||||
RefPtr<const ComputedStyle> sc =
|
||||
nsComputedDOMStyle::GetComputedStyle(aElement);
|
||||
if (!sc) {
|
||||
return NSApp.userInterfaceLayoutDirection;
|
||||
}
|
||||
|
@ -711,11 +767,13 @@ void nsMenuX::RebuildMenu() {
|
|||
}
|
||||
|
||||
if (menuPopup->IsElement()) {
|
||||
mNativeMenu.userInterfaceLayoutDirection = DirectionForElement(menuPopup->AsElement());
|
||||
mNativeMenu.userInterfaceLayoutDirection =
|
||||
DirectionForElement(menuPopup->AsElement());
|
||||
}
|
||||
|
||||
// Iterate over the kids
|
||||
for (nsIContent* child = menuPopup->GetFirstChild(); child; child = child->GetNextSibling()) {
|
||||
for (nsIContent* child = menuPopup->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (Maybe<MenuChild> menuChild = CreateMenuChild(child)) {
|
||||
AddMenuChild(std::move(*menuChild));
|
||||
}
|
||||
|
@ -732,9 +790,12 @@ void nsMenuX::InsertPlaceholderIfNeeded() {
|
|||
|
||||
if ([mNativeMenu numberOfItems] == 0) {
|
||||
MOZ_RELEASE_ASSERT(mVisibleItemsCount == 0);
|
||||
NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
|
||||
NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:@""
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
item.enabled = NO;
|
||||
item.view = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 150, 1)] autorelease];
|
||||
item.view =
|
||||
[[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 150, 1)] autorelease];
|
||||
[mNativeMenu addItem:item];
|
||||
[item release];
|
||||
}
|
||||
|
@ -800,11 +861,13 @@ GeckoNSMenu* nsMenuX::CreateMenuWithGeckoString(nsString& aMenuTitle) {
|
|||
}
|
||||
|
||||
Maybe<nsMenuX::MenuChild> nsMenuX::CreateMenuChild(nsIContent* aContent) {
|
||||
if (aContent->IsAnyOfXULElements(nsGkAtoms::menuitem, nsGkAtoms::menuseparator)) {
|
||||
if (aContent->IsAnyOfXULElements(nsGkAtoms::menuitem,
|
||||
nsGkAtoms::menuseparator)) {
|
||||
return Some(MenuChild(CreateMenuItem(aContent)));
|
||||
}
|
||||
if (aContent->IsXULElement(nsGkAtoms::menu)) {
|
||||
return Some(MenuChild(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aContent)));
|
||||
return Some(
|
||||
MenuChild(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aContent)));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -821,9 +884,10 @@ RefPtr<nsMenuItemX> nsMenuX::CreateMenuItem(nsIContent* aMenuItemContent) {
|
|||
if (aMenuItemContent->IsXULElement(nsGkAtoms::menuseparator)) {
|
||||
itemType = eSeparatorMenuItemType;
|
||||
} else if (aMenuItemContent->IsElement()) {
|
||||
static Element::AttrValuesArray strings[] = {nsGkAtoms::checkbox, nsGkAtoms::radio, nullptr};
|
||||
switch (aMenuItemContent->AsElement()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
|
||||
strings, eCaseMatters)) {
|
||||
static Element::AttrValuesArray strings[] = {nsGkAtoms::checkbox,
|
||||
nsGkAtoms::radio, nullptr};
|
||||
switch (aMenuItemContent->AsElement()->FindAttrValueIn(
|
||||
kNameSpaceID_None, nsGkAtoms::type, strings, eCaseMatters)) {
|
||||
case 0:
|
||||
itemType = eCheckboxMenuItemType;
|
||||
break;
|
||||
|
@ -833,17 +897,20 @@ RefPtr<nsMenuItemX> nsMenuX::CreateMenuItem(nsIContent* aMenuItemContent) {
|
|||
}
|
||||
}
|
||||
|
||||
return MakeRefPtr<nsMenuItemX>(this, menuitemName, itemType, mMenuGroupOwner, aMenuItemContent);
|
||||
return MakeRefPtr<nsMenuItemX>(this, menuitemName, itemType, mMenuGroupOwner,
|
||||
aMenuItemContent);
|
||||
}
|
||||
|
||||
// This menu is about to open. Returns false if the handler wants to stop the opening of the menu.
|
||||
// This menu is about to open. Returns false if the handler wants to stop the
|
||||
// opening of the menu.
|
||||
bool nsMenuX::OnOpen() {
|
||||
if (mDidFirePopupshowingAndIsApprovedToOpen) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mIsOpen) {
|
||||
NS_WARNING("nsMenuX::OnOpen() called while the menu is already considered to be open. This "
|
||||
NS_WARNING("nsMenuX::OnOpen() called while the menu is already considered "
|
||||
"to be open. This "
|
||||
"seems odd.");
|
||||
}
|
||||
|
||||
|
@ -854,7 +921,8 @@ bool nsMenuX::OnOpen() {
|
|||
}
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetMouseEvent event(true, eXULPopupShowing, nullptr, WidgetMouseEvent::eReal);
|
||||
WidgetMouseEvent event(true, eXULPopupShowing, nullptr,
|
||||
WidgetMouseEvent::eReal);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
|
||||
|
@ -886,9 +954,9 @@ void nsMenuX::DidFirePopupShowing() {
|
|||
}
|
||||
}
|
||||
|
||||
// Find the |menupopup| child in the |popup| representing this menu. It should be one
|
||||
// of a very few children so we won't be iterating over a bazillion menu items to find
|
||||
// it (so the strcmp won't kill us).
|
||||
// Find the |menupopup| child in the |popup| representing this menu. It should
|
||||
// be one of a very few children so we won't be iterating over a bazillion menu
|
||||
// items to find it (so the strcmp won't kill us).
|
||||
already_AddRefed<nsIContent> nsMenuX::GetMenuPopupContent() {
|
||||
// Check to see if we are a "menupopup" node (if we are a native menu).
|
||||
if (mContent->IsXULElement(nsGkAtoms::menupopup)) {
|
||||
|
@ -935,7 +1003,8 @@ bool nsMenuX::IsXULWindowMenu(nsIContent* aMenuContent) {
|
|||
// nsChangeObserver
|
||||
//
|
||||
|
||||
void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aContent,
|
||||
void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument,
|
||||
nsIContent* aContent,
|
||||
nsAtom* aAttribute) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
|
@ -945,14 +1014,17 @@ void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aCon
|
|||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::disabled) {
|
||||
SetEnabled(!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
nsGkAtoms::_true, eCaseMatters));
|
||||
SetEnabled(!mContent->AsElement()->AttrValueIs(
|
||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
|
||||
eCaseMatters));
|
||||
} else if (aAttribute == nsGkAtoms::label) {
|
||||
mContent->AsElement()->GetAttr(nsGkAtoms::label, mLabel);
|
||||
NSString* newCocoaLabelString = nsMenuUtilsX::GetTruncatedCocoaLabel(mLabel);
|
||||
NSString* newCocoaLabelString =
|
||||
nsMenuUtilsX::GetTruncatedCocoaLabel(mLabel);
|
||||
mNativeMenu.title = newCocoaLabelString;
|
||||
mNativeMenuItem.title = newCocoaLabelString;
|
||||
} else if (aAttribute == nsGkAtoms::hidden || aAttribute == nsGkAtoms::collapsed) {
|
||||
} else if (aAttribute == nsGkAtoms::hidden ||
|
||||
aAttribute == nsGkAtoms::collapsed) {
|
||||
SetRebuild(true);
|
||||
|
||||
bool newVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent);
|
||||
|
@ -977,8 +1049,9 @@ void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aCon
|
|||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
void nsMenuX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aContainer,
|
||||
nsIContent* aChild, nsIContent* aPreviousSibling) {
|
||||
void nsMenuX::ObserveContentRemoved(dom::Document* aDocument,
|
||||
nsIContent* aContainer, nsIContent* aChild,
|
||||
nsIContent* aPreviousSibling) {
|
||||
if (gConstructingMenu) {
|
||||
return;
|
||||
}
|
||||
|
@ -991,7 +1064,8 @@ void nsMenuX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aConta
|
|||
return;
|
||||
}
|
||||
|
||||
// The menu is currently open. Remove the child from mMenuChildren and from our NSMenu.
|
||||
// The menu is currently open. Remove the child from mMenuChildren and from
|
||||
// our NSMenu.
|
||||
nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent();
|
||||
if (popupContent && aContainer == popupContent && aChild->IsElement()) {
|
||||
if (Maybe<MenuChild> child = GetItemForElement(aChild->AsElement())) {
|
||||
|
@ -1000,7 +1074,8 @@ void nsMenuX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aConta
|
|||
}
|
||||
}
|
||||
|
||||
void nsMenuX::ObserveContentInserted(dom::Document* aDocument, nsIContent* aContainer,
|
||||
void nsMenuX::ObserveContentInserted(dom::Document* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild) {
|
||||
if (gConstructingMenu) {
|
||||
return;
|
||||
|
@ -1013,7 +1088,8 @@ void nsMenuX::ObserveContentInserted(dom::Document* aDocument, nsIContent* aCont
|
|||
return;
|
||||
}
|
||||
|
||||
// The menu is currently open. Insert the child into mMenuChildren and into our NSMenu.
|
||||
// The menu is currently open. Insert the child into mMenuChildren and into
|
||||
// our NSMenu.
|
||||
nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent();
|
||||
if (popupContent && aContainer == popupContent) {
|
||||
if (Maybe<MenuChild> child = CreateMenuChild(aChild)) {
|
||||
|
@ -1034,22 +1110,27 @@ void nsMenuX::IconUpdated() {
|
|||
}
|
||||
}
|
||||
|
||||
void nsMenuX::MenuChildChangedVisibility(const MenuChild& aChild, bool aIsVisible) {
|
||||
void nsMenuX::MenuChildChangedVisibility(const MenuChild& aChild,
|
||||
bool aIsVisible) {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
NSMenuItem* nativeItem = aChild.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->NativeNSMenuItem(); });
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->NativeNSMenuItem();
|
||||
});
|
||||
if (aIsVisible) {
|
||||
MOZ_RELEASE_ASSERT(!nativeItem.menu,
|
||||
"The native item should not be in a menu while it is hidden");
|
||||
MOZ_RELEASE_ASSERT(
|
||||
!nativeItem.menu,
|
||||
"The native item should not be in a menu while it is hidden");
|
||||
RemovePlaceholderIfPresent();
|
||||
NSInteger insertionPoint = CalculateNativeInsertionPoint(aChild);
|
||||
[mNativeMenu insertItem:nativeItem atIndex:insertionPoint];
|
||||
mVisibleItemsCount++;
|
||||
} else {
|
||||
MOZ_RELEASE_ASSERT([mNativeMenu indexOfItem:nativeItem] != -1,
|
||||
"The native item should be in this menu while it is visible");
|
||||
MOZ_RELEASE_ASSERT(
|
||||
[mNativeMenu indexOfItem:nativeItem] != -1,
|
||||
"The native item should be in this menu while it is visible");
|
||||
[mNativeMenu removeItem:nativeItem];
|
||||
mVisibleItemsCount--;
|
||||
InsertPlaceholderIfNeeded();
|
||||
|
@ -1067,7 +1148,9 @@ NSInteger nsMenuX::CalculateNativeInsertionPoint(const MenuChild& aChild) {
|
|||
}
|
||||
NSMenuItem* nativeItem = currItem.match(
|
||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->NativeNSMenuItem(); });
|
||||
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
return aMenuItem->NativeNSMenuItem();
|
||||
});
|
||||
// Only count visible items.
|
||||
if (nativeItem.menu) {
|
||||
insertionPoint++;
|
||||
|
@ -1077,9 +1160,10 @@ NSInteger nsMenuX::CalculateNativeInsertionPoint(const MenuChild& aChild) {
|
|||
}
|
||||
|
||||
void nsMenuX::Dump(uint32_t aIndent) const {
|
||||
printf("%*s - menu [%p] %-16s <%s>", aIndent * 2, "", this,
|
||||
mLabel.IsEmpty() ? "(empty label)" : NS_ConvertUTF16toUTF8(mLabel).get(),
|
||||
NS_ConvertUTF16toUTF8(mContent->NodeName()).get());
|
||||
printf(
|
||||
"%*s - menu [%p] %-16s <%s>", aIndent * 2, "", this,
|
||||
mLabel.IsEmpty() ? "(empty label)" : NS_ConvertUTF16toUTF8(mLabel).get(),
|
||||
NS_ConvertUTF16toUTF8(mContent->NodeName()).get());
|
||||
if (mNeedsRebuild) {
|
||||
printf(" [NeedsRebuild]");
|
||||
}
|
||||
|
@ -1095,8 +1179,11 @@ void nsMenuX::Dump(uint32_t aIndent) const {
|
|||
printf(" (%d visible items)", int(mVisibleItemsCount));
|
||||
printf("\n");
|
||||
for (const auto& subitem : mMenuChildren) {
|
||||
subitem.match([=](const RefPtr<nsMenuX>& aMenu) { aMenu->Dump(aIndent + 1); },
|
||||
[=](const RefPtr<nsMenuItemX>& aMenuItem) { aMenuItem->Dump(aIndent + 1); });
|
||||
subitem.match(
|
||||
[=](const RefPtr<nsMenuX>& aMenu) { aMenu->Dump(aIndent + 1); },
|
||||
[=](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||
aMenuItem->Dump(aIndent + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1108,8 +1195,8 @@ void nsMenuX::Dump(uint32_t aIndent) const {
|
|||
|
||||
- (id)initWithGeckoMenu:(nsMenuX*)geckoMenu {
|
||||
if ((self = [super init])) {
|
||||
NS_ASSERTION(geckoMenu,
|
||||
"Cannot initialize native menu delegate with NULL gecko menu! Will crash!");
|
||||
NS_ASSERTION(geckoMenu, "Cannot initialize native menu delegate with NULL "
|
||||
"gecko menu! Will crash!");
|
||||
mGeckoMenu = geckoMenu;
|
||||
mBlocksToRunWhenOpen = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
@ -1131,7 +1218,8 @@ void nsMenuX::Dump(uint32_t aIndent) const {
|
|||
}
|
||||
|
||||
Maybe<uint32_t> index =
|
||||
aItem ? Some(static_cast<uint32_t>([aMenu indexOfItem:aItem])) : Nothing();
|
||||
aItem ? Some(static_cast<uint32_t>([aMenu indexOfItem:aItem]))
|
||||
: Nothing();
|
||||
mGeckoMenu->OnHighlightedItemChanged(index);
|
||||
}
|
||||
|
||||
|
@ -1269,7 +1357,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
|
|||
|
||||
- (int)removeTable:(NSMapTable*)aTable {
|
||||
if (aTable) {
|
||||
NSValue* objectToRemove = [mTables member:[NSValue valueWithPointer:aTable]];
|
||||
NSValue* objectToRemove =
|
||||
[mTables member:[NSValue valueWithPointer:aTable]];
|
||||
if (objectToRemove) {
|
||||
[mTables removeObject:objectToRemove];
|
||||
}
|
||||
|
@ -1281,7 +1370,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
|
|||
|
||||
@interface NSMenu (MethodSwizzling)
|
||||
+ (void)nsMenuX_NSMenu_addItem:(NSMenuItem*)aItem toTable:(NSMapTable*)aTable;
|
||||
+ (void)nsMenuX_NSMenu_removeItem:(NSMenuItem*)aItem fromTable:(NSMapTable*)aTable;
|
||||
+ (void)nsMenuX_NSMenu_removeItem:(NSMenuItem*)aItem
|
||||
fromTable:(NSMapTable*)aTable;
|
||||
@end
|
||||
|
||||
@implementation NSMenu (MethodSwizzling)
|
||||
|
@ -1304,7 +1394,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
|
|||
[self nsMenuX_NSMenu_addItem:aItem toTable:aTable];
|
||||
}
|
||||
|
||||
+ (void)nsMenuX_NSMenu_removeItem:(NSMenuItem*)aItem fromTable:(NSMapTable*)aTable {
|
||||
+ (void)nsMenuX_NSMenu_removeItem:(NSMenuItem*)aItem
|
||||
fromTable:(NSMapTable*)aTable {
|
||||
[self nsMenuX_NSMenu_removeItem:aItem fromTable:aTable];
|
||||
|
||||
if (aItem && aTable) {
|
||||
|
@ -1382,7 +1473,9 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
|
|||
}
|
||||
}
|
||||
|
||||
[self nsMenuX_populateMenu:aMenu withServiceEntries:filteredServices forDisplay:aForDisplay];
|
||||
[self nsMenuX_populateMenu:aMenu
|
||||
withServiceEntries:filteredServices
|
||||
forDisplay:aForDisplay];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -73,7 +73,8 @@ NS_IMETHODIMP
|
|||
nsPrintDialogServiceX::Init() { return NS_OK; }
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSelection,
|
||||
nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent,
|
||||
bool aHaveSelection,
|
||||
nsIPrintSettings* aSettings) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
|
@ -84,7 +85,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NSPrintInfo* printInfo = settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
|
||||
NSPrintInfo* printInfo =
|
||||
settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
|
||||
if (NS_WARN_IF(!printInfo)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -100,7 +102,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
|||
NULL, reinterpret_cast<const UniChar*>(adjustedTitle.BeginReading()),
|
||||
adjustedTitle.Length());
|
||||
if (cfTitleString) {
|
||||
auto pmPrintSettings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
|
||||
auto pmPrintSettings =
|
||||
static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
|
||||
::PMPrintSettingsSetJobName(pmPrintSettings, cfTitleString);
|
||||
[printInfo updateFromPMPrintSettings];
|
||||
CFRelease(cfTitleString);
|
||||
|
@ -117,8 +120,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
|||
// [panel runModal] will look for it. We create the view because otherwise
|
||||
// we'll get unrelated warnings printed to the console.
|
||||
NSView* tmpView = [[NSView alloc] init];
|
||||
NSPrintOperation* printOperation = [NSPrintOperation printOperationWithView:tmpView
|
||||
printInfo:printInfo];
|
||||
NSPrintOperation* printOperation =
|
||||
[NSPrintOperation printOperationWithView:tmpView printInfo:printInfo];
|
||||
[NSPrintOperation setCurrentOperation:printOperation];
|
||||
|
||||
NSPrintPanel* panel = [NSPrintPanel printPanel];
|
||||
|
@ -136,8 +139,9 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
|||
int button = [panel runModal];
|
||||
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
||||
|
||||
// Retrieve a printInfo with the updated settings. (The NSPrintOperation operates on a
|
||||
// copy, so the object we passed in will not have been modified.)
|
||||
// Retrieve a printInfo with the updated settings. (The NSPrintOperation
|
||||
// operates on a copy, so the object we passed in will not have been
|
||||
// modified.)
|
||||
NSPrintInfo* result = [[NSPrintOperation currentOperation] printInfo];
|
||||
if (!result) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -164,9 +168,9 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
|||
[viewController exportSettings];
|
||||
|
||||
// Update our settings object based on the user's choices in the dialog.
|
||||
// We tell settingsX to adopt this printInfo so that it will be used to run print job,
|
||||
// so that any printer-specific custom settings from print dialog extension panels
|
||||
// will be carried through.
|
||||
// We tell settingsX to adopt this printInfo so that it will be used to run
|
||||
// print job, so that any printer-specific custom settings from print dialog
|
||||
// extension panels will be carried through.
|
||||
settingsX->SetFromPrintInfo(result, /* aAdoptPrintInfo = */ true);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -188,7 +192,8 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NSPrintInfo* printInfo = settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
|
||||
NSPrintInfo* printInfo =
|
||||
settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
|
||||
if (NS_WARN_IF(!printInfo)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -200,15 +205,17 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
|
|||
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
||||
|
||||
if (button == NSFileHandlingPanelOKButton) {
|
||||
// The Page Setup dialog does not include non-standard settings that need to be preserved,
|
||||
// separate from what the base printSettings object handles, so we do not need it to adopt
|
||||
// the printInfo object here.
|
||||
// The Page Setup dialog does not include non-standard settings that need to
|
||||
// be preserved, separate from what the base printSettings object handles,
|
||||
// so we do not need it to adopt the printInfo object here.
|
||||
settingsX->SetFromPrintInfo(printInfo, /* aAdoptPrintInfo = */ false);
|
||||
nsCOMPtr<nsIPrintSettingsService> printSettingsService =
|
||||
do_GetService("@mozilla.org/gfx/printsettings-service;1");
|
||||
if (printSettingsService && Preferences::GetBool("print.save_print_settings", false)) {
|
||||
if (printSettingsService &&
|
||||
Preferences::GetBool("print.save_print_settings", false)) {
|
||||
uint32_t flags = nsIPrintSettings::kInitSavePaperSize |
|
||||
nsIPrintSettings::kInitSaveOrientation | nsIPrintSettings::kInitSaveScaling;
|
||||
nsIPrintSettings::kInitSaveOrientation |
|
||||
nsIPrintSettings::kInitSaveScaling;
|
||||
printSettingsService->MaybeSavePrintSettingsToPrefs(aNSSettings, flags);
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -234,7 +241,9 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
|
|||
withFrame:(NSRect)aRect
|
||||
alignment:(NSTextAlignment)aAlignment;
|
||||
|
||||
- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect alignment:(NSTextAlignment)aAlignment;
|
||||
- (void)addLabel:(const char*)aLabel
|
||||
withFrame:(NSRect)aRect
|
||||
alignment:(NSTextAlignment)aAlignment;
|
||||
|
||||
- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect;
|
||||
|
||||
|
@ -243,7 +252,8 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
|
|||
- (NSButton*)checkboxWithLabel:(const char*)aLabel andFrame:(NSRect)aRect;
|
||||
|
||||
- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
|
||||
selectedItem:(const nsAString&)aCurrentString;
|
||||
selectedItem:
|
||||
(const nsAString&)aCurrentString;
|
||||
|
||||
- (void)addOptionsSection:(bool)aHaveSelection;
|
||||
|
||||
|
@ -265,7 +275,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
|
||||
// Public methods
|
||||
|
||||
- (id)initWithSettings:(nsIPrintSettings*)aSettings haveSelection:(bool)aHaveSelection {
|
||||
- (id)initWithSettings:(nsIPrintSettings*)aSettings
|
||||
haveSelection:(bool)aHaveSelection {
|
||||
[super initWithFrame:NSMakeRect(0, 0, 540, 185)];
|
||||
|
||||
mSettings = aSettings;
|
||||
|
@ -278,7 +289,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
}
|
||||
|
||||
- (void)exportSettings {
|
||||
mSettings->SetPrintSelectionOnly([mPrintSelectionOnlyCheckbox state] == NSOnState);
|
||||
mSettings->SetPrintSelectionOnly([mPrintSelectionOnlyCheckbox state] ==
|
||||
NSOnState);
|
||||
mSettings->SetShrinkToFit([mShrinkToFitCheckbox state] == NSOnState);
|
||||
mSettings->SetPrintBGColors([mPrintBGColorsCheckbox state] == NSOnState);
|
||||
mSettings->SetPrintBGImages([mPrintBGImagesCheckbox state] == NSOnState);
|
||||
|
@ -294,8 +306,10 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
// Localization
|
||||
|
||||
- (void)initBundle {
|
||||
nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", &mPrintBundle);
|
||||
nsCOMPtr<nsIStringBundleService> bundleSvc =
|
||||
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties",
|
||||
&mPrintBundle);
|
||||
}
|
||||
|
||||
- (NSString*)localizedString:(const char*)aKey {
|
||||
|
@ -303,11 +317,14 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
|
||||
nsAutoString intlString;
|
||||
mPrintBundle->GetStringFromName(aKey, intlString);
|
||||
NSMutableString* s =
|
||||
[NSMutableString stringWithUTF8String:NS_ConvertUTF16toUTF8(intlString).get()];
|
||||
NSMutableString* s = [NSMutableString
|
||||
stringWithUTF8String:NS_ConvertUTF16toUTF8(intlString).get()];
|
||||
|
||||
// Remove all underscores (they're used in the GTK dialog for accesskeys).
|
||||
[s replaceOccurrencesOfString:@"_" withString:@"" options:0 range:NSMakeRange(0, [s length])];
|
||||
[s replaceOccurrencesOfString:@"_"
|
||||
withString:@""
|
||||
options:0
|
||||
range:NSMakeRange(0, [s length])];
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -328,7 +345,9 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
return label;
|
||||
}
|
||||
|
||||
- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect alignment:(NSTextAlignment)aAlignment {
|
||||
- (void)addLabel:(const char*)aLabel
|
||||
withFrame:(NSRect)aRect
|
||||
alignment:(NSTextAlignment)aAlignment {
|
||||
NSTextField* label = [self label:aLabel withFrame:aRect alignment:aAlignment];
|
||||
[self addSubview:label];
|
||||
}
|
||||
|
@ -352,16 +371,19 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
}
|
||||
|
||||
- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
|
||||
selectedItem:(const nsAString&)aCurrentString {
|
||||
NSPopUpButton* list = [[[NSPopUpButton alloc] initWithFrame:aRect pullsDown:NO] autorelease];
|
||||
selectedItem:
|
||||
(const nsAString&)aCurrentString {
|
||||
NSPopUpButton* list = [[[NSPopUpButton alloc] initWithFrame:aRect
|
||||
pullsDown:NO] autorelease];
|
||||
[list setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
||||
[[list cell] setControlSize:NSControlSizeSmall];
|
||||
NSArray* items = [NSArray arrayWithObjects:[self localizedString:"headerFooterBlank"],
|
||||
[self localizedString:"headerFooterTitle"],
|
||||
[self localizedString:"headerFooterURL"],
|
||||
[self localizedString:"headerFooterDate"],
|
||||
[self localizedString:"headerFooterPage"],
|
||||
[self localizedString:"headerFooterPageTotal"], nil];
|
||||
NSArray* items = [NSArray
|
||||
arrayWithObjects:[self localizedString:"headerFooterBlank"],
|
||||
[self localizedString:"headerFooterTitle"],
|
||||
[self localizedString:"headerFooterURL"],
|
||||
[self localizedString:"headerFooterDate"],
|
||||
[self localizedString:"headerFooterPage"],
|
||||
[self localizedString:"headerFooterPageTotal"], nil];
|
||||
[list addItemsWithTitles:items];
|
||||
|
||||
NS_ConvertUTF16toUTF8 currentStringUTF8(aCurrentString);
|
||||
|
@ -382,8 +404,9 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
[self addLabel:"optionsTitleMac" withFrame:NSMakeRect(0, 155, 151, 22)];
|
||||
|
||||
// "Print Selection Only"
|
||||
mPrintSelectionOnlyCheckbox = [self checkboxWithLabel:"selectionOnly"
|
||||
andFrame:NSMakeRect(156, 155, 0, 0)];
|
||||
mPrintSelectionOnlyCheckbox =
|
||||
[self checkboxWithLabel:"selectionOnly"
|
||||
andFrame:NSMakeRect(156, 155, 0, 0)];
|
||||
[mPrintSelectionOnlyCheckbox setEnabled:aHaveSelection];
|
||||
|
||||
if (mSettings->GetPrintSelectionOnly()) {
|
||||
|
@ -393,7 +416,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
[self addSubview:mPrintSelectionOnlyCheckbox];
|
||||
|
||||
// "Shrink To Fit"
|
||||
mShrinkToFitCheckbox = [self checkboxWithLabel:"shrinkToFit" andFrame:NSMakeRect(156, 133, 0, 0)];
|
||||
mShrinkToFitCheckbox = [self checkboxWithLabel:"shrinkToFit"
|
||||
andFrame:NSMakeRect(156, 133, 0, 0)];
|
||||
|
||||
bool shrinkToFit;
|
||||
mSettings->GetShrinkToFit(&shrinkToFit);
|
||||
|
@ -437,33 +461,39 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
nsString sel;
|
||||
|
||||
mSettings->GetHeaderStrLeft(sel);
|
||||
mHeaderLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22)
|
||||
selectedItem:sel];
|
||||
mHeaderLeftList =
|
||||
[self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22)
|
||||
selectedItem:sel];
|
||||
[self addSubview:mHeaderLeftList];
|
||||
|
||||
mSettings->GetHeaderStrCenter(sel);
|
||||
mHeaderCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22)
|
||||
selectedItem:sel];
|
||||
mHeaderCenterList =
|
||||
[self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22)
|
||||
selectedItem:sel];
|
||||
[self addSubview:mHeaderCenterList];
|
||||
|
||||
mSettings->GetHeaderStrRight(sel);
|
||||
mHeaderRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 44, 100, 22)
|
||||
selectedItem:sel];
|
||||
mHeaderRightList =
|
||||
[self headerFooterItemListWithFrame:NSMakeRect(356, 44, 100, 22)
|
||||
selectedItem:sel];
|
||||
[self addSubview:mHeaderRightList];
|
||||
|
||||
mSettings->GetFooterStrLeft(sel);
|
||||
mFooterLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 0, 100, 22)
|
||||
selectedItem:sel];
|
||||
mFooterLeftList =
|
||||
[self headerFooterItemListWithFrame:NSMakeRect(156, 0, 100, 22)
|
||||
selectedItem:sel];
|
||||
[self addSubview:mFooterLeftList];
|
||||
|
||||
mSettings->GetFooterStrCenter(sel);
|
||||
mFooterCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 0, 100, 22)
|
||||
selectedItem:sel];
|
||||
mFooterCenterList =
|
||||
[self headerFooterItemListWithFrame:NSMakeRect(256, 0, 100, 22)
|
||||
selectedItem:sel];
|
||||
[self addSubview:mFooterCenterList];
|
||||
|
||||
mSettings->GetFooterStrRight(sel);
|
||||
mFooterRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 0, 100, 22)
|
||||
selectedItem:sel];
|
||||
mFooterRightList =
|
||||
[self headerFooterItemListWithFrame:NSMakeRect(356, 0, 100, 22)
|
||||
selectedItem:sel];
|
||||
[self addSubview:mFooterRightList];
|
||||
}
|
||||
|
||||
|
@ -502,8 +532,9 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
- (NSString*)summaryValueForCheckbox:(NSButton*)aCheckbox {
|
||||
if (![aCheckbox isEnabled]) return [self localizedString:"summaryNAValue"];
|
||||
|
||||
return [aCheckbox state] == NSOnState ? [self localizedString:"summaryOnValue"]
|
||||
: [self localizedString:"summaryOffValue"];
|
||||
return [aCheckbox state] == NSOnState
|
||||
? [self localizedString:"summaryOnValue"]
|
||||
: [self localizedString:"summaryOffValue"];
|
||||
}
|
||||
|
||||
- (NSString*)headerSummaryValue {
|
||||
|
@ -513,7 +544,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
stringByAppendingString:
|
||||
[[mHeaderCenterList titleOfSelectedItem]
|
||||
stringByAppendingString:
|
||||
[@", " stringByAppendingString:[mHeaderRightList titleOfSelectedItem]]]]];
|
||||
[@", " stringByAppendingString:
|
||||
[mHeaderRightList titleOfSelectedItem]]]]];
|
||||
}
|
||||
|
||||
- (NSString*)footerSummaryValue {
|
||||
|
@ -523,43 +555,49 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
stringByAppendingString:
|
||||
[[mFooterCenterList titleOfSelectedItem]
|
||||
stringByAppendingString:
|
||||
[@", " stringByAppendingString:[mFooterRightList titleOfSelectedItem]]]]];
|
||||
[@", " stringByAppendingString:
|
||||
[mFooterRightList titleOfSelectedItem]]]]];
|
||||
}
|
||||
|
||||
- (NSArray*)localizedSummaryItems {
|
||||
return [NSArray
|
||||
arrayWithObjects:
|
||||
[NSDictionary
|
||||
dictionaryWithObjectsAndKeys:[self localizedString:"summarySelectionOnlyTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self
|
||||
summaryValueForCheckbox:mPrintSelectionOnlyCheckbox],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||
dictionaryWithObjectsAndKeys:
|
||||
[self localizedString:"summarySelectionOnlyTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self summaryValueForCheckbox:mPrintSelectionOnlyCheckbox],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[self localizedString:"summaryShrinkToFitTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self summaryValueForCheckbox:mShrinkToFitCheckbox],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
||||
nil],
|
||||
[NSDictionary
|
||||
dictionaryWithObjectsAndKeys:[self localizedString:"summaryShrinkToFitTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self summaryValueForCheckbox:mShrinkToFitCheckbox],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||
dictionaryWithObjectsAndKeys:
|
||||
[self localizedString:"summaryPrintBGColorsTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self summaryValueForCheckbox:mPrintBGColorsCheckbox],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||
[NSDictionary
|
||||
dictionaryWithObjectsAndKeys:[self localizedString:"summaryPrintBGColorsTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self summaryValueForCheckbox:mPrintBGColorsCheckbox],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||
[NSDictionary
|
||||
dictionaryWithObjectsAndKeys:[self localizedString:"summaryPrintBGImagesTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self summaryValueForCheckbox:mPrintBGImagesCheckbox],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:[self localizedString:"summaryHeaderTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self headerSummaryValue],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
||||
nil],
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:[self localizedString:"summaryFooterTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self footerSummaryValue],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
||||
nil],
|
||||
dictionaryWithObjectsAndKeys:
|
||||
[self localizedString:"summaryPrintBGImagesTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self summaryValueForCheckbox:mPrintBGImagesCheckbox],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[self localizedString:"summaryHeaderTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self headerSummaryValue],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
||||
nil],
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[self localizedString:"summaryFooterTitle"],
|
||||
NSPrintPanelAccessorySummaryItemNameKey,
|
||||
[self footerSummaryValue],
|
||||
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
||||
nil],
|
||||
nil];
|
||||
}
|
||||
|
||||
|
@ -569,11 +607,13 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
|||
|
||||
@implementation PrintPanelAccessoryController
|
||||
|
||||
- (id)initWithSettings:(nsIPrintSettings*)aSettings haveSelection:(bool)aHaveSelection {
|
||||
- (id)initWithSettings:(nsIPrintSettings*)aSettings
|
||||
haveSelection:(bool)aHaveSelection {
|
||||
[super initWithNibName:nil bundle:nil];
|
||||
|
||||
NSView* accView = [[PrintPanelAccessoryView alloc] initWithSettings:aSettings
|
||||
haveSelection:aHaveSelection];
|
||||
NSView* accView =
|
||||
[[PrintPanelAccessoryView alloc] initWithSettings:aSettings
|
||||
haveSelection:aHaveSelection];
|
||||
[self setView:accView];
|
||||
[accView release];
|
||||
return self;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче