forked from mirrors/gecko-dev
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:
parent
ccc3244a24
commit
9331b9fb07
126 changed files with 8385 additions and 5412 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
BasedOnStyle: Google
|
BasedOnStyle: Google
|
||||||
|
ColumnLimit: 80
|
||||||
|
|
||||||
# Prevent the loss of indentation with these macros
|
# Prevent the loss of indentation with these macros
|
||||||
MacroBlockBegin: "^\
|
MacroBlockBegin: "^\
|
||||||
|
|
|
||||||
|
|
@ -24,27 +24,32 @@ using namespace mozilla::a11y;
|
||||||
|
|
||||||
// xpcAccessibleMacNSObjectWrapper
|
// xpcAccessibleMacNSObjectWrapper
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(xpcAccessibleMacNSObjectWrapper, nsIAccessibleMacNSObjectWrapper)
|
NS_IMPL_ISUPPORTS(xpcAccessibleMacNSObjectWrapper,
|
||||||
|
nsIAccessibleMacNSObjectWrapper)
|
||||||
|
|
||||||
xpcAccessibleMacNSObjectWrapper::xpcAccessibleMacNSObjectWrapper(id aNativeObj)
|
xpcAccessibleMacNSObjectWrapper::xpcAccessibleMacNSObjectWrapper(id aNativeObj)
|
||||||
: mNativeObject(aNativeObj) {
|
: mNativeObject(aNativeObj) {
|
||||||
[mNativeObject retain];
|
[mNativeObject retain];
|
||||||
}
|
}
|
||||||
|
|
||||||
xpcAccessibleMacNSObjectWrapper::~xpcAccessibleMacNSObjectWrapper() { [mNativeObject release]; }
|
xpcAccessibleMacNSObjectWrapper::~xpcAccessibleMacNSObjectWrapper() {
|
||||||
|
[mNativeObject release];
|
||||||
|
}
|
||||||
|
|
||||||
id xpcAccessibleMacNSObjectWrapper::GetNativeObject() { return mNativeObject; }
|
id xpcAccessibleMacNSObjectWrapper::GetNativeObject() { return mNativeObject; }
|
||||||
|
|
||||||
// xpcAccessibleMacInterface
|
// xpcAccessibleMacInterface
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS_INHERITED(xpcAccessibleMacInterface, xpcAccessibleMacNSObjectWrapper,
|
NS_IMPL_ISUPPORTS_INHERITED(xpcAccessibleMacInterface,
|
||||||
|
xpcAccessibleMacNSObjectWrapper,
|
||||||
nsIAccessibleMacInterface)
|
nsIAccessibleMacInterface)
|
||||||
|
|
||||||
xpcAccessibleMacInterface::xpcAccessibleMacInterface(Accessible* aObj)
|
xpcAccessibleMacInterface::xpcAccessibleMacInterface(Accessible* aObj)
|
||||||
: xpcAccessibleMacNSObjectWrapper(GetNativeFromGeckoAccessible(aObj)) {}
|
: xpcAccessibleMacNSObjectWrapper(GetNativeFromGeckoAccessible(aObj)) {}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
xpcAccessibleMacInterface::GetAttributeNames(nsTArray<nsString>& aAttributeNames) {
|
xpcAccessibleMacInterface::GetAttributeNames(
|
||||||
|
nsTArray<nsString>& aAttributeNames) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
||||||
|
|
||||||
if (!mNativeObject || [mNativeObject isExpired]) {
|
if (!mNativeObject || [mNativeObject isExpired]) {
|
||||||
|
|
@ -63,14 +68,16 @@ xpcAccessibleMacInterface::GetAttributeNames(nsTArray<nsString>& aAttributeNames
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
xpcAccessibleMacInterface::GetParameterizedAttributeNames(nsTArray<nsString>& aAttributeNames) {
|
xpcAccessibleMacInterface::GetParameterizedAttributeNames(
|
||||||
|
nsTArray<nsString>& aAttributeNames) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
||||||
|
|
||||||
if (!mNativeObject || [mNativeObject isExpired]) {
|
if (!mNativeObject || [mNativeObject isExpired]) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NSString* name in [mNativeObject accessibilityParameterizedAttributeNames]) {
|
for (NSString* name in
|
||||||
|
[mNativeObject accessibilityParameterizedAttributeNames]) {
|
||||||
nsAutoString attribName;
|
nsAutoString attribName;
|
||||||
nsCocoaUtils::GetStringForNSString(name, attribName);
|
nsCocoaUtils::GetStringForNSString(name, attribName);
|
||||||
aAttributeNames.AppendElement(attribName);
|
aAttributeNames.AppendElement(attribName);
|
||||||
|
|
@ -117,7 +124,8 @@ xpcAccessibleMacInterface::PerformAction(const nsAString& aActionName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName, JSContext* aCx,
|
xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName,
|
||||||
|
JSContext* aCx,
|
||||||
JS::MutableHandleValue aResult) {
|
JS::MutableHandleValue aResult) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
||||||
|
|
||||||
|
|
@ -126,17 +134,20 @@ xpcAccessibleMacInterface::GetAttributeValue(const nsAString& aAttributeName, JS
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
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_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE)
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName, bool* aIsSettable) {
|
xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName,
|
||||||
|
bool* aIsSettable) {
|
||||||
NS_ENSURE_ARG_POINTER(aIsSettable);
|
NS_ENSURE_ARG_POINTER(aIsSettable);
|
||||||
|
|
||||||
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
||||||
if ([mNativeObject respondsToSelector:@selector(accessibilityIsAttributeSettable:)]) {
|
if ([mNativeObject
|
||||||
|
respondsToSelector:@selector(accessibilityIsAttributeSettable:)]) {
|
||||||
*aIsSettable = [mNativeObject accessibilityIsAttributeSettable:attribName];
|
*aIsSettable = [mNativeObject accessibilityIsAttributeSettable:attribName];
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -146,13 +157,15 @@ xpcAccessibleMacInterface::IsAttributeSettable(const nsAString& aAttributeName,
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
xpcAccessibleMacInterface::SetAttributeValue(const nsAString& aAttributeName,
|
xpcAccessibleMacInterface::SetAttributeValue(const nsAString& aAttributeName,
|
||||||
JS::HandleValue aAttributeValue, JSContext* aCx) {
|
JS::HandleValue aAttributeValue,
|
||||||
|
JSContext* aCx) {
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
id obj = JsValueToNSObject(aAttributeValue, aCx, &rv);
|
id obj = JsValueToNSObject(aAttributeValue, aCx, &rv);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
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.
|
// The NSObject has an attribute setter, call that.
|
||||||
[mNativeObject accessibilitySetValue:obj forAttribute:attribName];
|
[mNativeObject accessibilitySetValue:obj forAttribute:attribName];
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -162,29 +175,30 @@ xpcAccessibleMacInterface::SetAttributeValue(const nsAString& aAttributeName,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
xpcAccessibleMacInterface::GetParameterizedAttributeValue(const nsAString& aAttributeName,
|
xpcAccessibleMacInterface::GetParameterizedAttributeValue(
|
||||||
JS::HandleValue aParameter,
|
const nsAString& aAttributeName, JS::HandleValue aParameter, JSContext* aCx,
|
||||||
JSContext* aCx,
|
JS::MutableHandleValue aResult) {
|
||||||
JS::MutableHandleValue aResult) {
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
id paramObj = JsValueToNSObject(aParameter, aCx, &rv);
|
id paramObj = JsValueToNSObject(aParameter, aCx, &rv);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
NSString* attribName = nsCocoaUtils::ToNSString(aAttributeName);
|
||||||
return NSObjectToJsValue(
|
return NSObjectToJsValue([mNativeObject accessibilityAttributeValue:attribName
|
||||||
[mNativeObject accessibilityAttributeValue:attribName forParameter:paramObj], aCx, aResult);
|
forParameter:paramObj],
|
||||||
|
aCx, aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xpcAccessibleMacInterface::SupportsSelector(SEL aSelector) {
|
bool xpcAccessibleMacInterface::SupportsSelector(SEL aSelector) {
|
||||||
// return true if we have this selector, and if isAccessibilitySelectorAllowed
|
// return true if we have this selector, and if isAccessibilitySelectorAllowed
|
||||||
// is implemented too whether it is "allowed".
|
// is implemented too whether it is "allowed".
|
||||||
return [mNativeObject respondsToSelector:aSelector] &&
|
return [mNativeObject respondsToSelector:aSelector] &&
|
||||||
(![mNativeObject respondsToSelector:@selector(isAccessibilitySelectorAllowed:selector:)] ||
|
(![mNativeObject respondsToSelector:@selector
|
||||||
|
(isAccessibilitySelectorAllowed:selector:)] ||
|
||||||
[mNativeObject isAccessibilitySelectorAllowed:aSelector]);
|
[mNativeObject isAccessibilitySelectorAllowed:aSelector]);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
nsresult xpcAccessibleMacInterface::NSObjectToJsValue(
|
||||||
JS::MutableHandleValue aResult) {
|
id aObj, JSContext* aCx, JS::MutableHandleValue aResult) {
|
||||||
if (!aObj) {
|
if (!aObj) {
|
||||||
aResult.set(JS::NullValue());
|
aResult.set(JS::NullValue());
|
||||||
} else if ([aObj isKindOfClass:[NSString class]]) {
|
} else if ([aObj isKindOfClass:[NSString class]]) {
|
||||||
|
|
@ -201,7 +215,8 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!mozilla::dom::ToJSValue(aCx, [(NSNumber*)aObj doubleValue], aResult)) {
|
if (!mozilla::dom::ToJSValue(aCx, [(NSNumber*)aObj doubleValue],
|
||||||
|
aResult)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -209,18 +224,25 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
||||||
strcmp([(NSValue*)aObj objCType], @encode(NSPoint)) == 0) {
|
strcmp([(NSValue*)aObj objCType], @encode(NSPoint)) == 0) {
|
||||||
NSPoint point = [(NSValue*)aObj pointValue];
|
NSPoint point = [(NSValue*)aObj pointValue];
|
||||||
return NSObjectToJsValue(
|
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]] &&
|
} else if ([aObj isKindOfClass:[NSValue class]] &&
|
||||||
strcmp([(NSValue*)aObj objCType], @encode(NSSize)) == 0) {
|
strcmp([(NSValue*)aObj objCType], @encode(NSSize)) == 0) {
|
||||||
NSSize size = [(NSValue*)aObj sizeValue];
|
NSSize size = [(NSValue*)aObj sizeValue];
|
||||||
return NSObjectToJsValue(
|
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]] &&
|
} else if ([aObj isKindOfClass:[NSValue class]] &&
|
||||||
strcmp([(NSValue*)aObj objCType], @encode(NSRange)) == 0) {
|
strcmp([(NSValue*)aObj objCType], @encode(NSRange)) == 0) {
|
||||||
NSRange range = [(NSValue*)aObj rangeValue];
|
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]] &&
|
} else if ([aObj isKindOfClass:[NSValue class]] &&
|
||||||
strcmp([(NSValue*)aObj objCType], @encode(NSRect)) == 0) {
|
strcmp([(NSValue*)aObj objCType], @encode(NSRect)) == 0) {
|
||||||
NSRect rect = [(NSValue*)aObj rectValue];
|
NSRect rect = [(NSValue*)aObj rectValue];
|
||||||
|
|
@ -263,14 +285,18 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
||||||
|
|
||||||
[attrStr
|
[attrStr
|
||||||
enumerateAttributesInRange:NSMakeRange(0, [attrStr length])
|
enumerateAttributesInRange:NSMakeRange(0, [attrStr length])
|
||||||
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
options:
|
||||||
usingBlock:^(NSDictionary* attributes, NSRange range, BOOL* stop) {
|
NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
||||||
NSString* str = [[attrStr string] substringWithRange:range];
|
usingBlock:^(NSDictionary* attributes, NSRange range,
|
||||||
|
BOOL* stop) {
|
||||||
|
NSString* str =
|
||||||
|
[[attrStr string] substringWithRange:range];
|
||||||
if (!str || !attributes) {
|
if (!str || !attributes) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableDictionary* attrRun = [attributes mutableCopy];
|
NSMutableDictionary* attrRun =
|
||||||
|
[attributes mutableCopy];
|
||||||
attrRun[@"string"] = str;
|
attrRun[@"string"] = str;
|
||||||
|
|
||||||
[attrRunArray addObject:attrRun];
|
[attrRunArray addObject:attrRun];
|
||||||
|
|
@ -282,28 +308,34 @@ nsresult xpcAccessibleMacInterface::NSObjectToJsValue(id aObj, JSContext* aCx,
|
||||||
return NSObjectToJsValue(attrRunArray, aCx, aResult);
|
return NSObjectToJsValue(attrRunArray, aCx, aResult);
|
||||||
} else if (CFGetTypeID(aObj) == CGColorGetTypeID()) {
|
} else if (CFGetTypeID(aObj) == CGColorGetTypeID()) {
|
||||||
const CGFloat* components = CGColorGetComponents((CGColorRef)aObj);
|
const CGFloat* components = CGColorGetComponents((CGColorRef)aObj);
|
||||||
NSString* hexString =
|
NSString* hexString = [NSString
|
||||||
[NSString stringWithFormat:@"#%02x%02x%02x", (int)(components[0] * 0xff),
|
stringWithFormat:@"#%02x%02x%02x", (int)(components[0] * 0xff),
|
||||||
(int)(components[1] * 0xff), (int)(components[2] * 0xff)];
|
(int)(components[1] * 0xff),
|
||||||
|
(int)(components[2] * 0xff)];
|
||||||
return NSObjectToJsValue(hexString, aCx, aResult);
|
return NSObjectToJsValue(hexString, aCx, aResult);
|
||||||
} else if ([aObj respondsToSelector:@selector(isAccessibilityElement)]) {
|
} else if ([aObj respondsToSelector:@selector(isAccessibilityElement)]) {
|
||||||
// We expect all of our accessibility objects to implement isAccessibilityElement
|
// We expect all of our accessibility objects to implement
|
||||||
// at the very least. If it is implemented we will assume its an accessibility object.
|
// isAccessibilityElement at the very least. If it is implemented we will
|
||||||
nsCOMPtr<nsIAccessibleMacInterface> obj = new xpcAccessibleMacInterface(aObj);
|
// assume its an accessibility object.
|
||||||
return nsContentUtils::WrapNative(aCx, obj, &NS_GET_IID(nsIAccessibleMacInterface), aResult);
|
nsCOMPtr<nsIAccessibleMacInterface> obj =
|
||||||
|
new xpcAccessibleMacInterface(aObj);
|
||||||
|
return nsContentUtils::WrapNative(
|
||||||
|
aCx, obj, &NS_GET_IID(nsIAccessibleMacInterface), aResult);
|
||||||
} else {
|
} else {
|
||||||
// If this is any other kind of NSObject, just wrap it and return it.
|
// 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
|
// It will be opaque and immutable on the JS side, but it can be
|
||||||
// brought back to us in an argument.
|
// brought back to us in an argument.
|
||||||
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> obj = new xpcAccessibleMacNSObjectWrapper(aObj);
|
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> obj =
|
||||||
return nsContentUtils::WrapNative(aCx, obj, &NS_GET_IID(nsIAccessibleMacNSObjectWrapper),
|
new xpcAccessibleMacNSObjectWrapper(aObj);
|
||||||
aResult);
|
return nsContentUtils::WrapNative(
|
||||||
|
aCx, obj, &NS_GET_IID(nsIAccessibleMacNSObjectWrapper), aResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContext* aCx,
|
id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue,
|
||||||
|
JSContext* aCx,
|
||||||
nsresult* aResult) {
|
nsresult* aResult) {
|
||||||
*aResult = NS_OK;
|
*aResult = NS_OK;
|
||||||
if (aValue.isInt32()) {
|
if (aValue.isInt32()) {
|
||||||
|
|
@ -363,9 +395,11 @@ id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContex
|
||||||
nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
|
nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
|
||||||
|
|
||||||
nsCOMPtr<nsIXPConnectWrappedNative> wrappedObj;
|
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);
|
NS_ENSURE_SUCCESS(rv, nil);
|
||||||
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> macObjIface = do_QueryInterface(wrappedObj->Native());
|
nsCOMPtr<nsIAccessibleMacNSObjectWrapper> macObjIface =
|
||||||
|
do_QueryInterface(wrappedObj->Native());
|
||||||
return macObjIface->GetNativeObject();
|
return macObjIface->GetNativeObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,7 +407,8 @@ id xpcAccessibleMacInterface::JsValueToNSObject(JS::HandleValue aValue, JSContex
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject, JSContext* aCx,
|
id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject,
|
||||||
|
JSContext* aCx,
|
||||||
nsresult* aResult) {
|
nsresult* aResult) {
|
||||||
*aResult = NS_ERROR_FAILURE;
|
*aResult = NS_ERROR_FAILURE;
|
||||||
JS::RootedValue valueTypeValue(aCx);
|
JS::RootedValue valueTypeValue(aCx);
|
||||||
|
|
@ -421,14 +456,15 @@ id xpcAccessibleMacInterface::JsValueToNSValue(JS::HandleObject aObject, JSConte
|
||||||
}
|
}
|
||||||
|
|
||||||
*aResult = NS_OK;
|
*aResult = NS_OK;
|
||||||
return [NSValue valueWithRange:NSMakeRange(locationValue.toInt32(), lengthValue.toInt32())];
|
return [NSValue valueWithRange:NSMakeRange(locationValue.toInt32(),
|
||||||
|
lengthValue.toInt32())];
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
id xpcAccessibleMacInterface::JsValueToSpecifiedNSObject(JS::HandleObject aObject, JSContext* aCx,
|
id xpcAccessibleMacInterface::JsValueToSpecifiedNSObject(
|
||||||
nsresult* aResult) {
|
JS::HandleObject aObject, JSContext* aCx, nsresult* aResult) {
|
||||||
*aResult = NS_ERROR_FAILURE;
|
*aResult = NS_ERROR_FAILURE;
|
||||||
JS::RootedValue objectTypeValue(aCx);
|
JS::RootedValue objectTypeValue(aCx);
|
||||||
if (!JS_GetProperty(aCx, aObject, "objectType", &objectTypeValue)) {
|
if (!JS_GetProperty(aCx, aObject, "objectType", &objectTypeValue)) {
|
||||||
|
|
@ -509,7 +545,8 @@ xpcAccessibleMacEvent::~xpcAccessibleMacEvent() {
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
xpcAccessibleMacEvent::GetMacIface(nsIAccessibleMacInterface** aMacIface) {
|
xpcAccessibleMacEvent::GetMacIface(nsIAccessibleMacInterface** aMacIface) {
|
||||||
RefPtr<xpcAccessibleMacInterface> macIface = new xpcAccessibleMacInterface(mNativeObject);
|
RefPtr<xpcAccessibleMacInterface> macIface =
|
||||||
|
new xpcAccessibleMacInterface(mNativeObject);
|
||||||
macIface.forget(aMacIface);
|
macIface.forget(aMacIface);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -519,20 +556,25 @@ xpcAccessibleMacEvent::GetData(JSContext* aCx, JS::MutableHandleValue aData) {
|
||||||
return xpcAccessibleMacInterface::NSObjectToJsValue(mData, aCx, aData);
|
return xpcAccessibleMacInterface::NSObjectToJsValue(mData, aCx, aData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xpcAccessibleMacEvent::FireEvent(id aNativeObj, id aNotification, id aUserInfo) {
|
void xpcAccessibleMacEvent::FireEvent(id aNativeObj, id aNotification,
|
||||||
if (nsCOMPtr<nsIObserverService> obsService = services::GetObserverService()) {
|
id aUserInfo) {
|
||||||
|
if (nsCOMPtr<nsIObserverService> obsService =
|
||||||
|
services::GetObserverService()) {
|
||||||
nsCOMPtr<nsISimpleEnumerator> observers;
|
nsCOMPtr<nsISimpleEnumerator> observers;
|
||||||
// Get all observers for the mac event topic.
|
// 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) {
|
if (observers) {
|
||||||
bool hasObservers = false;
|
bool hasObservers = false;
|
||||||
observers->HasMoreElements(&hasObservers);
|
observers->HasMoreElements(&hasObservers);
|
||||||
// If we have observers, notify them.
|
// If we have observers, notify them.
|
||||||
if (hasObservers) {
|
if (hasObservers) {
|
||||||
nsCOMPtr<nsIAccessibleMacEvent> xpcIface = new xpcAccessibleMacEvent(aNativeObj, aUserInfo);
|
nsCOMPtr<nsIAccessibleMacEvent> xpcIface =
|
||||||
|
new xpcAccessibleMacEvent(aNativeObj, aUserInfo);
|
||||||
nsAutoString notificationStr;
|
nsAutoString notificationStr;
|
||||||
nsCocoaUtils::GetStringForNSString(aNotification, 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
|
NS_IMETHODIMP
|
||||||
nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
|
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:
|
// To retrieve a secret, we create a CFDictionary of the form:
|
||||||
// { class: generic password,
|
// { class: generic password,
|
||||||
// service: the given service name
|
// 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
|
// matching the given service and account names. We then extract the data
|
||||||
// (i.e. the secret) and return it.
|
// (i.e. the secret) and return it.
|
||||||
NSDictionary* searchDictionary = @{
|
NSDictionary* searchDictionary = @{
|
||||||
(__bridge NSString*)kSecClass : (__bridge NSString*)kSecClassGenericPassword,
|
(__bridge NSString*)
|
||||||
(__bridge NSString*)kSecAttrService : nsCocoaUtils::ToNSString(aServiceName),
|
kSecClass : (__bridge NSString*)kSecClassGenericPassword,
|
||||||
(__bridge NSString*)kSecAttrAccount : nsCocoaUtils::ToNSString(aAccountName),
|
(__bridge NSString*)
|
||||||
|
kSecAttrService : nsCocoaUtils::ToNSString(aServiceName),
|
||||||
|
(__bridge NSString*)
|
||||||
|
kSecAttrAccount : nsCocoaUtils::ToNSString(aAccountName),
|
||||||
(__bridge NSString*)kSecMatchLimit : (__bridge NSString*)kSecMatchLimitOne,
|
(__bridge NSString*)kSecMatchLimit : (__bridge NSString*)kSecMatchLimitOne,
|
||||||
(__bridge NSString*)kSecReturnAttributes : @YES,
|
(__bridge NSString*)kSecReturnAttributes : @YES,
|
||||||
(__bridge NSString*)kSecReturnData : @YES
|
(__bridge NSString*)kSecReturnData : @YES
|
||||||
|
|
@ -41,9 +45,11 @@ nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
|
||||||
|
|
||||||
CFTypeRef item;
|
CFTypeRef item;
|
||||||
// https://developer.apple.com/documentation/security/1398306-secitemcopymatching
|
// 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) {
|
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;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
NSDictionary* resultDict = [(__bridge NSDictionary*)item autorelease];
|
NSDictionary* resultDict = [(__bridge NSDictionary*)item autorelease];
|
||||||
|
|
@ -53,8 +59,8 @@ nsKeychainMigrationUtils::GetGenericPassword(const nsACString& aServiceName,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
if ([secret length] != 0) {
|
if ([secret length] != 0) {
|
||||||
// We assume that the data is UTF-8 encoded since that seems to be common and
|
// We assume that the data is UTF-8 encoded since that seems to be common
|
||||||
// Keychain Access shows it with that encoding.
|
// and Keychain Access shows it with that encoding.
|
||||||
aKey.Assign(reinterpret_cast<const char*>([secret bytes]), [secret length]);
|
aKey.Assign(reinterpret_cast<const char*>([secret bytes]), [secret length]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,27 +18,31 @@ using namespace mozilla::widget;
|
||||||
|
|
||||||
static const int kSystemDefinedEventMediaKeysSubtype = 8;
|
static const int kSystemDefinedEventMediaKeysSubtype = 8;
|
||||||
|
|
||||||
static void SendFakeEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource, int aKeyData) {
|
static void SendFakeEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
||||||
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeSystemDefined
|
int aKeyData) {
|
||||||
location:NSZeroPoint
|
NSEvent* event =
|
||||||
modifierFlags:0
|
[NSEvent otherEventWithType:NSEventTypeSystemDefined
|
||||||
timestamp:0
|
location:NSZeroPoint
|
||||||
windowNumber:0
|
modifierFlags:0
|
||||||
context:nil
|
timestamp:0
|
||||||
subtype:kSystemDefinedEventMediaKeysSubtype
|
windowNumber:0
|
||||||
data1:aKeyData
|
context:nil
|
||||||
data2:0];
|
subtype:kSystemDefinedEventMediaKeysSubtype
|
||||||
aSource->EventTapCallback(nullptr, static_cast<CGEventType>(0), [event CGEvent], aSource.get());
|
data1:aKeyData
|
||||||
|
data2:0];
|
||||||
|
aSource->EventTapCallback(nullptr, static_cast<CGEventType>(0),
|
||||||
|
[event CGEvent], aSource.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NotifyFakeNonMediaKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
static void NotifyFakeNonMediaKey(
|
||||||
bool aIsKeyPressed) {
|
RefPtr<MediaHardwareKeysEventSourceMac>& aSource, bool aIsKeyPressed) {
|
||||||
int keyData = 0 | ((aIsKeyPressed ? 0xA : 0xB) << 8);
|
int keyData = 0 | ((aIsKeyPressed ? 0xA : 0xB) << 8);
|
||||||
SendFakeEvent(aSource, keyData);
|
SendFakeEvent(aSource, keyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NotifyFakeMediaControlKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
static void NotifyFakeMediaControlKey(
|
||||||
MediaControlKey aEvent, bool aIsKeyPressed) {
|
RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent,
|
||||||
|
bool aIsKeyPressed) {
|
||||||
int keyData = 0;
|
int keyData = 0;
|
||||||
if (aEvent == MediaControlKey::Playpause) {
|
if (aEvent == MediaControlKey::Playpause) {
|
||||||
keyData = NX_KEYTYPE_PLAY << 16;
|
keyData = NX_KEYTYPE_PLAY << 16;
|
||||||
|
|
@ -51,27 +55,30 @@ static void NotifyFakeMediaControlKey(RefPtr<MediaHardwareKeysEventSourceMac>& a
|
||||||
SendFakeEvent(aSource, keyData);
|
SendFakeEvent(aSource, keyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NotifyKeyPressedMediaKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
static void NotifyKeyPressedMediaKey(
|
||||||
MediaControlKey aEvent) {
|
RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent) {
|
||||||
NotifyFakeMediaControlKey(aSource, aEvent, true /* key pressed */);
|
NotifyFakeMediaControlKey(aSource, aEvent, true /* key pressed */);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NotifyKeyReleasedMediaKeysEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
|
static void NotifyKeyReleasedMediaKeysEvent(
|
||||||
MediaControlKey aEvent) {
|
RefPtr<MediaHardwareKeysEventSourceMac>& aSource, MediaControlKey aEvent) {
|
||||||
NotifyFakeMediaControlKey(aSource, aEvent, false /* key released */);
|
NotifyFakeMediaControlKey(aSource, aEvent, false /* key released */);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NotifyKeyPressedNonMediaKeysEvents(RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
|
static void NotifyKeyPressedNonMediaKeysEvents(
|
||||||
|
RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
|
||||||
NotifyFakeNonMediaKey(aSource, true /* key pressed */);
|
NotifyFakeNonMediaKey(aSource, true /* key pressed */);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NotifyKeyReleasedNonMediaKeysEvents(RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
|
static void NotifyKeyReleasedNonMediaKeysEvents(
|
||||||
|
RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
|
||||||
NotifyFakeNonMediaKey(aSource, false /* key released */);
|
NotifyFakeNonMediaKey(aSource, false /* key released */);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent)
|
TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent)
|
||||||
{
|
{
|
||||||
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
|
RefPtr<MediaHardwareKeysEventSourceMac> source =
|
||||||
|
new MediaHardwareKeysEventSourceMac();
|
||||||
ASSERT_TRUE(source->GetListenersNum() == 0);
|
ASSERT_TRUE(source->GetListenersNum() == 0);
|
||||||
|
|
||||||
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
||||||
|
|
@ -94,7 +101,8 @@ TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent)
|
||||||
|
|
||||||
TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent)
|
TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent)
|
||||||
{
|
{
|
||||||
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
|
RefPtr<MediaHardwareKeysEventSourceMac> source =
|
||||||
|
new MediaHardwareKeysEventSourceMac();
|
||||||
ASSERT_TRUE(source->GetListenersNum() == 0);
|
ASSERT_TRUE(source->GetListenersNum() == 0);
|
||||||
|
|
||||||
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
||||||
|
|
@ -117,7 +125,8 @@ TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent)
|
||||||
|
|
||||||
TEST(MediaHardwareKeysEventSourceMac, TestNonMediaKeysEvent)
|
TEST(MediaHardwareKeysEventSourceMac, TestNonMediaKeysEvent)
|
||||||
{
|
{
|
||||||
RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
|
RefPtr<MediaHardwareKeysEventSourceMac> source =
|
||||||
|
new MediaHardwareKeysEventSourceMac();
|
||||||
ASSERT_TRUE(source->GetListenersNum() == 0);
|
ASSERT_TRUE(source->GetListenersNum() == 0);
|
||||||
|
|
||||||
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,8 @@ TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestMediaCenterPrevNextEvent)
|
||||||
|
|
||||||
ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Nexttrack));
|
ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Nexttrack));
|
||||||
|
|
||||||
MediaCenterEventHandler previousHandler = source->CreatePreviousTrackHandler();
|
MediaCenterEventHandler previousHandler =
|
||||||
|
source->CreatePreviousTrackHandler();
|
||||||
|
|
||||||
previousHandler(nil);
|
previousHandler(nil);
|
||||||
|
|
||||||
|
|
@ -153,9 +154,12 @@ TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestSetMetadata)
|
||||||
// before checking the result.
|
// before checking the result.
|
||||||
PR_Sleep(PR_SecondsToInterval(1));
|
PR_Sleep(PR_SecondsToInterval(1));
|
||||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyTitle] isEqualToString:@"MediaPlayback"]);
|
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyTitle]
|
||||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyArtist] isEqualToString:@"Firefox"]);
|
isEqualToString:@"MediaPlayback"]);
|
||||||
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyAlbumTitle] isEqualToString:@"Mozilla"]);
|
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyArtist]
|
||||||
|
isEqualToString:@"Firefox"]);
|
||||||
|
ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyAlbumTitle]
|
||||||
|
isEqualToString:@"Mozilla"]);
|
||||||
|
|
||||||
source->Close();
|
source->Close();
|
||||||
PR_Sleep(PR_SecondsToInterval(1));
|
PR_Sleep(PR_SecondsToInterval(1));
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,13 @@ using namespace webrtc;
|
||||||
using namespace videocapturemodule;
|
using namespace videocapturemodule;
|
||||||
|
|
||||||
static NSArray* camera_presets = @[
|
static NSArray* camera_presets = @[
|
||||||
AVCaptureSessionPreset352x288, AVCaptureSessionPreset640x480, AVCaptureSessionPreset1280x720
|
AVCaptureSessionPreset352x288, AVCaptureSessionPreset640x480,
|
||||||
|
AVCaptureSessionPreset1280x720
|
||||||
];
|
];
|
||||||
|
|
||||||
#define IOS_UNSUPPORTED() \
|
#define IOS_UNSUPPORTED() \
|
||||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << " is not supported on the iOS platform."; \
|
RTC_LOG(LS_ERROR) << __FUNCTION__ \
|
||||||
|
<< " is not supported on the iOS platform."; \
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
|
VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
|
||||||
|
|
@ -60,7 +62,8 @@ int32_t DeviceInfoIos::Init() {
|
||||||
for (NSString* preset in camera_presets) {
|
for (NSString* preset in camera_presets) {
|
||||||
BOOL support = [avDevice supportsAVCaptureSessionPreset:preset];
|
BOOL support = [avDevice supportsAVCaptureSessionPreset:preset];
|
||||||
if (support) {
|
if (support) {
|
||||||
VideoCaptureCapability capability = [DeviceInfoIosObjC capabilityForPreset:preset];
|
VideoCaptureCapability capability =
|
||||||
|
[DeviceInfoIosObjC capabilityForPreset:preset];
|
||||||
capabilityVector.push_back(capability);
|
capabilityVector.push_back(capability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,31 +76,36 @@ int32_t DeviceInfoIos::Init() {
|
||||||
}
|
}
|
||||||
std::string deviceIdCopy(deviceId);
|
std::string deviceIdCopy(deviceId);
|
||||||
std::pair<std::string, VideoCaptureCapabilities> mapPair =
|
std::pair<std::string, VideoCaptureCapabilities> mapPair =
|
||||||
std::pair<std::string, VideoCaptureCapabilities>(deviceIdCopy, capabilityVector);
|
std::pair<std::string, VideoCaptureCapabilities>(deviceIdCopy,
|
||||||
|
capabilityVector);
|
||||||
_capabilitiesMap.insert(mapPair);
|
_capabilitiesMap.insert(mapPair);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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,
|
int32_t DeviceInfoIos::GetDeviceName(
|
||||||
uint32_t deviceNameUTF8Length, char* deviceUniqueIdUTF8,
|
uint32_t deviceNumber, char* deviceNameUTF8, uint32_t deviceNameUTF8Length,
|
||||||
uint32_t deviceUniqueIdUTF8Length, char* productUniqueIdUTF8,
|
char* deviceUniqueIdUTF8, uint32_t deviceUniqueIdUTF8Length,
|
||||||
uint32_t productUniqueIdUTF8Length, pid_t* pid) {
|
char* productUniqueIdUTF8, uint32_t productUniqueIdUTF8Length, pid_t* pid) {
|
||||||
if (deviceNumber >= NumberOfDevices()) {
|
if (deviceNumber >= NumberOfDevices()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* deviceName = [DeviceInfoIosObjC deviceNameForIndex:deviceNumber];
|
NSString* deviceName = [DeviceInfoIosObjC deviceNameForIndex:deviceNumber];
|
||||||
|
|
||||||
NSString* deviceUniqueId = [DeviceInfoIosObjC deviceUniqueIdForIndex:deviceNumber];
|
NSString* deviceUniqueId =
|
||||||
|
[DeviceInfoIosObjC deviceUniqueIdForIndex:deviceNumber];
|
||||||
|
|
||||||
strncpy(deviceNameUTF8, [deviceName UTF8String], deviceNameUTF8Length);
|
strncpy(deviceNameUTF8, [deviceName UTF8String], deviceNameUTF8Length);
|
||||||
deviceNameUTF8[deviceNameUTF8Length - 1] = '\0';
|
deviceNameUTF8[deviceNameUTF8Length - 1] = '\0';
|
||||||
|
|
||||||
strncpy(deviceUniqueIdUTF8, deviceUniqueId.UTF8String, deviceUniqueIdUTF8Length);
|
strncpy(deviceUniqueIdUTF8, deviceUniqueId.UTF8String,
|
||||||
|
deviceUniqueIdUTF8Length);
|
||||||
deviceUniqueIdUTF8[deviceUniqueIdUTF8Length - 1] = '\0';
|
deviceUniqueIdUTF8[deviceUniqueIdUTF8Length - 1] = '\0';
|
||||||
|
|
||||||
if (productUniqueIdUTF8) {
|
if (productUniqueIdUTF8) {
|
||||||
|
|
@ -140,14 +148,14 @@ int32_t DeviceInfoIos::GetCapability(const char* deviceUniqueIdUTF8,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t DeviceInfoIos::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
|
int32_t DeviceInfoIos::DisplayCaptureSettingsDialogBox(
|
||||||
const char* dialogTitleUTF8,
|
const char* deviceUniqueIdUTF8, const char* dialogTitleUTF8,
|
||||||
void* parentWindow, uint32_t positionX,
|
void* parentWindow, uint32_t positionX, uint32_t positionY) {
|
||||||
uint32_t positionY) {
|
|
||||||
IOS_UNSUPPORTED();
|
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) {
|
if (strcmp(deviceUniqueIdUTF8, "Front Camera") == 0) {
|
||||||
orientation = kVideoRotation_0;
|
orientation = kVideoRotation_0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,14 @@
|
||||||
|
|
||||||
namespace webrtc::videocapturemodule {
|
namespace webrtc::videocapturemodule {
|
||||||
/* static */
|
/* static */
|
||||||
int32_t DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(Float64 aRate) {
|
int32_t DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
|
||||||
|
Float64 aRate) {
|
||||||
return static_cast<int32_t>(aRate);
|
return static_cast<int32_t>(aRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(FourCharCode aCode) {
|
webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(
|
||||||
|
FourCharCode aCode) {
|
||||||
switch (aCode) {
|
switch (aCode) {
|
||||||
case kCVPixelFormatType_420YpCbCr8Planar:
|
case kCVPixelFormatType_420YpCbCr8Planar:
|
||||||
case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
|
case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
|
||||||
|
|
@ -57,11 +59,14 @@ webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(FourCharCode
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceInfoAvFoundation::DeviceInfoAvFoundation()
|
DeviceInfoAvFoundation::DeviceInfoAvFoundation()
|
||||||
: mInvalidateCapabilities(false), mDeviceChangeCaptureInfo([[DeviceInfoIosObjC alloc] init]) {
|
: mInvalidateCapabilities(false),
|
||||||
|
mDeviceChangeCaptureInfo([[DeviceInfoIosObjC alloc] init]) {
|
||||||
[mDeviceChangeCaptureInfo registerOwner:this];
|
[mDeviceChangeCaptureInfo registerOwner:this];
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceInfoAvFoundation::~DeviceInfoAvFoundation() { [mDeviceChangeCaptureInfo registerOwner:nil]; }
|
DeviceInfoAvFoundation::~DeviceInfoAvFoundation() {
|
||||||
|
[mDeviceChangeCaptureInfo registerOwner:nil];
|
||||||
|
}
|
||||||
|
|
||||||
void DeviceInfoAvFoundation::DeviceChange() {
|
void DeviceInfoAvFoundation::DeviceChange() {
|
||||||
mInvalidateCapabilities = true;
|
mInvalidateCapabilities = true;
|
||||||
|
|
@ -74,12 +79,11 @@ uint32_t DeviceInfoAvFoundation::NumberOfDevices() {
|
||||||
return mDevicesAndCapabilities.size();
|
return mDevicesAndCapabilities.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t DeviceInfoAvFoundation::GetDeviceName(uint32_t aDeviceNumber, char* aDeviceNameUTF8,
|
int32_t DeviceInfoAvFoundation::GetDeviceName(
|
||||||
uint32_t aDeviceNameLength, char* aDeviceUniqueIdUTF8,
|
uint32_t aDeviceNumber, char* aDeviceNameUTF8, uint32_t aDeviceNameLength,
|
||||||
uint32_t aDeviceUniqueIdUTF8Length,
|
char* aDeviceUniqueIdUTF8, uint32_t aDeviceUniqueIdUTF8Length,
|
||||||
char* /* aProductUniqueIdUTF8 */,
|
char* /* aProductUniqueIdUTF8 */, uint32_t /* aProductUniqueIdUTF8Length */,
|
||||||
uint32_t /* aProductUniqueIdUTF8Length */,
|
pid_t* /* aPid */) {
|
||||||
pid_t* /* aPid */) {
|
|
||||||
RTC_DCHECK_RUN_ON(&mChecker);
|
RTC_DCHECK_RUN_ON(&mChecker);
|
||||||
// Don't EnsureCapabilitiesMap() here, since:
|
// Don't EnsureCapabilitiesMap() here, since:
|
||||||
// 1) That might invalidate the capabilities map
|
// 1) That might invalidate the capabilities map
|
||||||
|
|
@ -100,7 +104,8 @@ int32_t DeviceInfoAvFoundation::GetDeviceName(uint32_t aDeviceNumber, char* aDev
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t DeviceInfoAvFoundation::NumberOfCapabilities(const char* aDeviceUniqueIdUTF8) {
|
int32_t DeviceInfoAvFoundation::NumberOfCapabilities(
|
||||||
|
const char* aDeviceUniqueIdUTF8) {
|
||||||
RTC_DCHECK_RUN_ON(&mChecker);
|
RTC_DCHECK_RUN_ON(&mChecker);
|
||||||
|
|
||||||
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
||||||
|
|
@ -113,9 +118,9 @@ int32_t DeviceInfoAvFoundation::NumberOfCapabilities(const char* aDeviceUniqueId
|
||||||
return static_cast<int32_t>(capabilities.size());
|
return static_cast<int32_t>(capabilities.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t DeviceInfoAvFoundation::GetCapability(const char* aDeviceUniqueIdUTF8,
|
int32_t DeviceInfoAvFoundation::GetCapability(
|
||||||
const uint32_t aDeviceCapabilityNumber,
|
const char* aDeviceUniqueIdUTF8, const uint32_t aDeviceCapabilityNumber,
|
||||||
VideoCaptureCapability& aCapability) {
|
VideoCaptureCapability& aCapability) {
|
||||||
RTC_DCHECK_RUN_ON(&mChecker);
|
RTC_DCHECK_RUN_ON(&mChecker);
|
||||||
|
|
||||||
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
||||||
|
|
@ -133,7 +138,8 @@ int32_t DeviceInfoAvFoundation::GetCapability(const char* aDeviceUniqueIdUTF8,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdUTF8) {
|
int32_t DeviceInfoAvFoundation::CreateCapabilityMap(
|
||||||
|
const char* aDeviceUniqueIdUTF8) {
|
||||||
RTC_DCHECK_RUN_ON(&mChecker);
|
RTC_DCHECK_RUN_ON(&mChecker);
|
||||||
|
|
||||||
const size_t deviceUniqueIdUTF8Length = strlen(aDeviceUniqueIdUTF8);
|
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";
|
RTC_LOG(LS_INFO) << "Device name too long";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device " << aDeviceUniqueIdUTF8;
|
RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device "
|
||||||
|
<< aDeviceUniqueIdUTF8;
|
||||||
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
std::string deviceUniqueId(aDeviceUniqueIdUTF8);
|
||||||
const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
|
const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
|
||||||
if (!tup) {
|
if (!tup) {
|
||||||
|
|
@ -151,16 +158,18 @@ int32_t DeviceInfoAvFoundation::CreateCapabilityMap(const char* aDeviceUniqueIdU
|
||||||
|
|
||||||
// Store the new used device name
|
// Store the new used device name
|
||||||
_lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
|
_lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
|
||||||
_lastUsedDeviceName =
|
_lastUsedDeviceName = static_cast<char*>(
|
||||||
static_cast<char*>(realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
|
realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
|
||||||
memcpy(_lastUsedDeviceName, aDeviceUniqueIdUTF8, _lastUsedDeviceNameLength + 1);
|
memcpy(_lastUsedDeviceName, aDeviceUniqueIdUTF8,
|
||||||
|
_lastUsedDeviceNameLength + 1);
|
||||||
|
|
||||||
const auto& [_, __, capabilities] = *tup;
|
const auto& [_, __, capabilities] = *tup;
|
||||||
_captureCapabilities = capabilities;
|
_captureCapabilities = capabilities;
|
||||||
return static_cast<int32_t>(_captureCapabilities.size());
|
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>* {
|
-> const std::tuple<std::string, std::string, VideoCaptureCapabilities>* {
|
||||||
RTC_DCHECK_RUN_ON(&mChecker);
|
RTC_DCHECK_RUN_ON(&mChecker);
|
||||||
for (const auto& tup : mDevicesAndCapabilities) {
|
for (const auto& tup : mDevicesAndCapabilities) {
|
||||||
|
|
@ -185,13 +194,14 @@ void DeviceInfoAvFoundation::EnsureCapabilitiesMap() {
|
||||||
for (AVCaptureDevice* device in [RTCCameraVideoCapturer captureDevices]) {
|
for (AVCaptureDevice* device in [RTCCameraVideoCapturer captureDevices]) {
|
||||||
std::string uniqueId = [NSString stdStringForString:device.uniqueID];
|
std::string uniqueId = [NSString stdStringForString:device.uniqueID];
|
||||||
std::string name = [NSString stdStringForString:device.localizedName];
|
std::string name = [NSString stdStringForString:device.localizedName];
|
||||||
auto& [_, __, capabilities] =
|
auto& [_, __, capabilities] = mDevicesAndCapabilities.emplace_back(
|
||||||
mDevicesAndCapabilities.emplace_back(uniqueId, name, VideoCaptureCapabilities());
|
uniqueId, name, VideoCaptureCapabilities());
|
||||||
|
|
||||||
for (AVCaptureDeviceFormat* format in
|
for (AVCaptureDeviceFormat* format in
|
||||||
[RTCCameraVideoCapturer supportedFormatsForDevice:device]) {
|
[RTCCameraVideoCapturer supportedFormatsForDevice:device]) {
|
||||||
VideoCaptureCapability cap;
|
VideoCaptureCapability cap;
|
||||||
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(format.formatDescription);
|
FourCharCode fourcc =
|
||||||
|
CMFormatDescriptionGetMediaSubType(format.formatDescription);
|
||||||
cap.videoType = ConvertFourCCToVideoType(fourcc);
|
cap.videoType = ConvertFourCCToVideoType(fourcc);
|
||||||
CMVideoDimensions dimensions =
|
CMVideoDimensions dimensions =
|
||||||
CMVideoFormatDescriptionGetDimensions(format.formatDescription);
|
CMVideoFormatDescriptionGetDimensions(format.formatDescription);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@
|
||||||
if (!_owner && owner) {
|
if (!_owner && owner) {
|
||||||
[self configureObservers];
|
[self configureObservers];
|
||||||
} else if (_owner && !owner) {
|
} else if (_owner && !owner) {
|
||||||
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
|
NSNotificationCenter* notificationCenter =
|
||||||
|
[NSNotificationCenter defaultCenter];
|
||||||
for (id observer in _observers) {
|
for (id observer in _observers) {
|
||||||
[notificationCenter removeObserver:observer];
|
[notificationCenter removeObserver:observer];
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +48,8 @@
|
||||||
+ (int)captureDeviceCount {
|
+ (int)captureDeviceCount {
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
@try {
|
@try {
|
||||||
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
for (AVCaptureDevice* device in
|
||||||
|
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||||
if ([device isSuspended]) {
|
if ([device isSuspended]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +64,8 @@
|
||||||
+ (AVCaptureDevice*)captureDeviceForIndex:(int)index {
|
+ (AVCaptureDevice*)captureDeviceForIndex:(int)index {
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
@try {
|
@try {
|
||||||
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
for (AVCaptureDevice* device in
|
||||||
|
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||||
if ([device isSuspended]) {
|
if ([device isSuspended]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +82,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (AVCaptureDevice*)captureDeviceForUniqueId:(NSString*)uniqueId {
|
+ (AVCaptureDevice*)captureDeviceForUniqueId:(NSString*)uniqueId {
|
||||||
for (AVCaptureDevice* device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
for (AVCaptureDevice* device in
|
||||||
|
[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
|
||||||
if ([device isSuspended]) {
|
if ([device isSuspended]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -133,34 +137,36 @@
|
||||||
|
|
||||||
- (void)configureObservers {
|
- (void)configureObservers {
|
||||||
// register device connected / disconnected event
|
// register device connected / disconnected event
|
||||||
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
|
NSNotificationCenter* notificationCenter =
|
||||||
|
[NSNotificationCenter defaultCenter];
|
||||||
|
|
||||||
id deviceWasConnectedObserver =
|
id deviceWasConnectedObserver = [notificationCenter
|
||||||
[notificationCenter addObserverForName:AVCaptureDeviceWasConnectedNotification
|
addObserverForName:AVCaptureDeviceWasConnectedNotification
|
||||||
object:nil
|
object:nil
|
||||||
queue:[NSOperationQueue mainQueue]
|
queue:[NSOperationQueue mainQueue]
|
||||||
usingBlock:^(NSNotification* note) {
|
usingBlock:^(NSNotification* note) {
|
||||||
[_lock lock];
|
[_lock lock];
|
||||||
AVCaptureDevice* device = [note object];
|
AVCaptureDevice* device = [note object];
|
||||||
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
|
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
|
||||||
if (isVideoDevice && _owner) _owner->DeviceChange();
|
if (isVideoDevice && _owner) _owner->DeviceChange();
|
||||||
[_lock unlock];
|
[_lock unlock];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
id deviceWasDisconnectedObserver =
|
id deviceWasDisconnectedObserver = [notificationCenter
|
||||||
[notificationCenter addObserverForName:AVCaptureDeviceWasDisconnectedNotification
|
addObserverForName:AVCaptureDeviceWasDisconnectedNotification
|
||||||
object:nil
|
object:nil
|
||||||
queue:[NSOperationQueue mainQueue]
|
queue:[NSOperationQueue mainQueue]
|
||||||
usingBlock:^(NSNotification* note) {
|
usingBlock:^(NSNotification* note) {
|
||||||
[_lock lock];
|
[_lock lock];
|
||||||
AVCaptureDevice* device = [note object];
|
AVCaptureDevice* device = [note object];
|
||||||
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
|
BOOL isVideoDevice = [device hasMediaType:AVMediaTypeVideo];
|
||||||
if (isVideoDevice && _owner) _owner->DeviceChange();
|
if (isVideoDevice && _owner) _owner->DeviceChange();
|
||||||
[_lock unlock];
|
[_lock unlock];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
_observers = [[NSArray alloc]
|
_observers =
|
||||||
initWithObjects:deviceWasConnectedObserver, deviceWasDisconnectedObserver, nil];
|
[[NSArray alloc] initWithObjects:deviceWasConnectedObserver,
|
||||||
|
deviceWasDisconnectedObserver, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
||||||
|
|
@ -57,18 +57,22 @@ using namespace webrtc::videocapturemodule;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create and configure a new output (using callbacks)
|
// create and configure a new output (using callbacks)
|
||||||
AVCaptureVideoDataOutput* captureOutput = [[AVCaptureVideoDataOutput alloc] init];
|
AVCaptureVideoDataOutput* captureOutput =
|
||||||
|
[[AVCaptureVideoDataOutput alloc] init];
|
||||||
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
|
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
|
||||||
|
|
||||||
NSNumber* val = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8];
|
NSNumber* val =
|
||||||
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val forKey:key];
|
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8];
|
||||||
|
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val
|
||||||
|
forKey:key];
|
||||||
captureOutput.videoSettings = videoSettings;
|
captureOutput.videoSettings = videoSettings;
|
||||||
|
|
||||||
// add new output
|
// add new output
|
||||||
if ([_captureSession canAddOutput:captureOutput]) {
|
if ([_captureSession canAddOutput:captureOutput]) {
|
||||||
[_captureSession addOutput:captureOutput];
|
[_captureSession addOutput:captureOutput];
|
||||||
} else {
|
} 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
|
#ifdef WEBRTC_IOS
|
||||||
|
|
@ -86,12 +90,14 @@ using namespace webrtc::videocapturemodule;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a serial queue on which video capture will run. By setting the target,
|
// Create a serial queue on which video capture will run. By setting the
|
||||||
// blocks should still run on DISPATH_QUEUE_PRIORITY_DEFAULT rather than creating
|
// target, blocks should still run on DISPATH_QUEUE_PRIORITY_DEFAULT rather
|
||||||
// a new thread.
|
// than creating a new thread.
|
||||||
_frameQueue = dispatch_queue_create("org.webrtc.videocapture", DISPATCH_QUEUE_SERIAL);
|
_frameQueue =
|
||||||
dispatch_set_target_queue(_frameQueue,
|
dispatch_queue_create("org.webrtc.videocapture", DISPATCH_QUEUE_SERIAL);
|
||||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
dispatch_set_target_queue(
|
||||||
|
_frameQueue,
|
||||||
|
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
@ -144,11 +150,13 @@ using namespace webrtc::videocapturemodule;
|
||||||
if (capability.width > 1280 || capability.height > 720) {
|
if (capability.width > 1280 || capability.height > 720) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
} else if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
|
} else if ([_captureSession
|
||||||
|
canSetSessionPreset:AVCaptureSessionPreset640x480]) {
|
||||||
if (capability.width > 640 || capability.height > 480) {
|
if (capability.width > 640 || capability.height > 480) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
} else if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset352x288]) {
|
} else if ([_captureSession
|
||||||
|
canSetSessionPreset:AVCaptureSessionPreset352x288]) {
|
||||||
if (capability.width > 352 || capability.height > 288) {
|
if (capability.width > 352 || capability.height > 288) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
@ -175,8 +183,10 @@ using namespace webrtc::videocapturemodule;
|
||||||
return [[_captureSession outputs] firstObject];
|
return [[_captureSession outputs] firstObject];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)startCaptureInBackgroundWithOutput:(AVCaptureVideoDataOutput*)currentOutput {
|
- (void)startCaptureInBackgroundWithOutput:
|
||||||
NSString* captureQuality = [NSString stringWithString:AVCaptureSessionPresetLow];
|
(AVCaptureVideoDataOutput*)currentOutput {
|
||||||
|
NSString* captureQuality =
|
||||||
|
[NSString stringWithString:AVCaptureSessionPresetLow];
|
||||||
if (_capability.width >= 1280 || _capability.height >= 720) {
|
if (_capability.width >= 1280 || _capability.height >= 720) {
|
||||||
captureQuality = [NSString stringWithString:AVCaptureSessionPreset1280x720];
|
captureQuality = [NSString stringWithString:AVCaptureSessionPreset1280x720];
|
||||||
} else if (_capability.width >= 640 || _capability.height >= 480) {
|
} else if (_capability.width >= 640 || _capability.height >= 480) {
|
||||||
|
|
@ -214,7 +224,8 @@ using namespace webrtc::videocapturemodule;
|
||||||
_connection.videoOrientation = AVCaptureVideoOrientationPortrait;
|
_connection.videoOrientation = AVCaptureVideoOrientationPortrait;
|
||||||
break;
|
break;
|
||||||
case UIDeviceOrientationPortraitUpsideDown:
|
case UIDeviceOrientationPortraitUpsideDown:
|
||||||
_connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
|
_connection.videoOrientation =
|
||||||
|
AVCaptureVideoOrientationPortraitUpsideDown;
|
||||||
break;
|
break;
|
||||||
case UIDeviceOrientationLandscapeLeft:
|
case UIDeviceOrientationLandscapeLeft:
|
||||||
_connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
|
_connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
|
||||||
|
|
@ -236,7 +247,8 @@ using namespace webrtc::videocapturemodule;
|
||||||
- (void)onVideoError:(NSNotification*)notification {
|
- (void)onVideoError:(NSNotification*)notification {
|
||||||
NSLog(@"onVideoError: %@", notification);
|
NSLog(@"onVideoError: %@", notification);
|
||||||
// TODO(sjlee): make the specific error handling with this 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 {
|
- (BOOL)stopCapture {
|
||||||
|
|
@ -265,7 +277,8 @@ using namespace webrtc::videocapturemodule;
|
||||||
NSArray* currentInputs = [_captureSession inputs];
|
NSArray* currentInputs = [_captureSession inputs];
|
||||||
// remove current input
|
// remove current input
|
||||||
if ([currentInputs count] > 0) {
|
if ([currentInputs count] > 0) {
|
||||||
AVCaptureInput* currentInput = (AVCaptureInput*)[currentInputs objectAtIndex:0];
|
AVCaptureInput* currentInput =
|
||||||
|
(AVCaptureInput*)[currentInputs objectAtIndex:0];
|
||||||
|
|
||||||
[_captureSession removeInput:currentInput];
|
[_captureSession removeInput:currentInput];
|
||||||
}
|
}
|
||||||
|
|
@ -277,7 +290,8 @@ using namespace webrtc::videocapturemodule;
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVCaptureDevice* captureDevice = [DeviceInfoIosObjC captureDeviceForUniqueId:uniqueId];
|
AVCaptureDevice* captureDevice =
|
||||||
|
[DeviceInfoIosObjC captureDeviceForUniqueId:uniqueId];
|
||||||
|
|
||||||
if (!captureDevice) {
|
if (!captureDevice) {
|
||||||
return NO;
|
return NO;
|
||||||
|
|
@ -285,13 +299,15 @@ using namespace webrtc::videocapturemodule;
|
||||||
|
|
||||||
// now create capture session input out of AVCaptureDevice
|
// now create capture session input out of AVCaptureDevice
|
||||||
NSError* deviceError = nil;
|
NSError* deviceError = nil;
|
||||||
AVCaptureDeviceInput* newCaptureInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice
|
AVCaptureDeviceInput* newCaptureInput =
|
||||||
error:&deviceError];
|
[AVCaptureDeviceInput deviceInputWithDevice:captureDevice
|
||||||
|
error:&deviceError];
|
||||||
|
|
||||||
if (!newCaptureInput) {
|
if (!newCaptureInput) {
|
||||||
const char* errorMessage = [[deviceError localizedDescription] UTF8String];
|
const char* errorMessage = [[deviceError localizedDescription] UTF8String];
|
||||||
|
|
||||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << ": deviceInputWithDevice error:" << errorMessage;
|
RTC_LOG(LS_ERROR) << __FUNCTION__
|
||||||
|
<< ": deviceInputWithDevice error:" << errorMessage;
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ using namespace mozilla;
|
||||||
using namespace webrtc;
|
using namespace webrtc;
|
||||||
using namespace videocapturemodule;
|
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()) {
|
if (StaticPrefs::media_getusermedia_camera_macavf_enabled_AtStartup()) {
|
||||||
return VideoCaptureAvFoundation::Create(deviceUniqueIdUTF8);
|
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]) {
|
if (!deviceUniqueIdUTF8[0]) {
|
||||||
return NULL;
|
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);
|
const int32_t name_length = strlen(deviceUniqueIdUTF8);
|
||||||
if (name_length >= kVideoCaptureUniqueNameLength) return nullptr;
|
if (name_length >= kVideoCaptureUniqueNameLength) return nullptr;
|
||||||
|
|
@ -65,14 +68,16 @@ rtc::scoped_refptr<VideoCaptureModule> VideoCaptureIos::Create(const char* devic
|
||||||
}
|
}
|
||||||
|
|
||||||
if (![capture_module->capture_device_
|
if (![capture_module->capture_device_
|
||||||
setCaptureDeviceByUniqueId:[[NSString alloc] initWithCString:deviceUniqueIdUTF8
|
setCaptureDeviceByUniqueId:
|
||||||
encoding:NSUTF8StringEncoding]]) {
|
[[NSString alloc] initWithCString:deviceUniqueIdUTF8
|
||||||
|
encoding:NSUTF8StringEncoding]]) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return capture_module;
|
return capture_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t VideoCaptureIos::StartCapture(const VideoCaptureCapability& capability) {
|
int32_t VideoCaptureIos::StartCapture(
|
||||||
|
const VideoCaptureCapability& capability) {
|
||||||
capability_ = capability;
|
capability_ = capability;
|
||||||
|
|
||||||
if (![capture_device_ startCaptureWithCapability:capability]) {
|
if (![capture_device_ startCaptureWithCapability:capability]) {
|
||||||
|
|
|
||||||
|
|
@ -38,30 +38,37 @@ webrtc::VideoRotation ToNativeRotation(RTCVideoRotation aRotation) {
|
||||||
case RTCVideoRotation_270:
|
case RTCVideoRotation_270:
|
||||||
return webrtc::kVideoRotation_270;
|
return webrtc::kVideoRotation_270;
|
||||||
default:
|
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;
|
return webrtc::kVideoRotation_0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
|
AVCaptureDeviceFormat* _Nullable FindFormat(
|
||||||
webrtc::VideoCaptureCapability aCapability) {
|
AVCaptureDevice* _Nonnull aDevice,
|
||||||
|
webrtc::VideoCaptureCapability aCapability) {
|
||||||
for (AVCaptureDeviceFormat* format in [aDevice formats]) {
|
for (AVCaptureDeviceFormat* format in [aDevice formats]) {
|
||||||
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
|
CMVideoDimensions dimensions =
|
||||||
|
CMVideoFormatDescriptionGetDimensions(format.formatDescription);
|
||||||
if (dimensions.width != aCapability.width) {
|
if (dimensions.width != aCapability.width) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (dimensions.height != aCapability.height) {
|
if (dimensions.height != aCapability.height) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
FourCharCode fourcc = CMFormatDescriptionGetMediaSubType(format.formatDescription);
|
FourCharCode fourcc =
|
||||||
if (aCapability.videoType != DeviceInfoAvFoundation::ConvertFourCCToVideoType(fourcc)) {
|
CMFormatDescriptionGetMediaSubType(format.formatDescription);
|
||||||
|
if (aCapability.videoType !=
|
||||||
|
DeviceInfoAvFoundation::ConvertFourCCToVideoType(fourcc)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ([format.videoSupportedFrameRateRanges
|
if ([format.videoSupportedFrameRateRanges
|
||||||
indexOfObjectPassingTest:^BOOL(AVFrameRateRange* _Nonnull obj, NSUInteger idx,
|
indexOfObjectPassingTest:^BOOL(AVFrameRateRange* _Nonnull obj,
|
||||||
|
NSUInteger idx,
|
||||||
BOOL* _Nonnull stop) {
|
BOOL* _Nonnull stop) {
|
||||||
return static_cast<BOOL>(DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
|
return static_cast<BOOL>(
|
||||||
obj.maxFrameRate) == aCapability.maxFPS);
|
DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
|
||||||
|
obj.maxFrameRate) == aCapability.maxFPS);
|
||||||
}] == NSNotFound) {
|
}] == NSNotFound) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +80,8 @@ AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@implementation VideoCaptureAdapter
|
@implementation VideoCaptureAdapter
|
||||||
- (void)setCapturer:(webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable)capturer {
|
- (void)setCapturer:
|
||||||
|
(webrtc::videocapturemodule::VideoCaptureAvFoundation* _Nullable)capturer {
|
||||||
webrtc::MutexLock lock(&_mutex);
|
webrtc::MutexLock lock(&_mutex);
|
||||||
_capturer = capturer;
|
_capturer = capturer;
|
||||||
}
|
}
|
||||||
|
|
@ -91,10 +99,12 @@ AVCaptureDeviceFormat* _Nullable FindFormat(AVCaptureDevice* _Nonnull aDevice,
|
||||||
@end
|
@end
|
||||||
|
|
||||||
namespace webrtc::videocapturemodule {
|
namespace webrtc::videocapturemodule {
|
||||||
VideoCaptureAvFoundation::VideoCaptureAvFoundation(AVCaptureDevice* _Nonnull aDevice)
|
VideoCaptureAvFoundation::VideoCaptureAvFoundation(
|
||||||
|
AVCaptureDevice* _Nonnull aDevice)
|
||||||
: mDevice(aDevice),
|
: mDevice(aDevice),
|
||||||
mAdapter([[VideoCaptureAdapter alloc] init]),
|
mAdapter([[VideoCaptureAdapter alloc] init]),
|
||||||
mCapturer([[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc] initWithDelegate:mAdapter]),
|
mCapturer([[RTC_OBJC_TYPE(RTCCameraVideoCapturer) alloc]
|
||||||
|
initWithDelegate:mAdapter]),
|
||||||
mCallbackThreadId() {
|
mCallbackThreadId() {
|
||||||
const char* uniqueId = [[aDevice uniqueID] UTF8String];
|
const char* uniqueId = [[aDevice uniqueID] UTF8String];
|
||||||
size_t len = strlen(uniqueId);
|
size_t len = strlen(uniqueId);
|
||||||
|
|
@ -123,7 +133,8 @@ rtc::scoped_refptr<VideoCaptureModule> VideoCaptureAvFoundation::Create(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t VideoCaptureAvFoundation::StartCapture(const VideoCaptureCapability& aCapability) {
|
int32_t VideoCaptureAvFoundation::StartCapture(
|
||||||
|
const VideoCaptureCapability& aCapability) {
|
||||||
RTC_DCHECK_RUN_ON(&mChecker);
|
RTC_DCHECK_RUN_ON(&mChecker);
|
||||||
AVCaptureDeviceFormat* format = FindFormat(mDevice, aCapability);
|
AVCaptureDeviceFormat* format = FindFormat(mDevice, aCapability);
|
||||||
if (!format) {
|
if (!format) {
|
||||||
|
|
@ -133,7 +144,8 @@ int32_t VideoCaptureAvFoundation::StartCapture(const VideoCaptureCapability& aCa
|
||||||
{
|
{
|
||||||
MutexLock lock(&api_lock_);
|
MutexLock lock(&api_lock_);
|
||||||
if (mCapability) {
|
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->maxFPS == aCapability.maxFPS &&
|
||||||
mCapability->videoType == aCapability.videoType) {
|
mCapability->videoType == aCapability.videoType) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -250,28 +262,33 @@ bool VideoCaptureAvFoundation::CaptureStarted() {
|
||||||
return mCapability.isSome();
|
return mCapability.isSome();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t VideoCaptureAvFoundation::CaptureSettings(VideoCaptureCapability& aSettings) {
|
int32_t VideoCaptureAvFoundation::CaptureSettings(
|
||||||
|
VideoCaptureCapability& aSettings) {
|
||||||
MOZ_CRASH("Unexpected call");
|
MOZ_CRASH("Unexpected call");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t VideoCaptureAvFoundation::OnFrame(__strong RTCVideoFrame* _Nonnull aFrame) {
|
int32_t VideoCaptureAvFoundation::OnFrame(
|
||||||
|
__strong RTCVideoFrame* _Nonnull aFrame) {
|
||||||
MaybeRegisterCallbackThread();
|
MaybeRegisterCallbackThread();
|
||||||
if (MutexLock lock(&api_lock_); MOZ_LIKELY(mTrackingId)) {
|
if (MutexLock lock(&api_lock_); MOZ_LIKELY(mTrackingId)) {
|
||||||
mCaptureRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width,
|
mCaptureRecorder.Start(
|
||||||
aFrame.height, mImageType.valueOr(CaptureStage::ImageType::Unknown));
|
0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width,
|
||||||
|
aFrame.height, mImageType.valueOr(CaptureStage::ImageType::Unknown));
|
||||||
if (mCapability && mCapability->videoType != webrtc::VideoType::kI420) {
|
if (mCapability && mCapability->videoType != webrtc::VideoType::kI420) {
|
||||||
mConversionRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId, aFrame.width,
|
mConversionRecorder.Start(0, "VideoCaptureAVFoundation"_ns, *mTrackingId,
|
||||||
aFrame.height);
|
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];
|
RTCI420Buffer* buffer = [aFrame.buffer toI420];
|
||||||
mConversionRecorder.Record(0);
|
mConversionRecorder.Record(0);
|
||||||
// Accessing the (intended-to-be-private) native buffer directly is hacky but lets us skip two
|
// Accessing the (intended-to-be-private) native buffer directly is hacky but
|
||||||
// copies
|
// lets us skip two copies
|
||||||
rtc::scoped_refptr<webrtc::I420BufferInterface> nativeBuffer = buffer.nativeI420Buffer;
|
rtc::scoped_refptr<webrtc::I420BufferInterface> nativeBuffer =
|
||||||
|
buffer.nativeI420Buffer;
|
||||||
auto frame = webrtc::VideoFrame::Builder()
|
auto frame = webrtc::VideoFrame::Builder()
|
||||||
.set_video_frame_buffer(nativeBuffer)
|
.set_video_frame_buffer(nativeBuffer)
|
||||||
.set_rotation(ToNativeRotation(aFrame.rotation))
|
.set_rotation(ToNativeRotation(aFrame.rotation))
|
||||||
|
|
@ -288,8 +305,8 @@ void VideoCaptureAvFoundation::SetTrackingId(uint32_t aTrackingIdProcId) {
|
||||||
RTC_DCHECK_RUN_ON(&mChecker);
|
RTC_DCHECK_RUN_ON(&mChecker);
|
||||||
MutexLock lock(&api_lock_);
|
MutexLock lock(&api_lock_);
|
||||||
if (NS_WARN_IF(mTrackingId.isSome())) {
|
if (NS_WARN_IF(mTrackingId.isSome())) {
|
||||||
// This capture instance must be shared across multiple camera requests. For now ignore other
|
// This capture instance must be shared across multiple camera requests. For
|
||||||
// requests than the first.
|
// now ignore other requests than the first.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mTrackingId.emplace(TrackingId::Source::Camera, aTrackingIdProcId);
|
mTrackingId.emplace(TrackingId::Source::Camera, aTrackingIdProcId);
|
||||||
|
|
@ -301,6 +318,7 @@ void VideoCaptureAvFoundation::MaybeRegisterCallbackThread() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mCallbackThreadId = id;
|
mCallbackThreadId = id;
|
||||||
CallbackThreadRegistry::Get()->Register(mCallbackThreadId, "VideoCaptureAVFoundationCallback");
|
CallbackThreadRegistry::Get()->Register(mCallbackThreadId,
|
||||||
|
"VideoCaptureAVFoundationCallback");
|
||||||
}
|
}
|
||||||
} // namespace webrtc::videocapturemodule
|
} // 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: */
|
/* vim: set ts=2 sw=2 et tw=80: */
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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);
|
const nsTArray<size_t>& aOffsets);
|
||||||
|
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechTaskCallback, nsISpeechTaskCallback)
|
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechTaskCallback,
|
||||||
|
nsISpeechTaskCallback)
|
||||||
|
|
||||||
NS_DECL_NSISPEECHTASKCALLBACK
|
NS_DECL_NSISPEECHTASKCALLBACK
|
||||||
|
|
||||||
|
|
@ -79,7 +81,8 @@ class SpeechTaskCallback final : public nsISpeechTaskCallback {
|
||||||
mCallback->OnWillSpeakWord(aRange.location, aRange.length);
|
mCallback->OnWillSpeakWord(aRange.location, aRange.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)speechSynthesizer:(NSSpeechSynthesizer*)aSender didFinishSpeaking:(BOOL)aFinishedSpeaking {
|
- (void)speechSynthesizer:(NSSpeechSynthesizer*)aSender
|
||||||
|
didFinishSpeaking:(BOOL)aFinishedSpeaking {
|
||||||
mCallback->OnDidFinishSpeaking();
|
mCallback->OnDidFinishSpeaking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,9 +104,13 @@ NS_INTERFACE_MAP_END
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechTaskCallback)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechTaskCallback)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechTaskCallback)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechTaskCallback)
|
||||||
|
|
||||||
SpeechTaskCallback::SpeechTaskCallback(nsISpeechTask* aTask, NSSpeechSynthesizer* aSynth,
|
SpeechTaskCallback::SpeechTaskCallback(nsISpeechTask* aTask,
|
||||||
|
NSSpeechSynthesizer* aSynth,
|
||||||
const nsTArray<size_t>& aOffsets)
|
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];
|
mDelegate = [[SpeechDelegate alloc] initWithCallback:this];
|
||||||
[mSpeechSynthesizer setDelegate:mDelegate];
|
[mSpeechSynthesizer setDelegate:mDelegate];
|
||||||
mStartingTime = TimeStamp::Now();
|
mStartingTime = TimeStamp::Now();
|
||||||
|
|
@ -179,7 +186,8 @@ void SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex, uint32_t aLength) {
|
||||||
if (!mTask) {
|
if (!mTask) {
|
||||||
return;
|
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) {
|
void SpeechTaskCallback::OnError(uint32_t aIndex) {
|
||||||
|
|
@ -210,8 +218,11 @@ struct OSXVoice {
|
||||||
|
|
||||||
class RegisterVoicesRunnable final : public Runnable {
|
class RegisterVoicesRunnable final : public Runnable {
|
||||||
public:
|
public:
|
||||||
RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService, nsTArray<OSXVoice>& aList)
|
RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService,
|
||||||
: Runnable("RegisterVoicesRunnable"), mSpeechService(aSpeechService), mVoices(aList) {}
|
nsTArray<OSXVoice>& aList)
|
||||||
|
: Runnable("RegisterVoicesRunnable"),
|
||||||
|
mSpeechService(aSpeechService),
|
||||||
|
mVoices(aList) {}
|
||||||
|
|
||||||
NS_IMETHOD Run() override;
|
NS_IMETHOD Run() override;
|
||||||
|
|
||||||
|
|
@ -226,13 +237,15 @@ class RegisterVoicesRunnable final : public Runnable {
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
RegisterVoicesRunnable::Run() {
|
RegisterVoicesRunnable::Run() {
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsCOMPtr<nsISynthVoiceRegistry> registry = do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID, &rv);
|
nsCOMPtr<nsISynthVoiceRegistry> registry =
|
||||||
|
do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID, &rv);
|
||||||
if (!registry) {
|
if (!registry) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (OSXVoice voice : mVoices) {
|
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))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -275,11 +288,14 @@ EnumVoicesRunnable::Run() {
|
||||||
NSDictionary* attr = [NSSpeechSynthesizer attributesForVoice:voice];
|
NSDictionary* attr = [NSSpeechSynthesizer attributesForVoice:voice];
|
||||||
|
|
||||||
nsAutoString identifier;
|
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.mLocale.ReplaceChar('_', '-');
|
||||||
|
|
||||||
item.mUri.AssignLiteral("urn:moz-tts:osx:");
|
item.mUri.AssignLiteral("urn:moz-tts:osx:");
|
||||||
|
|
@ -292,16 +308,19 @@ EnumVoicesRunnable::Run() {
|
||||||
list.AppendElement(item);
|
list.AppendElement(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<RegisterVoicesRunnable> runnable = new RegisterVoicesRunnable(mSpeechService, list);
|
RefPtr<RegisterVoicesRunnable> runnable =
|
||||||
|
new RegisterVoicesRunnable(mSpeechService, list);
|
||||||
NS_DispatchAndSpinEventLoopUntilComplete("EnumVoicesRunnable"_ns,
|
NS_DispatchAndSpinEventLoopUntilComplete("EnumVoicesRunnable"_ns,
|
||||||
GetMainThreadSerialEventTarget(), runnable.forget());
|
GetMainThreadSerialEventTarget(),
|
||||||
|
runnable.forget());
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
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_BEGIN(OSXSpeechSynthesizerService)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsISpeechService)
|
NS_INTERFACE_MAP_ENTRY(nsISpeechService)
|
||||||
|
|
@ -312,7 +331,8 @@ NS_INTERFACE_MAP_END
|
||||||
NS_IMPL_ADDREF(OSXSpeechSynthesizerService)
|
NS_IMPL_ADDREF(OSXSpeechSynthesizerService)
|
||||||
NS_IMPL_RELEASE(OSXSpeechSynthesizerService)
|
NS_IMPL_RELEASE(OSXSpeechSynthesizerService)
|
||||||
|
|
||||||
OSXSpeechSynthesizerService::OSXSpeechSynthesizerService() : mInitialized(false) {}
|
OSXSpeechSynthesizerService::OSXSpeechSynthesizerService()
|
||||||
|
: mInitialized(false) {}
|
||||||
|
|
||||||
bool OSXSpeechSynthesizerService::Init() {
|
bool OSXSpeechSynthesizerService::Init() {
|
||||||
if (Preferences::GetBool("media.webspeech.synth.test") ||
|
if (Preferences::GetBool("media.webspeech.synth.test") ||
|
||||||
|
|
@ -335,8 +355,10 @@ bool OSXSpeechSynthesizerService::Init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXSpeechSynthesizerService::Speak(const nsAString& aText, const nsAString& aUri, float aVolume,
|
OSXSpeechSynthesizerService::Speak(const nsAString& aText,
|
||||||
float aRate, float aPitch, nsISpeechTask* aTask) {
|
const nsAString& aUri, float aVolume,
|
||||||
|
float aRate, float aPitch,
|
||||||
|
nsISpeechTask* aTask) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
MOZ_ASSERT(StringBeginsWith(aUri, u"urn:moz-tts:osx:"_ns),
|
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];
|
[synth setVoice:identifier];
|
||||||
|
|
||||||
// default rate is 180-220
|
// 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
|
// 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
|
// Use default pitch value to calculate this
|
||||||
NSNumber* defaultPitch = [synth objectForProperty:NSSpeechPitchBaseProperty error:nil];
|
NSNumber* defaultPitch = [synth objectForProperty:NSSpeechPitchBaseProperty
|
||||||
|
error:nil];
|
||||||
if (defaultPitch) {
|
if (defaultPitch) {
|
||||||
int newPitch = [defaultPitch intValue] * (aPitch / 2 + 0.5);
|
int newPitch = [defaultPitch intValue] * (aPitch / 2 + 0.5);
|
||||||
[synth setObject:[NSNumber numberWithInt:newPitch]
|
[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
|
// This loop looks for occurances of "[[" or "]]", escapes them, and
|
||||||
// populates the offsets array to supply a map to the original offsets.
|
// populates the offsets array to supply a map to the original offsets.
|
||||||
for (size_t i = 0; i < aText.Length(); i++) {
|
for (size_t i = 0; i < aText.Length(); i++) {
|
||||||
if (aText.Length() > i + 1 &&
|
if (aText.Length() > i + 1 && ((aText[i] == ']' && aText[i + 1] == ']') ||
|
||||||
((aText[i] == ']' && aText[i + 1] == ']') || (aText[i] == '[' && aText[i + 1] == '['))) {
|
(aText[i] == '[' && aText[i + 1] == '['))) {
|
||||||
escapedText.AppendLiteral(DLIM_ESCAPE_START);
|
escapedText.AppendLiteral(DLIM_ESCAPE_START);
|
||||||
offsets.AppendElements(strlen(DLIM_ESCAPE_START));
|
offsets.AppendElements(strlen(DLIM_ESCAPE_START));
|
||||||
escapedText.Append(aText[i]);
|
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);
|
nsresult rv = aTask->Setup(callback);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
|
@ -413,7 +441,8 @@ OSXSpeechSynthesizerService* OSXSpeechSynthesizerService::GetInstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sSingleton) {
|
if (!sSingleton) {
|
||||||
RefPtr<OSXSpeechSynthesizerService> speechService = new OSXSpeechSynthesizerService();
|
RefPtr<OSXSpeechSynthesizerService> speechService =
|
||||||
|
new OSXSpeechSynthesizerService();
|
||||||
if (speechService->Init()) {
|
if (speechService->Init()) {
|
||||||
sSingleton = speechService;
|
sSingleton = speechService;
|
||||||
ClearOnShutdown(&sSingleton);
|
ClearOnShutdown(&sSingleton);
|
||||||
|
|
@ -422,7 +451,8 @@ OSXSpeechSynthesizerService* OSXSpeechSynthesizerService::GetInstance() {
|
||||||
return sSingleton;
|
return sSingleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<OSXSpeechSynthesizerService> OSXSpeechSynthesizerService::GetInstanceForService() {
|
already_AddRefed<OSXSpeechSynthesizerService>
|
||||||
|
OSXSpeechSynthesizerService::GetInstanceForService() {
|
||||||
RefPtr<OSXSpeechSynthesizerService> speechService = GetInstance();
|
RefPtr<OSXSpeechSynthesizerService> speechService = GetInstance();
|
||||||
return speechService.forget();
|
return speechService.forget();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,18 @@
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
static const CLLocationAccuracy kHIGH_ACCURACY = kCLLocationAccuracyBest;
|
static const CLLocationAccuracy kHIGH_ACCURACY = kCLLocationAccuracyBest;
|
||||||
static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTenMeters;
|
static const CLLocationAccuracy kDEFAULT_ACCURACY =
|
||||||
|
kCLLocationAccuracyNearestTenMeters;
|
||||||
|
|
||||||
@interface LocationDelegate : NSObject <CLLocationManagerDelegate> {
|
@interface LocationDelegate : NSObject <CLLocationManagerDelegate> {
|
||||||
CoreLocationLocationProvider* mProvider;
|
CoreLocationLocationProvider* mProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init:(CoreLocationLocationProvider*)aProvider;
|
- (id)init:(CoreLocationLocationProvider*)aProvider;
|
||||||
- (void)locationManager:(CLLocationManager*)aManager didFailWithError:(NSError*)aError;
|
- (void)locationManager:(CLLocationManager*)aManager
|
||||||
- (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)locations;
|
didFailWithError:(NSError*)aError;
|
||||||
|
- (void)locationManager:(CLLocationManager*)aManager
|
||||||
|
didUpdateLocations:(NSArray*)locations;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
@ -50,28 +53,32 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)locationManager:(CLLocationManager*)aManager didFailWithError:(NSError*)aError {
|
- (void)locationManager:(CLLocationManager*)aManager
|
||||||
nsCOMPtr<nsIConsoleService> console = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
didFailWithError:(NSError*)aError {
|
||||||
|
nsCOMPtr<nsIConsoleService> console =
|
||||||
|
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||||
|
|
||||||
NS_ENSURE_TRUE_VOID(console);
|
NS_ENSURE_TRUE_VOID(console);
|
||||||
|
|
||||||
NSString* message =
|
NSString* message = [@"Failed to acquire position: "
|
||||||
[@"Failed to acquire position: " stringByAppendingString:[aError localizedDescription]];
|
stringByAppendingString:[aError localizedDescription]];
|
||||||
|
|
||||||
console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get());
|
console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get());
|
||||||
|
|
||||||
if ([aError code] == kCLErrorDenied) {
|
if ([aError code] == kCLErrorDenied) {
|
||||||
mProvider->NotifyError(dom::GeolocationPositionError_Binding::PERMISSION_DENIED);
|
mProvider->NotifyError(
|
||||||
|
dom::GeolocationPositionError_Binding::PERMISSION_DENIED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The CL provider does not fallback to GeoIP, so use NetworkGeolocationProvider for this.
|
// The CL provider does not fallback to GeoIP, so use
|
||||||
// The concept here is: on error, hand off geolocation to MLS, which will then report
|
// NetworkGeolocationProvider for this. The concept here is: on error, hand
|
||||||
// back a location or error.
|
// off geolocation to MLS, which will then report back a location or error.
|
||||||
mProvider->CreateMLSFallbackProvider();
|
mProvider->CreateMLSFallbackProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)aLocations {
|
- (void)locationManager:(CLLocationManager*)aManager
|
||||||
|
didUpdateLocations:(NSArray*)aLocations {
|
||||||
if (aLocations.count < 1) {
|
if (aLocations.count < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -92,24 +99,29 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe
|
||||||
altitudeAccuracy = UnspecifiedNaN<double>();
|
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
|
// nsGeoPositionCoords will convert NaNs to null for optional properties of
|
||||||
// the JavaScript Coordinates object.
|
// the JavaScript Coordinates object.
|
||||||
nsCOMPtr<nsIDOMGeoPosition> geoPosition = new nsGeoPosition(
|
nsCOMPtr<nsIDOMGeoPosition> geoPosition = new nsGeoPosition(
|
||||||
location.coordinate.latitude, location.coordinate.longitude, altitude,
|
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);
|
mProvider->Update(geoPosition);
|
||||||
Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, false);
|
Telemetry::Accumulate(Telemetry::GEOLOCATION_OSX_SOURCE_IS_MLS, false);
|
||||||
}
|
}
|
||||||
@end
|
@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) {}
|
: mParentLocationProvider(parentProvider) {}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
@ -175,7 +187,8 @@ CoreLocationLocationProvider::Startup() {
|
||||||
mCLObjects = clObjs.release();
|
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 stopUpdatingLocation];
|
||||||
[mCLObjects->mLocationManager startUpdatingLocation];
|
[mCLObjects->mLocationManager startUpdatingLocation];
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -212,7 +225,8 @@ NS_IMETHODIMP
|
||||||
CoreLocationLocationProvider::SetHighAccuracy(bool aEnable) {
|
CoreLocationLocationProvider::SetHighAccuracy(bool aEnable) {
|
||||||
NS_ENSURE_STATE(mCLObjects);
|
NS_ENSURE_STATE(mCLObjects);
|
||||||
|
|
||||||
mCLObjects->mLocationManager.desiredAccuracy = (aEnable ? kHIGH_ACCURACY : kDEFAULT_ACCURACY);
|
mCLObjects->mLocationManager.desiredAccuracy =
|
||||||
|
(aEnable ? kHIGH_ACCURACY : kDEFAULT_ACCURACY);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ nsOSPermissionRequest::GetScreenCapturePermissionState(uint16_t* aScreen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx, Promise** aPromiseOut) {
|
nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx,
|
||||||
|
Promise** aPromiseOut) {
|
||||||
RefPtr<Promise> promiseHandle;
|
RefPtr<Promise> promiseHandle;
|
||||||
nsresult rv = GetPromise(aCx, promiseHandle);
|
nsresult rv = GetPromise(aCx, promiseHandle);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
@ -45,7 +46,8 @@ nsOSPermissionRequest::RequestVideoCapturePermission(JSContext* aCx, Promise** a
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOSPermissionRequest::RequestAudioCapturePermission(JSContext* aCx, Promise** aPromiseOut) {
|
nsOSPermissionRequest::RequestAudioCapturePermission(JSContext* aCx,
|
||||||
|
Promise** aPromiseOut) {
|
||||||
RefPtr<Promise> promiseHandle;
|
RefPtr<Promise> promiseHandle;
|
||||||
nsresult rv = GetPromise(aCx, promiseHandle);
|
nsresult rv = GetPromise(aCx, promiseHandle);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ class CGLLibrary {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!mOGLLibrary) {
|
if (!mOGLLibrary) {
|
||||||
mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
|
mOGLLibrary =
|
||||||
|
PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
|
||||||
if (!mOGLLibrary) {
|
if (!mOGLLibrary) {
|
||||||
NS_WARNING("Couldn't load OpenGL Framework.");
|
NS_WARNING("Couldn't load OpenGL Framework.");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -59,7 +60,8 @@ CGLLibrary sCGLLibrary;
|
||||||
|
|
||||||
GLContextCGL::GLContextCGL(const GLContextDesc& desc, NSOpenGLContext* context)
|
GLContextCGL::GLContextCGL(const GLContextDesc& desc, NSOpenGLContext* context)
|
||||||
: GLContext(desc), mContext(context) {
|
: GLContext(desc), mContext(context) {
|
||||||
CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback, this);
|
CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback,
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLContextCGL::~GLContextCGL() {
|
GLContextCGL::~GLContextCGL() {
|
||||||
|
|
@ -89,33 +91,39 @@ bool GLContextCGL::MakeCurrentImpl() const {
|
||||||
// Use non-blocking swap in "ASAP mode".
|
// Use non-blocking swap in "ASAP mode".
|
||||||
// ASAP mode means that rendering is iterated as fast as possible.
|
// ASAP mode means that rendering is iterated as fast as possible.
|
||||||
// ASAP mode is entered when layout.frame_rate=0 (requires restart).
|
// 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.
|
// If swapInt is 1, then glSwapBuffers will block and wait for a vblank
|
||||||
// When we're iterating as fast as possible, however, we want a non-blocking
|
// signal. When we're iterating as fast as possible, however, we want a
|
||||||
// glSwapBuffers, which will happen when swapInt==0.
|
// non-blocking glSwapBuffers, which will happen when swapInt==0.
|
||||||
GLint swapInt = StaticPrefs::layout_frame_rate() == 0 ? 0 : 1;
|
GLint swapInt = StaticPrefs::layout_frame_rate() == 0 ? 0 : 1;
|
||||||
[mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
[mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLContextCGL::IsCurrentImpl() const { return [NSOpenGLContext currentContext] == mContext; }
|
bool GLContextCGL::IsCurrentImpl() const {
|
||||||
|
return [NSOpenGLContext currentContext] == mContext;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ void GLContextCGL::DisplayReconfigurationCallback(CGDirectDisplayID aDisplay,
|
/* static */ void GLContextCGL::DisplayReconfigurationCallback(
|
||||||
CGDisplayChangeSummaryFlags aFlags,
|
CGDirectDisplayID aDisplay, CGDisplayChangeSummaryFlags aFlags,
|
||||||
void* aUserInfo) {
|
void* aUserInfo) {
|
||||||
if (aFlags & kCGDisplaySetModeFlag) {
|
if (aFlags & kCGDisplaySetModeFlag) {
|
||||||
static_cast<GLContextCGL*>(aUserInfo)->mActiveGPUSwitchMayHaveOccurred = true;
|
static_cast<GLContextCGL*>(aUserInfo)->mActiveGPUSwitchMayHaveOccurred =
|
||||||
|
true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSOpenGLContext* CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs) {
|
static NSOpenGLContext* CreateWithFormat(
|
||||||
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
const NSOpenGLPixelFormatAttribute* attribs) {
|
||||||
|
NSOpenGLPixelFormat* format =
|
||||||
|
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||||
if (!format) {
|
if (!format) {
|
||||||
NS_WARNING("Failed to create NSOpenGLPixelFormat.");
|
NS_WARNING("Failed to create NSOpenGLPixelFormat.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nullptr];
|
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format
|
||||||
|
shareContext:nullptr];
|
||||||
|
|
||||||
[format release];
|
[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
|
// 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.
|
// 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
|
// In practice, on a Macbook Pro with an integrated and a discrete GPU, this
|
||||||
// display mask for the GPU that currently drives the internal display.
|
// function returns the display mask for the GPU that currently drives the
|
||||||
|
// internal display.
|
||||||
//
|
//
|
||||||
// Quick reference of the concepts involved in the code below:
|
// 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 switch: On Mac devices with an integrated and a discrete GPU, a GPU
|
||||||
// GPU drives the internal display. Both GPUs are still usable at all times. (When the
|
// switch changes which
|
||||||
// integrated GPU is driving the internal display, using the discrete GPU can incur a longer
|
// GPU drives the internal display. Both GPUs are still usable at all times.
|
||||||
// warm-up cost.)
|
// (When the integrated GPU is driving the internal display, using the
|
||||||
// Virtual screen: A CGL concept. A "virtual screen" corresponds to a GL renderer. There's one
|
// discrete GPU can incur a longer warm-up cost.)
|
||||||
// for the integrated GPU, one for each discrete GPU, and one for the Apple software renderer.
|
// Virtual screen: A CGL concept. A "virtual screen" corresponds to a GL
|
||||||
// The list of virtual screens is per-NSOpenGLPixelFormat; it is filtered down to only the
|
// renderer. There's one
|
||||||
// renderers that support the requirements from the pixel format attributes. Indexes into this
|
// for the integrated GPU, one for each discrete GPU, and one for the Apple
|
||||||
// list (such as currentVirtualScreen) cannot be used interchangably across different
|
// software renderer. The list of virtual screens is
|
||||||
// NSOpenGLPixelFormat instances.
|
// per-NSOpenGLPixelFormat; it is filtered down to only the renderers that
|
||||||
// Display mask: A bitset per GL renderer. Different renderers have disjoint display masks. The
|
// 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,
|
// Apple software renderer has all bits zeroed. For each CGDirectDisplayID,
|
||||||
// CGDisplayIDToOpenGLDisplayMask(displayID) returns a single bit in the display mask.
|
// CGDisplayIDToOpenGLDisplayMask(displayID) returns a single bit in the
|
||||||
// CGDirectDisplayID: An ID for each (physical screen, GPU which can drive this screen) pair. The
|
// display mask.
|
||||||
// current CGDirectDisplayID for an NSScreen object can be obtained using [[[screen
|
// CGDirectDisplayID: An ID for each (physical screen, GPU which can drive
|
||||||
// deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; it changes depending on
|
// this screen) pair. The
|
||||||
// which GPU is currently driving the screen.
|
// 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() {
|
static CGOpenGLDisplayMask GetFreshContextDisplayMask() {
|
||||||
NSOpenGLPixelFormatAttribute attribs[] = {NSOpenGLPFAAllowOfflineRenderers, 0};
|
NSOpenGLPixelFormatAttribute attribs[] = {NSOpenGLPFAAllowOfflineRenderers,
|
||||||
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
0};
|
||||||
|
NSOpenGLPixelFormat* pixelFormat =
|
||||||
|
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||||
MOZ_RELEASE_ASSERT(pixelFormat);
|
MOZ_RELEASE_ASSERT(pixelFormat);
|
||||||
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
|
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
|
||||||
shareContext:nullptr];
|
shareContext:nullptr];
|
||||||
|
|
@ -185,13 +203,15 @@ void GLContextCGL::MigrateToActiveGPU() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the "virtual screen" with a display mask that matches newPreferredDisplayMask, if
|
// Find the "virtual screen" with a display mask that matches
|
||||||
// available, and switch the context over to it.
|
// newPreferredDisplayMask, if available, and switch the context over to it.
|
||||||
// This code was inspired by equivalent functionality in -[NSOpenGLContext update] which only
|
// This code was inspired by equivalent functionality in -[NSOpenGLContext
|
||||||
// kicks in for contexts that present via a CAOpenGLLayer.
|
// update] which only kicks in for contexts that present via a CAOpenGLLayer.
|
||||||
for (const auto i : IntegerRange([pixelFormat numberOfVirtualScreens])) {
|
for (const auto i : IntegerRange([pixelFormat numberOfVirtualScreens])) {
|
||||||
GLint displayMask = 0;
|
GLint displayMask = 0;
|
||||||
[pixelFormat getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:i];
|
[pixelFormat getValues:&displayMask
|
||||||
|
forAttribute:NSOpenGLPFAScreenMask
|
||||||
|
forVirtualScreen:i];
|
||||||
if (IsSameGPU(displayMask, newPreferredDisplayMask)) {
|
if (IsSameGPU(displayMask, newPreferredDisplayMask)) {
|
||||||
CGLSetVirtualScreen([mContext CGLContextObj], i);
|
CGLSetVirtualScreen([mContext CGLContextObj], i);
|
||||||
return;
|
return;
|
||||||
|
|
@ -212,7 +232,9 @@ bool GLContextCGL::SwapBuffers() {
|
||||||
return true;
|
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 {
|
Maybe<SymbolLoader> GLContextCGL::GetSymbolLoader() const {
|
||||||
const auto& lib = sCGLLibrary.Library();
|
const auto& lib = sCGLLibrary.Library();
|
||||||
|
|
@ -220,7 +242,8 @@ Maybe<SymbolLoader> GLContextCGL::GetSymbolLoader() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
|
already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
|
||||||
CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) {
|
CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
|
||||||
|
bool aForceAccelerated) {
|
||||||
CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER;
|
CreateContextFlags flags = CreateContextFlags::ALLOW_OFFLINE_RENDERER;
|
||||||
if (aForceAccelerated) {
|
if (aForceAccelerated) {
|
||||||
flags |= CreateContextFlags::FORBID_SOFTWARE;
|
flags |= CreateContextFlags::FORBID_SOFTWARE;
|
||||||
|
|
@ -232,7 +255,8 @@ already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
|
||||||
return CreateHeadless({flags}, &failureUnused);
|
return CreateHeadless({flags}, &failureUnused);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc) {
|
static RefPtr<GLContextCGL> CreateOffscreenFBOContext(
|
||||||
|
GLContextCreateDesc desc) {
|
||||||
if (!sCGLLibrary.EnsureInitialized()) {
|
if (!sCGLLibrary.EnsureInitialized()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -247,8 +271,9 @@ static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc)
|
||||||
}
|
}
|
||||||
if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER ||
|
if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER ||
|
||||||
!(flags & CreateContextFlags::HIGH_POWER)) {
|
!(flags & CreateContextFlags::HIGH_POWER)) {
|
||||||
// This is really poorly named on Apple's part, but "AllowOfflineRenderers" means
|
// This is really poorly named on Apple's part, but "AllowOfflineRenderers"
|
||||||
// that we want to allow running on the iGPU instead of requiring the dGPU.
|
// means that we want to allow running on the iGPU instead of requiring the
|
||||||
|
// dGPU.
|
||||||
attribs.push_back(NSOpenGLPFAAllowOfflineRenderers);
|
attribs.push_back(NSOpenGLPFAAllowOfflineRenderers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,8 +323,8 @@ static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc)
|
||||||
return glContext;
|
return glContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(const GLContextCreateDesc& desc,
|
already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(
|
||||||
nsACString* const out_failureId) {
|
const GLContextCreateDesc& desc, nsACString* const out_failureId) {
|
||||||
auto gl = CreateOffscreenFBOContext(desc);
|
auto gl = CreateOffscreenFBOContext(desc);
|
||||||
if (!gl) {
|
if (!gl) {
|
||||||
*out_failureId = "FEATURE_FAILURE_CGL_FBO"_ns;
|
*out_failureId = "FEATURE_FAILURE_CGL_FBO"_ns;
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,8 @@ bool GLContextEAGL::AttachToWindow(nsIWidget* aWidget) {
|
||||||
// This should only be called once
|
// This should only be called once
|
||||||
MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
|
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) {
|
if (!view) {
|
||||||
MOZ_CRASH("no view!");
|
MOZ_CRASH("no view!");
|
||||||
|
|
@ -82,10 +83,11 @@ bool GLContextEAGL::RecreateRB() {
|
||||||
[mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer];
|
[mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER fromDrawable:layer];
|
||||||
|
|
||||||
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB);
|
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB);
|
||||||
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER,
|
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
|
||||||
mBackbufferRB);
|
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 {
|
bool GLContextEAGL::MakeCurrentImpl() const {
|
||||||
|
|
@ -97,7 +99,9 @@ bool GLContextEAGL::MakeCurrentImpl() const {
|
||||||
return true;
|
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) {
|
static PRFuncPtr GLAPIENTRY GetLoadedProcAddress(const char* const name) {
|
||||||
PRLibrary* lib = nullptr;
|
PRLibrary* lib = nullptr;
|
||||||
|
|
@ -121,7 +125,9 @@ bool GLContextEAGL::SwapBuffers() {
|
||||||
return true;
|
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() {
|
static GLContextEAGL* GetGlobalContextEAGL() {
|
||||||
return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
|
return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
|
||||||
|
|
@ -129,14 +135,16 @@ static GLContextEAGL* GetGlobalContextEAGL() {
|
||||||
|
|
||||||
static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
|
static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
|
||||||
GLContextEAGL* sharedContext) {
|
GLContextEAGL* sharedContext) {
|
||||||
EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3, kEAGLRenderingAPIOpenGLES2};
|
EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3,
|
||||||
|
kEAGLRenderingAPIOpenGLES2};
|
||||||
|
|
||||||
// Try to create a GLES3 context if we can, otherwise fall back to GLES2
|
// Try to create a GLES3 context if we can, otherwise fall back to GLES2
|
||||||
EAGLContext* context = nullptr;
|
EAGLContext* context = nullptr;
|
||||||
for (EAGLRenderingAPI api : apis) {
|
for (EAGLRenderingAPI api : apis) {
|
||||||
if (sharedContext) {
|
if (sharedContext) {
|
||||||
context = [[EAGLContext alloc] initWithAPI:api
|
context = [[EAGLContext alloc]
|
||||||
sharegroup:sharedContext->GetEAGLContext().sharegroup];
|
initWithAPI:api
|
||||||
|
sharegroup:sharedContext->GetEAGLContext().sharegroup];
|
||||||
} else {
|
} else {
|
||||||
context = [[EAGLContext alloc] initWithAPI:api];
|
context = [[EAGLContext alloc] initWithAPI:api];
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +158,8 @@ static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<GLContextEAGL> glContext = new GLContextEAGL(desc, context, sharedContext);
|
RefPtr<GLContextEAGL> glContext =
|
||||||
|
new GLContextEAGL(desc, context, sharedContext);
|
||||||
if (!glContext->Init()) {
|
if (!glContext->Init()) {
|
||||||
glContext = nullptr;
|
glContext = nullptr;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -160,7 +169,8 @@ static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
|
already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
|
||||||
CompositorWidget* aCompositorWidget, bool aHardwareWebRender, bool aForceAccelerated) {
|
CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
|
||||||
|
bool aForceAccelerated) {
|
||||||
if (!aCompositorWidget) {
|
if (!aCompositorWidget) {
|
||||||
MOZ_ASSERT(false);
|
MOZ_ASSERT(false);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -172,7 +182,8 @@ already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aCompositorWidget->RealWidget())) {
|
if (!GLContextEAGL::Cast(glContext)->AttachToWindow(
|
||||||
|
aCompositorWidget->RealWidget())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,7 +204,8 @@ GLContext* GLContextProviderEAGL::GetGlobalContext() {
|
||||||
if (!triedToCreateContext) {
|
if (!triedToCreateContext) {
|
||||||
triedToCreateContext = true;
|
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);
|
RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE);
|
||||||
gGlobalContext = temp;
|
gGlobalContext = temp;
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
@ -36,11 +36,13 @@ using gl::GLContextCGL;
|
||||||
|
|
||||||
// SurfacePoolCA::LockedPool
|
// SurfacePoolCA::LockedPool
|
||||||
|
|
||||||
SurfacePoolCA::LockedPool::LockedPool(size_t aPoolSizeLimit) : mPoolSizeLimit(aPoolSizeLimit) {}
|
SurfacePoolCA::LockedPool::LockedPool(size_t aPoolSizeLimit)
|
||||||
|
: mPoolSizeLimit(aPoolSizeLimit) {}
|
||||||
|
|
||||||
SurfacePoolCA::LockedPool::~LockedPool() {
|
SurfacePoolCA::LockedPool::~LockedPool() {
|
||||||
MOZ_RELEASE_ASSERT(mWrappers.empty(),
|
MOZ_RELEASE_ASSERT(
|
||||||
"Any outstanding wrappers should have kept the surface pool alive");
|
mWrappers.empty(),
|
||||||
|
"Any outstanding wrappers should have kept the surface pool alive");
|
||||||
MOZ_RELEASE_ASSERT(mInUseEntries.empty(),
|
MOZ_RELEASE_ASSERT(mInUseEntries.empty(),
|
||||||
"Leak! No more surfaces should be in use at this point.");
|
"Leak! No more surfaces should be in use at this point.");
|
||||||
// Remove all entries in mPendingEntries and mAvailableEntries.
|
// Remove all entries in mPendingEntries and mAvailableEntries.
|
||||||
|
|
@ -50,8 +52,8 @@ SurfacePoolCA::LockedPool::~LockedPool() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<SurfacePoolCAWrapperForGL> SurfacePoolCA::LockedPool::GetWrapperForGL(SurfacePoolCA* aPool,
|
RefPtr<SurfacePoolCAWrapperForGL> SurfacePoolCA::LockedPool::GetWrapperForGL(
|
||||||
GLContext* aGL) {
|
SurfacePoolCA* aPool, GLContext* aGL) {
|
||||||
auto& wrapper = mWrappers[aGL];
|
auto& wrapper = mWrappers[aGL];
|
||||||
if (!wrapper) {
|
if (!wrapper) {
|
||||||
wrapper = new SurfacePoolCAWrapperForGL(aPool, aGL);
|
wrapper = new SurfacePoolCAWrapperForGL(aPool, aGL);
|
||||||
|
|
@ -71,7 +73,8 @@ void SurfacePoolCA::LockedPool::DestroyGLResourcesForContext(GLContext* aGL) {
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
void SurfacePoolCA::LockedPool::MutateEntryStorage(const char* aMutationType,
|
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 inUseCountBefore = mInUseEntries.size();
|
||||||
[[maybe_unused]] size_t pendingCountBefore = mPendingEntries.Length();
|
[[maybe_unused]] size_t pendingCountBefore = mPendingEntries.Length();
|
||||||
[[maybe_unused]] size_t availableCountBefore = mAvailableEntries.Length();
|
[[maybe_unused]] size_t availableCountBefore = mAvailableEntries.Length();
|
||||||
|
|
@ -84,9 +87,11 @@ void SurfacePoolCA::LockedPool::MutateEntryStorage(const char* aMutationType,
|
||||||
"SurfacePool", GRAPHICS, MarkerTiming::IntervalUntilNowFrom(before),
|
"SurfacePool", GRAPHICS, MarkerTiming::IntervalUntilNowFrom(before),
|
||||||
nsPrintfCString("%d -> %d in use | %d -> %d waiting for | %d -> %d "
|
nsPrintfCString("%d -> %d in use | %d -> %d waiting for | %d -> %d "
|
||||||
"available | %s %dx%d | %dMB total memory",
|
"available | %s %dx%d | %dMB total memory",
|
||||||
int(inUseCountBefore), int(mInUseEntries.size()), int(pendingCountBefore),
|
int(inUseCountBefore), int(mInUseEntries.size()),
|
||||||
int(mPendingEntries.Length()), int(availableCountBefore),
|
int(pendingCountBefore), int(mPendingEntries.Length()),
|
||||||
int(mAvailableEntries.Length()), aMutationType, aSize.width, aSize.height,
|
int(availableCountBefore),
|
||||||
|
int(mAvailableEntries.Length()), aMutationType,
|
||||||
|
aSize.width, aSize.height,
|
||||||
int(EstimateTotalMemory() / 1000 / 1000)));
|
int(EstimateTotalMemory() / 1000 / 1000)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -126,8 +131,8 @@ uint64_t SurfacePoolCA::LockedPool::EstimateTotalMemory() {
|
||||||
return memBytes;
|
return memBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(const SurfacePoolEntry& aEntry,
|
bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(
|
||||||
const IntSize& aSize, GLContext* aGL) {
|
const SurfacePoolEntry& aEntry, const IntSize& aSize, GLContext* aGL) {
|
||||||
if (aEntry.mSize != aSize) {
|
if (aEntry.mSize != aSize) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -137,14 +142,16 @@ bool SurfacePoolCA::LockedPool::CanRecycleSurfaceForRequest(const SurfacePoolEnt
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(const IntSize& aSize,
|
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(
|
||||||
GLContext* aGL) {
|
const IntSize& aSize, GLContext* aGL) {
|
||||||
// Do a linear scan through mAvailableEntries to find an eligible surface, going from oldest to
|
// Do a linear scan through mAvailableEntries to find an eligible surface,
|
||||||
// newest. The size of this array is limited, so the linear scan is fast.
|
// going from oldest to newest. The size of this array is limited, so the
|
||||||
auto iterToRecycle = std::find_if(mAvailableEntries.begin(), mAvailableEntries.end(),
|
// linear scan is fast.
|
||||||
[&](const SurfacePoolEntry& aEntry) {
|
auto iterToRecycle =
|
||||||
return CanRecycleSurfaceForRequest(aEntry, aSize, aGL);
|
std::find_if(mAvailableEntries.begin(), mAvailableEntries.end(),
|
||||||
});
|
[&](const SurfacePoolEntry& aEntry) {
|
||||||
|
return CanRecycleSurfaceForRequest(aEntry, aSize, aGL);
|
||||||
|
});
|
||||||
if (iterToRecycle != mAvailableEntries.end()) {
|
if (iterToRecycle != mAvailableEntries.end()) {
|
||||||
CFTypeRefPtr<IOSurfaceRef> surface = iterToRecycle->mIOSurface;
|
CFTypeRefPtr<IOSurfaceRef> surface = iterToRecycle->mIOSurface;
|
||||||
MOZ_RELEASE_ASSERT(surface.get(), "Available surfaces should be non-null.");
|
MOZ_RELEASE_ASSERT(surface.get(), "Available surfaces should be non-null.");
|
||||||
|
|
@ -156,18 +163,22 @@ CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(cons
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("IOSurface creation", GRAPHICS_TileAllocation,
|
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
|
||||||
nsPrintfCString("%dx%d", aSize.width, aSize.height));
|
"IOSurface creation", GRAPHICS_TileAllocation,
|
||||||
|
nsPrintfCString("%dx%d", aSize.width, aSize.height));
|
||||||
CFTypeRefPtr<IOSurfaceRef> surface =
|
CFTypeRefPtr<IOSurfaceRef> surface =
|
||||||
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(IOSurfaceCreate((__bridge CFDictionaryRef) @{
|
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
|
||||||
(__bridge NSString*)kIOSurfaceWidth : @(aSize.width),
|
IOSurfaceCreate((__bridge CFDictionaryRef) @{
|
||||||
(__bridge NSString*)kIOSurfaceHeight : @(aSize.height),
|
(__bridge NSString*)kIOSurfaceWidth : @(aSize.width),
|
||||||
(__bridge NSString*)kIOSurfacePixelFormat : @(kCVPixelFormatType_32BGRA),
|
(__bridge NSString*)kIOSurfaceHeight : @(aSize.height),
|
||||||
(__bridge NSString*)kIOSurfaceBytesPerElement : @(4),
|
(__bridge NSString*)
|
||||||
}));
|
kIOSurfacePixelFormat : @(kCVPixelFormatType_32BGRA),
|
||||||
|
(__bridge NSString*)kIOSurfaceBytesPerElement : @(4),
|
||||||
|
}));
|
||||||
if (surface) {
|
if (surface) {
|
||||||
if (StaticPrefs::gfx_color_management_native_srgb()) {
|
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.
|
// Create a new entry in mInUseEntries.
|
||||||
MutateEntryStorage("Create", aSize, [&]() {
|
MutateEntryStorage("Create", aSize, [&]() {
|
||||||
|
|
@ -177,16 +188,18 @@ CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::LockedPool::ObtainSurfaceFromPool(cons
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> aSurface) {
|
void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(
|
||||||
|
CFTypeRefPtr<IOSurfaceRef> aSurface) {
|
||||||
auto inUseEntryIter = mInUseEntries.find(aSurface);
|
auto inUseEntryIter = mInUseEntries.find(aSurface);
|
||||||
MOZ_RELEASE_ASSERT(inUseEntryIter != mInUseEntries.end());
|
MOZ_RELEASE_ASSERT(inUseEntryIter != mInUseEntries.end());
|
||||||
if (IOSurfaceIsInUse(aSurface.get())) {
|
if (IOSurfaceIsInUse(aSurface.get())) {
|
||||||
// Move the entry from mInUseEntries to mPendingEntries.
|
// Move the entry from mInUseEntries to mPendingEntries.
|
||||||
MutateEntryStorage("Start waiting for", IntSize(inUseEntryIter->second.mSize), [&]() {
|
MutateEntryStorage(
|
||||||
mPendingEntries.AppendElement(
|
"Start waiting for", IntSize(inUseEntryIter->second.mSize), [&]() {
|
||||||
PendingSurfaceEntry{std::move(inUseEntryIter->second), mCollectionGeneration, 0});
|
mPendingEntries.AppendElement(PendingSurfaceEntry{
|
||||||
mInUseEntries.erase(inUseEntryIter);
|
std::move(inUseEntryIter->second), mCollectionGeneration, 0});
|
||||||
});
|
mInUseEntries.erase(inUseEntryIter);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// Move the entry from mInUseEntries to mAvailableEntries.
|
// Move the entry from mInUseEntries to mAvailableEntries.
|
||||||
MOZ_RELEASE_ASSERT(inUseEntryIter->second.mIOSurface.get(),
|
MOZ_RELEASE_ASSERT(inUseEntryIter->second.mIOSurface.get(),
|
||||||
|
|
@ -199,14 +212,16 @@ void SurfacePoolCA::LockedPool::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> a
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfacePoolCA::LockedPool::EnforcePoolSizeLimit() {
|
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) {
|
while (mAvailableEntries.Length() > mPoolSizeLimit) {
|
||||||
MutateEntryStorage("Evict", IntSize(mAvailableEntries[0].mSize),
|
MutateEntryStorage("Evict", IntSize(mAvailableEntries[0].mSize),
|
||||||
[&]() { mAvailableEntries.RemoveElementAt(0); });
|
[&]() { mAvailableEntries.RemoveElementAt(0); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(uint64_t aCheckGenerationsUpTo) {
|
uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(
|
||||||
|
uint64_t aCheckGenerationsUpTo) {
|
||||||
mCollectionGeneration++;
|
mCollectionGeneration++;
|
||||||
|
|
||||||
// Loop from back to front, potentially deleting items as we iterate.
|
// 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) {
|
if (pendingSurf.mPreviousCheckGeneration > aCheckGenerationsUpTo) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Check if the window server is still using the surface. As long as it is doing that, we cannot
|
// Check if the window server is still using the surface. As long as it is
|
||||||
// move the surface to mAvailableSurfaces because anything we draw to it could reach the screen
|
// doing that, we cannot move the surface to mAvailableSurfaces because
|
||||||
// in a place where we don't expect it.
|
// anything we draw to it could reach the screen in a place where we don't
|
||||||
|
// expect it.
|
||||||
if (IOSurfaceIsInUse(pendingSurf.mEntry.mIOSurface.get())) {
|
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.mPreviousCheckGeneration = mCollectionGeneration;
|
||||||
pendingSurf.mCheckCount++;
|
pendingSurf.mCheckCount++;
|
||||||
if (pendingSurf.mCheckCount >= 30) {
|
if (pendingSurf.mCheckCount >= 30) {
|
||||||
// The window server has been holding on to this surface for an unreasonably long time. This
|
// The window server has been holding on to this surface for an
|
||||||
// is known to happen sometimes, for example in occluded windows or after a GPU switch. In
|
// unreasonably long time. This is known to happen sometimes, for
|
||||||
// that case, release our references to the surface so that it's Not Our Problem anymore.
|
// example in occluded windows or after a GPU switch. In that case,
|
||||||
// Remove the entry from mPendingEntries.
|
// 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),
|
MutateEntryStorage("Eject", IntSize(pendingSurf.mEntry.mSize),
|
||||||
[&]() { mPendingEntries.RemoveElementAt(i); });
|
[&]() { mPendingEntries.RemoveElementAt(i); });
|
||||||
}
|
}
|
||||||
|
|
@ -238,30 +256,33 @@ uint64_t SurfacePoolCA::LockedPool::CollectPendingSurfaces(uint64_t aCheckGenera
|
||||||
// Move the entry from mPendingEntries to mAvailableEntries.
|
// Move the entry from mPendingEntries to mAvailableEntries.
|
||||||
MOZ_RELEASE_ASSERT(pendingSurf.mEntry.mIOSurface.get(),
|
MOZ_RELEASE_ASSERT(pendingSurf.mEntry.mIOSurface.get(),
|
||||||
"Pending surfaces should be non-null.");
|
"Pending surfaces should be non-null.");
|
||||||
MutateEntryStorage("Stop waiting for", IntSize(pendingSurf.mEntry.mSize), [&]() {
|
MutateEntryStorage(
|
||||||
mAvailableEntries.AppendElement(std::move(pendingSurf.mEntry));
|
"Stop waiting for", IntSize(pendingSurf.mEntry.mSize), [&]() {
|
||||||
mPendingEntries.RemoveElementAt(i);
|
mAvailableEntries.AppendElement(std::move(pendingSurf.mEntry));
|
||||||
});
|
mPendingEntries.RemoveElementAt(i);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mCollectionGeneration;
|
return mCollectionGeneration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfacePoolCA::LockedPool::OnWrapperDestroyed(gl::GLContext* aGL,
|
void SurfacePoolCA::LockedPool::OnWrapperDestroyed(
|
||||||
SurfacePoolCAWrapperForGL* aWrapper) {
|
gl::GLContext* aGL, SurfacePoolCAWrapperForGL* aWrapper) {
|
||||||
if (aGL) {
|
if (aGL) {
|
||||||
DestroyGLResourcesForContext(aGL);
|
DestroyGLResourcesForContext(aGL);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = mWrappers.find(aGL);
|
auto iter = mWrappers.find(aGL);
|
||||||
MOZ_RELEASE_ASSERT(iter != mWrappers.end());
|
MOZ_RELEASE_ASSERT(iter != mWrappers.end());
|
||||||
MOZ_RELEASE_ASSERT(iter->second == aWrapper, "Only one SurfacePoolCAWrapperForGL object should "
|
MOZ_RELEASE_ASSERT(iter->second == aWrapper,
|
||||||
"exist for each GLContext* at any time");
|
"Only one SurfacePoolCAWrapperForGL object should "
|
||||||
|
"exist for each GLContext* at any time");
|
||||||
mWrappers.erase(iter);
|
mWrappers.erase(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
||||||
CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL, bool aNeedsDepthBuffer) {
|
CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL,
|
||||||
|
bool aNeedsDepthBuffer) {
|
||||||
MOZ_RELEASE_ASSERT(aGL);
|
MOZ_RELEASE_ASSERT(aGL);
|
||||||
|
|
||||||
auto inUseEntryIter = mInUseEntries.find(aSurface);
|
auto inUseEntryIter = mInUseEntries.find(aSurface);
|
||||||
|
|
@ -271,7 +292,8 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
||||||
if (entry.mGLResources) {
|
if (entry.mGLResources) {
|
||||||
// We have an existing framebuffer.
|
// We have an existing framebuffer.
|
||||||
MOZ_RELEASE_ASSERT(entry.mGLResources->mGLContext == aGL,
|
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.");
|
"This shouldn't happen.");
|
||||||
if (!aNeedsDepthBuffer || entry.mGLResources->mFramebuffer->HasDepth()) {
|
if (!aNeedsDepthBuffer || entry.mGLResources->mFramebuffer->HasDepth()) {
|
||||||
return Some(entry.mGLResources->mFramebuffer->mFB);
|
return Some(entry.mGLResources->mFramebuffer->mFB);
|
||||||
|
|
@ -294,13 +316,16 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
||||||
|
|
||||||
GLuint tex = aGL->CreateTexture();
|
GLuint tex = aGL->CreateTexture();
|
||||||
{
|
{
|
||||||
const gl::ScopedBindTexture bindTex(aGL, tex, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
const gl::ScopedBindTexture bindTex(aGL, tex,
|
||||||
CGLTexImageIOSurface2D(cgl->GetCGLContext(), LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_RGBA,
|
LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
||||||
entry.mSize.width, entry.mSize.height, LOCAL_GL_BGRA,
|
CGLTexImageIOSurface2D(cgl->GetCGLContext(), LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||||
LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, entry.mIOSurface.get(), 0);
|
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) {
|
if (!fb) {
|
||||||
// Framebuffer completeness check may have failed.
|
// Framebuffer completeness check may have failed.
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -311,10 +336,12 @@ Maybe<GLuint> SurfacePoolCA::LockedPool::GetFramebufferForSurface(
|
||||||
return Some(fbo);
|
return Some(fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<gl::DepthAndStencilBuffer> SurfacePoolCA::LockedPool::GetDepthBufferForSharing(
|
RefPtr<gl::DepthAndStencilBuffer>
|
||||||
GLContext* aGL, const IntSize& aSize) {
|
SurfacePoolCA::LockedPool::GetDepthBufferForSharing(GLContext* aGL,
|
||||||
|
const IntSize& aSize) {
|
||||||
// Clean out entries for which the weak pointer has become null.
|
// 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) {
|
for (const auto& entry : mDepthBuffers) {
|
||||||
if (entry.mGLContext == aGL && entry.mSize == aSize) {
|
if (entry.mGLContext == aGL && entry.mSize == aSize) {
|
||||||
|
|
@ -324,22 +351,29 @@ RefPtr<gl::DepthAndStencilBuffer> SurfacePoolCA::LockedPool::GetDepthBufferForSh
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniquePtr<gl::MozFramebuffer> SurfacePoolCA::LockedPool::CreateFramebufferForTexture(
|
UniquePtr<gl::MozFramebuffer>
|
||||||
GLContext* aGL, const IntSize& aSize, GLuint aTexture, bool aNeedsDepthBuffer) {
|
SurfacePoolCA::LockedPool::CreateFramebufferForTexture(GLContext* aGL,
|
||||||
|
const IntSize& aSize,
|
||||||
|
GLuint aTexture,
|
||||||
|
bool aNeedsDepthBuffer) {
|
||||||
if (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)) {
|
if (auto buffer = GetDepthBufferForSharing(aGL, aSize)) {
|
||||||
return gl::MozFramebuffer::CreateForBackingWithSharedDepthAndStencil(
|
return gl::MozFramebuffer::CreateForBackingWithSharedDepthAndStencil(
|
||||||
aSize, 0, LOCAL_GL_TEXTURE_RECTANGLE_ARB, aTexture, buffer);
|
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
|
// No depth buffer needed or we didn't find one. Create a framebuffer with a
|
||||||
// store a weak pointer to the new depth buffer in mDepthBuffers.
|
// new depth buffer and store a weak pointer to the new depth buffer in
|
||||||
|
// mDepthBuffers.
|
||||||
UniquePtr<gl::MozFramebuffer> fb = gl::MozFramebuffer::CreateForBacking(
|
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()) {
|
if (fb && fb->GetDepthAndStencilBuffer()) {
|
||||||
mDepthBuffers.AppendElement(DepthBufferEntry{aGL, aSize, fb->GetDepthAndStencilBuffer().get()});
|
mDepthBuffers.AppendElement(
|
||||||
|
DepthBufferEntry{aGL, aSize, fb->GetDepthAndStencilBuffer().get()});
|
||||||
}
|
}
|
||||||
|
|
||||||
return fb;
|
return fb;
|
||||||
|
|
@ -347,8 +381,9 @@ UniquePtr<gl::MozFramebuffer> SurfacePoolCA::LockedPool::CreateFramebufferForTex
|
||||||
|
|
||||||
// SurfacePoolHandleCA
|
// SurfacePoolHandleCA
|
||||||
|
|
||||||
SurfacePoolHandleCA::SurfacePoolHandleCA(RefPtr<SurfacePoolCAWrapperForGL>&& aPoolWrapper,
|
SurfacePoolHandleCA::SurfacePoolHandleCA(
|
||||||
uint64_t aCurrentCollectionGeneration)
|
RefPtr<SurfacePoolCAWrapperForGL>&& aPoolWrapper,
|
||||||
|
uint64_t aCurrentCollectionGeneration)
|
||||||
: mPoolWrapper(aPoolWrapper),
|
: mPoolWrapper(aPoolWrapper),
|
||||||
mPreviousFrameCollectionGeneration(
|
mPreviousFrameCollectionGeneration(
|
||||||
"SurfacePoolHandleCA::mPreviousFrameCollectionGeneration") {
|
"SurfacePoolHandleCA::mPreviousFrameCollectionGeneration") {
|
||||||
|
|
@ -363,20 +398,24 @@ void SurfacePoolHandleCA::OnBeginFrame() {
|
||||||
*generation = mPoolWrapper->mPool->CollectPendingSurfaces(*generation);
|
*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);
|
return mPoolWrapper->mPool->ObtainSurfaceFromPool(aSize, mPoolWrapper->mGL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfacePoolHandleCA::ReturnSurfaceToPool(CFTypeRefPtr<IOSurfaceRef> aSurface) {
|
void SurfacePoolHandleCA::ReturnSurfaceToPool(
|
||||||
|
CFTypeRefPtr<IOSurfaceRef> aSurface) {
|
||||||
mPoolWrapper->mPool->ReturnSurfaceToPool(aSurface);
|
mPoolWrapper->mPool->ReturnSurfaceToPool(aSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<GLuint> SurfacePoolHandleCA::GetFramebufferForSurface(CFTypeRefPtr<IOSurfaceRef> aSurface,
|
Maybe<GLuint> SurfacePoolHandleCA::GetFramebufferForSurface(
|
||||||
bool aNeedsDepthBuffer) {
|
CFTypeRefPtr<IOSurfaceRef> aSurface, bool aNeedsDepthBuffer) {
|
||||||
return mPoolWrapper->mPool->GetFramebufferForSurface(aSurface, mPoolWrapper->mGL,
|
return mPoolWrapper->mPool->GetFramebufferForSurface(
|
||||||
aNeedsDepthBuffer);
|
aSurface, mPoolWrapper->mGL, aNeedsDepthBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SurfacePoolCA
|
// SurfacePoolCA
|
||||||
|
|
@ -405,8 +444,8 @@ void SurfacePoolCA::DestroyGLResourcesForContext(GLContext* aGL) {
|
||||||
pool->DestroyGLResourcesForContext(aGL);
|
pool->DestroyGLResourcesForContext(aGL);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::ObtainSurfaceFromPool(const IntSize& aSize,
|
CFTypeRefPtr<IOSurfaceRef> SurfacePoolCA::ObtainSurfaceFromPool(
|
||||||
GLContext* aGL) {
|
const IntSize& aSize, GLContext* aGL) {
|
||||||
auto pool = mPool.Lock();
|
auto pool = mPool.Lock();
|
||||||
return pool->ObtainSurfaceFromPool(aSize, aGL);
|
return pool->ObtainSurfaceFromPool(aSize, aGL);
|
||||||
}
|
}
|
||||||
|
|
@ -425,13 +464,15 @@ void SurfacePoolCA::EnforcePoolSizeLimit() {
|
||||||
pool->EnforcePoolSizeLimit();
|
pool->EnforcePoolSizeLimit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<GLuint> SurfacePoolCA::GetFramebufferForSurface(CFTypeRefPtr<IOSurfaceRef> aSurface,
|
Maybe<GLuint> SurfacePoolCA::GetFramebufferForSurface(
|
||||||
GLContext* aGL, bool aNeedsDepthBuffer) {
|
CFTypeRefPtr<IOSurfaceRef> aSurface, GLContext* aGL,
|
||||||
|
bool aNeedsDepthBuffer) {
|
||||||
auto pool = mPool.Lock();
|
auto pool = mPool.Lock();
|
||||||
return pool->GetFramebufferForSurface(aSurface, aGL, aNeedsDepthBuffer);
|
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();
|
auto pool = mPool.Lock();
|
||||||
return pool->OnWrapperDestroyed(aGL, aWrapper);
|
return pool->OnWrapperDestroyed(aGL, aWrapper);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,14 @@
|
||||||
|
|
||||||
namespace mozilla::gfx {
|
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,
|
PrintTargetCG::PrintTargetCG(CGContextRef aPrintToStreamContext,
|
||||||
PMPageFormat aPageFormat, PMPrintSettings aPrintSettings,
|
PMPrintSession aPrintSession,
|
||||||
|
PMPageFormat aPageFormat,
|
||||||
|
PMPrintSettings aPrintSettings,
|
||||||
const IntSize& aSize)
|
const IntSize& aSize)
|
||||||
: PrintTarget(/* aCairoSurface */ nullptr, aSize),
|
: PrintTarget(/* aCairoSurface */ nullptr, aSize),
|
||||||
mPrintToStreamContext(aPrintToStreamContext),
|
mPrintToStreamContext(aPrintToStreamContext),
|
||||||
|
|
@ -53,14 +57,16 @@ PrintTargetCG::~PrintTargetCG() {
|
||||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
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* stream = static_cast<nsIOutputStream*>(aInfo);
|
||||||
auto* data = static_cast<const char*>(aBuffer);
|
auto* data = static_cast<const char*>(aBuffer);
|
||||||
size_t remaining = aCount;
|
size_t remaining = aCount;
|
||||||
do {
|
do {
|
||||||
uint32_t wrote = 0;
|
uint32_t wrote = 0;
|
||||||
// Handle potential narrowing from size_t to uint32_t.
|
// 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)))) {
|
if (NS_WARN_IF(NS_FAILED(stream->Write(data, toWrite, &wrote)))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -87,21 +93,25 @@ static CGContextRef CreatePrintToStreamContext(nsIOutputStream* aOutputStream,
|
||||||
CGDataConsumerRef consumer = CGDataConsumerCreate(aOutputStream, &callbacks);
|
CGDataConsumerRef consumer = CGDataConsumerCreate(aOutputStream, &callbacks);
|
||||||
|
|
||||||
// This metadata is added by the CorePrinting APIs in the non-stream case.
|
// This metadata is added by the CorePrinting APIs in the non-stream case.
|
||||||
NSString* bundleName =
|
NSString* bundleName = [NSBundle.mainBundle.localizedInfoDictionary
|
||||||
[NSBundle.mainBundle.localizedInfoDictionary objectForKey:(NSString*)kCFBundleNameKey];
|
objectForKey:(NSString*)kCFBundleNameKey];
|
||||||
CFMutableDictionaryRef auxiliaryInfo = CFDictionaryCreateMutable(
|
CFMutableDictionaryRef auxiliaryInfo = CFDictionaryCreateMutable(
|
||||||
kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks,
|
||||||
CFDictionaryAddValue(auxiliaryInfo, kCGPDFContextCreator, (__bridge CFStringRef)bundleName);
|
&kCFTypeDictionaryValueCallBacks);
|
||||||
|
CFDictionaryAddValue(auxiliaryInfo, kCGPDFContextCreator,
|
||||||
|
(__bridge CFStringRef)bundleName);
|
||||||
|
|
||||||
CGContextRef pdfContext = CGPDFContextCreate(consumer, &pageBox, auxiliaryInfo);
|
CGContextRef pdfContext =
|
||||||
|
CGPDFContextCreate(consumer, &pageBox, auxiliaryInfo);
|
||||||
CGDataConsumerRelease(consumer);
|
CGDataConsumerRelease(consumer);
|
||||||
CFRelease(auxiliaryInfo);
|
CFRelease(auxiliaryInfo);
|
||||||
return pdfContext;
|
return pdfContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ already_AddRefed<PrintTargetCG> PrintTargetCG::CreateOrNull(
|
/* static */ already_AddRefed<PrintTargetCG> PrintTargetCG::CreateOrNull(
|
||||||
nsIOutputStream* aOutputStream, PMPrintSession aPrintSession, PMPageFormat aPageFormat,
|
nsIOutputStream* aOutputStream, PMPrintSession aPrintSession,
|
||||||
PMPrintSettings aPrintSettings, const IntSize& aSize) {
|
PMPageFormat aPageFormat, PMPrintSettings aPrintSettings,
|
||||||
|
const IntSize& aSize) {
|
||||||
if (!Factory::CheckSurfaceSize(aSize)) {
|
if (!Factory::CheckSurfaceSize(aSize)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -114,8 +124,8 @@ static CGContextRef CreatePrintToStreamContext(nsIOutputStream* aOutputStream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<PrintTargetCG> target =
|
RefPtr<PrintTargetCG> target = new PrintTargetCG(
|
||||||
new PrintTargetCG(printToStreamContext, aPrintSession, aPageFormat, aPrintSettings, aSize);
|
printToStreamContext, aPrintSession, aPageFormat, aPrintSettings, aSize);
|
||||||
|
|
||||||
return target.forget();
|
return target.forget();
|
||||||
}
|
}
|
||||||
|
|
@ -129,8 +139,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
|
||||||
CGContextRef pdfContext = CGPDFContextCreate(consumer, nullptr, nullptr);
|
CGContextRef pdfContext = CGPDFContextCreate(consumer, nullptr, nullptr);
|
||||||
CGDataConsumerRelease(consumer);
|
CGDataConsumerRelease(consumer);
|
||||||
|
|
||||||
cairo_surface_t* similar =
|
cairo_surface_t* similar = cairo_quartz_surface_create_for_cg_context(
|
||||||
cairo_quartz_surface_create_for_cg_context(pdfContext, size.width, size.height);
|
pdfContext, size.width, size.height);
|
||||||
|
|
||||||
CGContextRelease(pdfContext);
|
CGContextRelease(pdfContext);
|
||||||
|
|
||||||
|
|
@ -138,7 +148,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
|
||||||
return nullptr;
|
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:
|
// The DT addrefs the surface, so we need drop our own reference to it:
|
||||||
cairo_surface_destroy(similar);
|
cairo_surface_destroy(similar);
|
||||||
|
|
@ -152,7 +163,8 @@ already_AddRefed<DrawTarget> PrintTargetCG::GetReferenceDrawTarget() {
|
||||||
return do_AddRef(mRefDT);
|
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) {
|
int32_t aStartPage, int32_t aEndPage) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
|
|
@ -182,7 +194,8 @@ nsresult PrintTargetCG::BeginPrinting(const nsAString& aTitle, const nsAString&
|
||||||
status = ::PMSetLastPage(mPrintSettings, aEndPage, false);
|
status = ::PMSetLastPage(mPrintSettings, aEndPage, false);
|
||||||
NS_ASSERTION(status == noErr, "PMSetLastPage failed");
|
NS_ASSERTION(status == noErr, "PMSetLastPage failed");
|
||||||
|
|
||||||
status = ::PMSessionBeginCGDocumentNoDialog(mPrintSession, mPrintSettings, mPageFormat);
|
status = ::PMSessionBeginCGDocumentNoDialog(mPrintSession, mPrintSettings,
|
||||||
|
mPageFormat);
|
||||||
|
|
||||||
return status == noErr ? NS_OK : NS_ERROR_ABORT;
|
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()) {
|
if (StaticPrefs::layout_css_page_orientation_enabled()) {
|
||||||
::PMOrientation pageOrientation =
|
::PMOrientation pageOrientation =
|
||||||
aSizeInPoints.width < aSizeInPoints.height ? kPMPortrait : kPMLandscape;
|
aSizeInPoints.width < aSizeInPoints.height ? kPMPortrait
|
||||||
|
: kPMLandscape;
|
||||||
::PMSetOrientation(mPageFormat, pageOrientation, kPMUnlocked);
|
::PMSetOrientation(mPageFormat, pageOrientation, kPMUnlocked);
|
||||||
// We don't need to reset the orientation, since we set it for every page.
|
// 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) {
|
if (status != noErr) {
|
||||||
return NS_ERROR_ABORT;
|
return NS_ERROR_ABORT;
|
||||||
}
|
}
|
||||||
|
|
@ -257,7 +272,8 @@ nsresult PrintTargetCG::BeginPage(const IntSize& aSizeInPoints) {
|
||||||
CGContextTranslateCTM(context, 0, height);
|
CGContextTranslateCTM(context, 0, height);
|
||||||
CGContextScaleCTM(context, 1.0, -1.0);
|
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)) {
|
if (cairo_surface_status(surface)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,9 @@ static void GetStringForNSString(const NSString* aSrc, nsAString& aDest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSString* GetNSStringForString(const nsAString& aSrc) {
|
static NSString* GetNSStringForString(const nsAString& aSrc) {
|
||||||
return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading())
|
return [NSString
|
||||||
length:aSrc.Length()];
|
stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading())
|
||||||
|
length:aSrc.Length()];
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LOG_FONTLIST(args) \
|
#define LOG_FONTLIST(args) \
|
||||||
|
|
@ -77,7 +78,8 @@ static NSString* GetNSStringForString(const nsAString& aSrc) {
|
||||||
class gfxMacFontFamily final : public CTFontFamily {
|
class gfxMacFontFamily final : public CTFontFamily {
|
||||||
public:
|
public:
|
||||||
gfxMacFontFamily(const nsACString& aName, NSFont* aSystemFont)
|
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,
|
// 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
|
// but to be on the safe side let's retain a reference until we're finished
|
||||||
// using it for lazy initialization.
|
// using it for lazy initialization.
|
||||||
|
|
@ -88,9 +90,9 @@ class gfxMacFontFamily final : public CTFontFamily {
|
||||||
MOZ_REQUIRES(mLock) override;
|
MOZ_REQUIRES(mLock) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// If non-null, this is a family representing the system UI font, and should use
|
// If non-null, this is a family representing the system UI font, and should
|
||||||
// the given NSFont as the basis for initialization as the normal font-manager APIs
|
// use the given NSFont as the basis for initialization as the normal
|
||||||
// based on family name won't handle it.
|
// font-manager APIs based on family name won't handle it.
|
||||||
NSFont* mForSystemFont = nullptr;
|
NSFont* mForSystemFont = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -99,7 +101,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxMacFontFamily::FindStyleVariations", LAYOUT, mName);
|
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("gfxMacFontFamily::FindStyleVariations",
|
||||||
|
LAYOUT, mName);
|
||||||
|
|
||||||
nsAutoreleasePool localPool;
|
nsAutoreleasePool localPool;
|
||||||
|
|
||||||
|
|
@ -113,12 +116,14 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
||||||
nsCocoaUtils::GetStringForNSString(psNameNS, nameUTF16);
|
nsCocoaUtils::GetStringForNSString(psNameNS, nameUTF16);
|
||||||
CopyUTF16toUTF8(nameUTF16, psName);
|
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.
|
// Set the appropriate style, assuming it may not have a variation range.
|
||||||
fe->mStyleRange = SlantStyleRange(
|
fe->mStyleRange = SlantStyleRange(
|
||||||
([[aNSFont fontDescriptor] symbolicTraits] & NSFontItalicTrait) ? FontSlantStyle::ITALIC
|
([[aNSFont fontDescriptor] symbolicTraits] & NSFontItalicTrait)
|
||||||
: FontSlantStyle::NORMAL);
|
? FontSlantStyle::ITALIC
|
||||||
|
: FontSlantStyle::NORMAL);
|
||||||
|
|
||||||
// Set up weight (and width, if present) ranges.
|
// Set up weight (and width, if present) ranges.
|
||||||
fe->SetupVariationRanges();
|
fe->SetupVariationRanges();
|
||||||
|
|
@ -128,7 +133,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
||||||
addToFamily(mForSystemFont);
|
addToFamily(mForSystemFont);
|
||||||
|
|
||||||
// See if there is a corresponding italic face, and add it to the family.
|
// 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) {
|
if (italicFont != mForSystemFont) {
|
||||||
addToFamily(italicFont);
|
addToFamily(italicFont);
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +153,8 @@ void gfxMacFontFamily::FindStyleVariationsLocked(FontInfoData* aFontInfoData) {
|
||||||
|
|
||||||
class gfxSingleFaceMacFontFamily final : public gfxFontFamily {
|
class gfxSingleFaceMacFontFamily final : public gfxFontFamily {
|
||||||
public:
|
public:
|
||||||
gfxSingleFaceMacFontFamily(const nsACString& aName, FontVisibility aVisibility)
|
gfxSingleFaceMacFontFamily(const nsACString& aName,
|
||||||
|
FontVisibility aVisibility)
|
||||||
: gfxFontFamily(aName, aVisibility) {
|
: gfxFontFamily(aName, aVisibility) {
|
||||||
mFaceNamesInitialized = true; // omit from face name lists
|
mFaceNamesInitialized = true; // omit from face name lists
|
||||||
}
|
}
|
||||||
|
|
@ -175,8 +182,9 @@ void gfxSingleFaceMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxFontEntry* fe = mAvailableFonts[0];
|
gfxFontEntry* fe = mAvailableFonts[0];
|
||||||
NSFont* font = [NSFont fontWithName:GetNSStringForString(NS_ConvertUTF8toUTF16(fe->Name()))
|
NSFont* font = [NSFont
|
||||||
size:0.0];
|
fontWithName:GetNSStringForString(NS_ConvertUTF8toUTF16(fe->Name()))
|
||||||
|
size:0.0];
|
||||||
if (font) {
|
if (font) {
|
||||||
NSString* localized = [font displayName];
|
NSString* localized = [font displayName];
|
||||||
if (localized) {
|
if (localized) {
|
||||||
|
|
@ -191,7 +199,8 @@ void gfxSingleFaceMacFontFamily::LocalizedName(nsACString& aLocalizedName) {
|
||||||
aLocalizedName = mName;
|
aLocalizedName = mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList* aPlatformFontList) {
|
void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(
|
||||||
|
gfxPlatformFontList* aPlatformFontList) {
|
||||||
AutoWriteLock lock(mLock);
|
AutoWriteLock lock(mLock);
|
||||||
if (mOtherFamilyNamesInitialized) {
|
if (mOtherFamilyNamesInitialized) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -209,7 +218,8 @@ void gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList* aPlat
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable, true);
|
mHasOtherFamilyNames =
|
||||||
|
ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable, true);
|
||||||
|
|
||||||
mOtherFamilyNamesInitialized = true;
|
mOtherFamilyNamesInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
@ -229,7 +239,8 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() : CoreTextFontList() {
|
||||||
gfxFontUtils::GetPrefsFontList("font.single-face-list", mSingleFaceFonts);
|
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")) {
|
if (aName[0] == '.' || aName.LowerCaseEqualsLiteral("lastresort")) {
|
||||||
return FontVisibility::Hidden;
|
return FontVisibility::Hidden;
|
||||||
}
|
}
|
||||||
|
|
@ -244,7 +255,8 @@ FontVisibility gfxMacPlatformFontList::GetVisibilityForFamily(const nsACString&
|
||||||
return FontVisibility::User;
|
return FontVisibility::User;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gfxMacPlatformFontList::DeprecatedFamilyIsAvailable(const nsACString& aName) {
|
bool gfxMacPlatformFontList::DeprecatedFamilyIsAvailable(
|
||||||
|
const nsACString& aName) {
|
||||||
NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(aName));
|
NSString* family = GetNSStringForString(NS_ConvertUTF8toUTF16(aName));
|
||||||
return [[sFontManager availableMembersOfFontFamily:family] count] > 0;
|
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.
|
// We found the correct face, so create the single-face family record.
|
||||||
GenerateFontListKey(aliasName, key);
|
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
|
// add only if doesn't exist already
|
||||||
if (!mFontFamilies.GetWeak(key)) {
|
if (!mFontFamilies.GetWeak(key)) {
|
||||||
|
|
@ -372,13 +385,14 @@ void gfxMacPlatformFontList::InitSingleFaceList() {
|
||||||
new gfxSingleFaceMacFontFamily(aliasName, family->Visibility());
|
new gfxSingleFaceMacFontFamily(aliasName, family->Visibility());
|
||||||
// We need a separate font entry, because its family name will
|
// We need a separate font entry, because its family name will
|
||||||
// differ from the one we found in the main list.
|
// differ from the one we found in the main list.
|
||||||
CTFontEntry* fontEntry = new CTFontEntry(fe->Name(), fe->Weight(), true,
|
CTFontEntry* fontEntry =
|
||||||
static_cast<const CTFontEntry*>(fe)->mSizeHint);
|
new CTFontEntry(fe->Name(), fe->Weight(), true,
|
||||||
|
static_cast<const CTFontEntry*>(fe)->mSizeHint);
|
||||||
familyEntry->AddFontEntry(fontEntry);
|
familyEntry->AddFontEntry(fontEntry);
|
||||||
familyEntry->SetHasStyles(true);
|
familyEntry->SetHasStyles(true);
|
||||||
mFontFamilies.InsertOrUpdate(key, std::move(familyEntry));
|
mFontFamilies.InsertOrUpdate(key, std::move(familyEntry));
|
||||||
LOG_FONTLIST(
|
LOG_FONTLIST(("(fontlist-singleface) added new family: %s, key: %s\n",
|
||||||
("(fontlist-singleface) added new family: %s, key: %s\n", aliasName.get(), key.get()));
|
aliasName.get(), key.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -404,12 +418,14 @@ static NSString* GetRealFamilyName(NSFont* aFont) {
|
||||||
// Eventually we should move to using CTFontUIFontType constants to identify
|
// Eventually we should move to using CTFontUIFontType constants to identify
|
||||||
// system fonts, and eliminate the need to instantiate them (indirectly) from
|
// system fonts, and eliminate the need to instantiate them (indirectly) from
|
||||||
// their postscript names.
|
// their postscript names.
|
||||||
AutoCFRelease<CGFontRef> cgFont = CGFontCreateWithFontName(CFStringRef(psName));
|
AutoCFRelease<CGFontRef> cgFont =
|
||||||
|
CGFontCreateWithFontName(CFStringRef(psName));
|
||||||
if (!cgFont) {
|
if (!cgFont) {
|
||||||
return [aFont familyName];
|
return [aFont familyName];
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoCFRelease<CTFontRef> ctFont = CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr);
|
AutoCFRelease<CTFontRef> ctFont =
|
||||||
|
CTFontCreateWithGraphicsFont(cgFont, 0.0, nullptr, nullptr);
|
||||||
if (!ctFont) {
|
if (!ctFont) {
|
||||||
return [aFont familyName];
|
return [aFont familyName];
|
||||||
}
|
}
|
||||||
|
|
@ -441,7 +457,8 @@ void gfxMacPlatformFontList::InitSystemFontNames() {
|
||||||
// the hidden system fonts may be excluded from the font list altogether.
|
// the hidden system fonts may be excluded from the font list altogether.
|
||||||
if (nsCocoaFeatures::OnCatalinaOrLater()) {
|
if (nsCocoaFeatures::OnCatalinaOrLater()) {
|
||||||
// This family will be populated based on the given NSFont.
|
// 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) {
|
if (fam) {
|
||||||
nsAutoCString key;
|
nsAutoCString key;
|
||||||
GenerateFontListKey(mSystemTextFontFamilyName, 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
|
// 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
|
// just assume that and emit a warning if that ever changes
|
||||||
NSString* sysFamily = GetRealFamilyName([NSFont systemFontOfSize:0.0]);
|
NSString* sysFamily = GetRealFamilyName([NSFont systemFontOfSize:0.0]);
|
||||||
if ([sysFamily compare:GetRealFamilyName([NSFont boldSystemFontOfSize:0.0])] != NSOrderedSame ||
|
if ([sysFamily compare:GetRealFamilyName([NSFont
|
||||||
[sysFamily compare:GetRealFamilyName([NSFont controlContentFontOfSize:0.0])] !=
|
boldSystemFontOfSize:0.0])] != NSOrderedSame ||
|
||||||
|
[sysFamily compare:GetRealFamilyName([NSFont
|
||||||
|
controlContentFontOfSize:0.0])] != NSOrderedSame ||
|
||||||
|
[sysFamily compare:GetRealFamilyName([NSFont menuBarFontOfSize:0.0])] !=
|
||||||
NSOrderedSame ||
|
NSOrderedSame ||
|
||||||
[sysFamily compare:GetRealFamilyName([NSFont menuBarFontOfSize:0.0])] != NSOrderedSame ||
|
[sysFamily compare:GetRealFamilyName([NSFont toolTipsFontOfSize:0.0])] !=
|
||||||
[sysFamily compare:GetRealFamilyName([NSFont toolTipsFontOfSize:0.0])] != NSOrderedSame) {
|
NSOrderedSame) {
|
||||||
NS_WARNING("system font types map to different font families"
|
NS_WARNING("system font types map to different font families"
|
||||||
" -- please log a bug!!");
|
" -- please log a bug!!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(nsPresContext* aPresContext,
|
FontFamily gfxMacPlatformFontList::GetDefaultFontForPlatform(
|
||||||
const gfxFontStyle* aStyle,
|
nsPresContext* aPresContext, const gfxFontStyle* aStyle,
|
||||||
nsAtom* aLanguage) {
|
nsAtom* aLanguage) {
|
||||||
nsAutoreleasePool localPool;
|
nsAutoreleasePool localPool;
|
||||||
|
|
||||||
NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
|
NSString* defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName];
|
||||||
|
|
@ -538,11 +558,14 @@ void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
|
||||||
}
|
}
|
||||||
|
|
||||||
NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
|
NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
|
||||||
aFontStyle.style = (traits & NSFontItalicTrait) ? FontSlantStyle::ITALIC : FontSlantStyle::NORMAL;
|
aFontStyle.style = (traits & NSFontItalicTrait) ? FontSlantStyle::ITALIC
|
||||||
aFontStyle.weight = (traits & NSFontBoldTrait) ? FontWeight::BOLD : FontWeight::NORMAL;
|
: FontSlantStyle::NORMAL;
|
||||||
aFontStyle.stretch = (traits & NSFontExpandedTrait) ? FontStretch::EXPANDED
|
aFontStyle.weight =
|
||||||
: (traits & NSFontCondensedTrait) ? FontStretch::CONDENSED
|
(traits & NSFontBoldTrait) ? FontWeight::BOLD : FontWeight::NORMAL;
|
||||||
: FontStretch::NORMAL;
|
aFontStyle.stretch = (traits & NSFontExpandedTrait) ? FontStretch::EXPANDED
|
||||||
|
: (traits & NSFontCondensedTrait)
|
||||||
|
? FontStretch::CONDENSED
|
||||||
|
: FontStretch::NORMAL;
|
||||||
aFontStyle.size = [font pointSize];
|
aFontStyle.size = [font pointSize];
|
||||||
aFontStyle.systemFont = true;
|
aFontStyle.systemFont = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ static io_connect_t sDataPort = IO_OBJECT_NULL;
|
||||||
static uint64_t sLastMean = -1;
|
static uint64_t sLastMean = -1;
|
||||||
static float LMUvalueToLux(uint64_t aValue) {
|
static float LMUvalueToLux(uint64_t aValue) {
|
||||||
// Conversion formula from regression. See Bug 793728.
|
// 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 powerC4 = 1 / pow((long double)10, 27);
|
||||||
long double powerC3 = 1 / pow((long double)10, 19);
|
long double powerC3 = 1 / pow((long double)10, 19);
|
||||||
long double powerC2 = 1 / pow((long double)10, 12);
|
long double powerC2 = 1 / pow((long double)10, 12);
|
||||||
|
|
@ -54,7 +55,8 @@ void UpdateHandler(nsITimer* aTimer, void* aClosure) {
|
||||||
uint32_t outputs = 2;
|
uint32_t outputs = 2;
|
||||||
uint64_t lightLMU[outputs];
|
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) {
|
if (kr == KERN_SUCCESS) {
|
||||||
uint64_t mean = (lightLMU[0] + lightLMU[1]) / 2;
|
uint64_t mean = (lightLMU[0] + lightLMU[1]) / 2;
|
||||||
if (mean == sLastMean) {
|
if (mean == sLastMean) {
|
||||||
|
|
@ -84,8 +86,8 @@ void EnableSensorNotifications(SensorType aSensor) {
|
||||||
}
|
}
|
||||||
} else if (aSensor == SENSOR_LIGHT) {
|
} else if (aSensor == SENSOR_LIGHT) {
|
||||||
io_service_t serviceObject;
|
io_service_t serviceObject;
|
||||||
serviceObject =
|
serviceObject = IOServiceGetMatchingService(
|
||||||
IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
|
kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
|
||||||
if (!serviceObject) {
|
if (!serviceObject) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -104,14 +106,15 @@ void EnableSensorNotifications(SensorType aSensor) {
|
||||||
if (!sUpdateTimer) {
|
if (!sUpdateTimer) {
|
||||||
CallCreateInstance("@mozilla.org/timer;1", &sUpdateTimer);
|
CallCreateInstance("@mozilla.org/timer;1", &sUpdateTimer);
|
||||||
if (sUpdateTimer) {
|
if (sUpdateTimer) {
|
||||||
sUpdateTimer->InitWithNamedFuncCallback(UpdateHandler, nullptr, DEFAULT_SENSOR_POLL,
|
sUpdateTimer->InitWithNamedFuncCallback(
|
||||||
nsITimer::TYPE_REPEATING_SLACK,
|
UpdateHandler, nullptr, DEFAULT_SENSOR_POLL,
|
||||||
"hal_impl::UpdateHandler");
|
nsITimer::TYPE_REPEATING_SLACK, "hal_impl::UpdateHandler");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DisableSensorNotifications(SensorType aSensor) {
|
void DisableSensorNotifications(SensorType aSensor) {
|
||||||
if (!sActiveSensors[aSensor] || (aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) {
|
if (!sActiveSensors[aSensor] ||
|
||||||
|
(aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,20 +80,21 @@ typedef struct sensorSpec {
|
||||||
//
|
//
|
||||||
// These values came from SeisMaCalibrate calibration reports. In general I've
|
// These values came from SeisMaCalibrate calibration reports. In general I've
|
||||||
// found the following:
|
// found the following:
|
||||||
// - All Intel-based SMSs have 250 counts per g, centered on 0, but the signs
|
// - All Intel-based SMSs have 250 counts per g, centered on 0, but the
|
||||||
// are different (and in one case two axes are swapped)
|
// signs are different (and in one case two axes are swapped)
|
||||||
// - PowerBooks and iBooks all have sensors centered on 0, and reading
|
// - PowerBooks and iBooks all have sensors centered on 0, and reading
|
||||||
// 50-53 steps per gravity (but with differing polarities!)
|
// 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
|
// - PowerBook and iBook access methods are model- and OS version-specific
|
||||||
//
|
//
|
||||||
// So, the sequence of tests is:
|
// So, the sequence of tests is:
|
||||||
// - Try model-specific access methods. Note that the test is for a match to the
|
// - Try model-specific access methods. Note that the test is for a match
|
||||||
// beginning of the model name, e.g. the record with model name "MacBook"
|
// to the beginning of the model name, e.g. the record with model name
|
||||||
// matches computer models "MacBookPro1,2" and "MacBook1,1" (and ""
|
// "MacBook" matches computer models "MacBookPro1,2" and "MacBook1,1" (and ""
|
||||||
// matches any model).
|
// matches any model).
|
||||||
// - If no model-specific record's access fails, then try each model-independent
|
// - If no model-specific record's access fails, then try each
|
||||||
// access method in order, stopping when one works.
|
// model-independent access method in order, stopping when one works.
|
||||||
static const sensorSpec sensors[] = {
|
static const sensorSpec sensors[] = {
|
||||||
// ****** Model-dependent methods ******
|
// ****** Model-dependent methods ******
|
||||||
// The PowerBook5,6 is one of the G4 models that seems to lose
|
// The PowerBook5,6 is one of the G4 models that seems to lose
|
||||||
|
|
@ -142,7 +143,8 @@ static const sensorSpec sensors[] = {
|
||||||
5,
|
5,
|
||||||
40,
|
40,
|
||||||
{{1, 0, 2, 0, 251}, {1, 2, 2, 0, -251}, {1, 4, 2, 0, -251}}},
|
{{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
|
// 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
|
// from this calibration, but there's no clear way to discriminate between
|
||||||
// the two machines.
|
// the two machines.
|
||||||
|
|
@ -169,7 +171,8 @@ static const sensorSpec sensors[] = {
|
||||||
5,
|
5,
|
||||||
40,
|
40,
|
||||||
{{1, 0, 2, 0, -251}, {1, 2, 2, 0, -251}, {1, 4, 2, 0, 251}}},
|
{{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.
|
// are swapped. This is true for no other known Appple laptop.
|
||||||
{"MacBookPro5,3",
|
{"MacBookPro5,3",
|
||||||
"SMCMotionSensor",
|
"SMCMotionSensor",
|
||||||
|
|
@ -185,10 +188,18 @@ static const sensorSpec sensors[] = {
|
||||||
// ****** Model-independent methods ******
|
// ****** Model-independent methods ******
|
||||||
// Seen once with PowerBook6,8 under system 10.3.9; I suspect
|
// Seen once with PowerBook6,8 under system 10.3.9; I suspect
|
||||||
// other G4-based 10.3.* systems might use this
|
// 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
|
// PowerBook5,6 , PowerBook5,7 , PowerBook6,7 , PowerBook6,8
|
||||||
// under OS X 10.4.*
|
// 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.*
|
// PowerBook5,8 , PowerBook5,9 under OS X 10.4.*
|
||||||
{"",
|
{"",
|
||||||
"PMUMotionSensor",
|
"PMUMotionSensor",
|
||||||
|
|
@ -200,9 +211,11 @@ static const sensorSpec sensors[] = {
|
||||||
{1, 0, 1, 0, -51.5},
|
{1, 0, 1, 0, -51.5},
|
||||||
{1, 1, 1, -6, -51.5},
|
{1, 1, 1, -6, -51.5},
|
||||||
{1, 2, 1, 0, -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
|
// 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:
|
// that use this are:
|
||||||
// MacBook1,1
|
// MacBook1,1
|
||||||
// MacBook2,1
|
// MacBook2,1
|
||||||
|
|
@ -215,13 +228,18 @@ static const sensorSpec sensors[] = {
|
||||||
// MacBookPro1,2
|
// MacBookPro1,2
|
||||||
// MacBookPro4,1
|
// MacBookPro4,1
|
||||||
// MacBookPro5,5
|
// 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))
|
#define SENSOR_COUNT (sizeof(sensors) / sizeof(sensorSpec))
|
||||||
|
|
||||||
#pragma mark Internal prototypes
|
#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 float getAxis(int which, int calibrated);
|
||||||
static int signExtend(int value, int size);
|
static int signExtend(int value, int size);
|
||||||
static NSString* getModelName(void);
|
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)
|
// Name of configuration for given axis' zero (axis specified by integer)
|
||||||
#define ZERO_NAME(a) [NSString stringWithFormat:@"%@-Axis-Zero", INT_TO_AXIS(a)]
|
#define ZERO_NAME(a) [NSString stringWithFormat:@"%@-Axis-Zero", INT_TO_AXIS(a)]
|
||||||
// Name of configuration for given axis' oneg (axis specified by integer)
|
// 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
|
// Name of "Is calibrated" preference
|
||||||
#define CALIBRATED_NAME (@"Calibrated")
|
#define CALIBRATED_NAME (@"Calibrated")
|
||||||
// Application domain for SeisMac library
|
// Application domain for SeisMac library
|
||||||
|
|
@ -271,19 +290,22 @@ static float onegs[3]; // X, Y and Z one-g calibration values
|
||||||
if (logObject) { \
|
if (logObject) { \
|
||||||
[logObject performSelector:logSelector withObject:message]; \
|
[logObject performSelector:logSelector withObject:message]; \
|
||||||
}
|
}
|
||||||
#define LOG_ARG(format, var1) \
|
#define LOG_ARG(format, var1) \
|
||||||
if (logObject) { \
|
if (logObject) { \
|
||||||
[logObject performSelector:logSelector withObject:[NSString stringWithFormat:format, var1]]; \
|
[logObject performSelector:logSelector \
|
||||||
|
withObject:[NSString stringWithFormat:format, var1]]; \
|
||||||
}
|
}
|
||||||
#define LOG_2ARG(format, var1, var2) \
|
#define LOG_2ARG(format, var1, var2) \
|
||||||
if (logObject) { \
|
if (logObject) { \
|
||||||
[logObject performSelector:logSelector \
|
[logObject \
|
||||||
withObject:[NSString stringWithFormat:format, var1, var2]]; \
|
performSelector:logSelector \
|
||||||
|
withObject:[NSString stringWithFormat:format, var1, var2]]; \
|
||||||
}
|
}
|
||||||
#define LOG_3ARG(format, var1, var2, var3) \
|
#define LOG_3ARG(format, var1, var2, var3) \
|
||||||
if (logObject) { \
|
if (logObject) { \
|
||||||
[logObject performSelector:logSelector \
|
[logObject \
|
||||||
withObject:[NSString stringWithFormat:format, var1, var2, var3]]; \
|
performSelector:logSelector \
|
||||||
|
withObject:[NSString stringWithFormat:format, var1, var2, var3]]; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark Function definitions
|
#pragma mark Function definitions
|
||||||
|
|
@ -322,11 +344,12 @@ int smsStartup(id logObject, SEL logSelector) {
|
||||||
recordSize = sensors[sensorNum].recordSize;
|
recordSize = sensors[sensorNum].recordSize;
|
||||||
function = sensors[sensorNum].function;
|
function = sensors[sensorNum].function;
|
||||||
|
|
||||||
LOG_3ARG(@"Trying service \"%s\" with selector %d and %d byte record:\n", serviceName, function,
|
LOG_3ARG(@"Trying service \"%s\" with selector %d and %d byte record:\n",
|
||||||
recordSize);
|
serviceName, function, recordSize);
|
||||||
|
|
||||||
NSString* targetName = [NSString stringWithCString:sensors[sensorNum].model
|
NSString* targetName =
|
||||||
encoding:NSMacOSRomanStringEncoding];
|
[NSString stringWithCString:sensors[sensorNum].model
|
||||||
|
encoding:NSMacOSRomanStringEncoding];
|
||||||
LOG_ARG(@" Comparing model name to target \"%@\": ", targetName);
|
LOG_ARG(@" Comparing model name to target \"%@\": ", targetName);
|
||||||
if ([targetName length] == 0 || [modelName hasPrefix:targetName]) {
|
if ([targetName length] == 0 || [modelName hasPrefix:targetName]) {
|
||||||
LOG(@"success.\n");
|
LOG(@"success.\n");
|
||||||
|
|
@ -350,7 +373,8 @@ int smsStartup(id logObject, SEL logSelector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(@" Getting list of matching services: ");
|
LOG(@" Getting list of matching services: ");
|
||||||
result = IOServiceGetMatchingServices(kIOMasterPortDefault, dict, &iterator);
|
result =
|
||||||
|
IOServiceGetMatchingServices(kIOMasterPortDefault, dict, &iterator);
|
||||||
|
|
||||||
if (result == KERN_SUCCESS) {
|
if (result == KERN_SUCCESS) {
|
||||||
LOG(@"success.\n");
|
LOG(@"success.\n");
|
||||||
|
|
@ -386,7 +410,9 @@ int smsStartup(id logObject, SEL logSelector) {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (connection == 0) {
|
} 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);
|
IOObjectRelease(device);
|
||||||
if (failure_result < SMS_FAIL_CONNECTION) {
|
if (failure_result < SMS_FAIL_CONNECTION) {
|
||||||
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
|
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||||
const size_t InStructSize = recordSize;
|
const size_t InStructSize = recordSize;
|
||||||
size_t OutStructSize = recordSize;
|
size_t OutStructSize = recordSize;
|
||||||
result =
|
result = IOConnectCallStructMethod(connection,
|
||||||
IOConnectCallStructMethod(connection,
|
function, // magic kernel function number
|
||||||
function, // magic kernel function number
|
(const void*)iRecord, InStructSize,
|
||||||
(const void*)iRecord, InStructSize, (void*)buffer, &OutStructSize);
|
(void*)buffer, &OutStructSize);
|
||||||
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||||
result = IOConnectMethodStructureIStructureO(connection,
|
result = IOConnectMethodStructureIStructureO(
|
||||||
function, // magic kernel function number
|
connection,
|
||||||
iSize, &oSize, iRecord, buffer);
|
function, // magic kernel function number
|
||||||
|
iSize, &oSize, iRecord, buffer);
|
||||||
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||||
|
|
||||||
if (result != KERN_SUCCESS) {
|
if (result != KERN_SUCCESS) {
|
||||||
|
|
@ -580,9 +607,10 @@ NSString* smsGetCalibrationDescription(void) {
|
||||||
[s appendString:@"---- SeisMac Calibration Record ----\n \n"];
|
[s appendString:@"---- SeisMac Calibration Record ----\n \n"];
|
||||||
[s appendFormat:@"Machine model: %@\n", getModelName()];
|
[s appendFormat:@"Machine model: %@\n", getModelName()];
|
||||||
[s appendFormat:@"OS X build: %@\n", getOSVersion()];
|
[s appendFormat:@"OS X build: %@\n", getOSVersion()];
|
||||||
[s appendFormat:@"SeisMacLib version %s, record %d\n \n", SMSLIB_VERSION, sensorNum];
|
[s appendFormat:@"SeisMacLib version %s, record %d\n \n", SMSLIB_VERSION,
|
||||||
[s appendFormat:@"Using service \"%s\", function index %d, size %d\n \n", serviceName, function,
|
sensorNum];
|
||||||
recordSize];
|
[s appendFormat:@"Using service \"%s\", function index %d, size %d\n \n",
|
||||||
|
serviceName, function, recordSize];
|
||||||
if (prefIntRead(CALIBRATED_NAME, &success) && success) {
|
if (prefIntRead(CALIBRATED_NAME, &success) && success) {
|
||||||
[s appendString:@"Calibration values (from calibration):\n"];
|
[s appendString:@"Calibration values (from calibration):\n"];
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -670,7 +698,8 @@ static void deleteCalibration(void) {
|
||||||
static float prefFloatRead(NSString* prefName, BOOL* success) {
|
static float prefFloatRead(NSString* prefName, BOOL* success) {
|
||||||
float result = 0.0f;
|
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 there isn't such a preference, fail
|
||||||
if (ref == NULL) {
|
if (ref == NULL) {
|
||||||
*success = NO;
|
*success = NO;
|
||||||
|
|
@ -682,7 +711,8 @@ static float prefFloatRead(NSString* prefName, BOOL* success) {
|
||||||
// Is it a floating point number?
|
// Is it a floating point number?
|
||||||
if (CFNumberIsFloatType((CFNumberRef)ref)) {
|
if (CFNumberIsFloatType((CFNumberRef)ref)) {
|
||||||
// Yup: grab it.
|
// Yup: grab it.
|
||||||
*success = CFNumberGetValue((__CFNumber*)ref, kCFNumberFloat32Type, &result);
|
*success =
|
||||||
|
CFNumberGetValue((__CFNumber*)ref, kCFNumberFloat32Type, &result);
|
||||||
} else {
|
} else {
|
||||||
// Nope: grab as an integer, and convert to a float.
|
// Nope: grab as an integer, and convert to a float.
|
||||||
long num;
|
long num;
|
||||||
|
|
@ -707,7 +737,8 @@ static float prefFloatRead(NSString* prefName, BOOL* success) {
|
||||||
|
|
||||||
// Writes a named floating point value to the stored preferences.
|
// Writes a named floating point value to the stored preferences.
|
||||||
static void prefFloatWrite(NSString* prefName, float prefValue) {
|
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);
|
CFPreferencesSetAppValue((CFStringRef)prefName, cfFloat, APP_ID);
|
||||||
CFRelease(cfFloat);
|
CFRelease(cfFloat);
|
||||||
}
|
}
|
||||||
|
|
@ -715,7 +746,8 @@ static void prefFloatWrite(NSString* prefName, float prefValue) {
|
||||||
// Reads a named integer value from the stored preferences.
|
// Reads a named integer value from the stored preferences.
|
||||||
static int prefIntRead(NSString* prefName, BOOL* success) {
|
static int prefIntRead(NSString* prefName, BOOL* success) {
|
||||||
Boolean internalSuccess;
|
Boolean internalSuccess;
|
||||||
CFIndex result = CFPreferencesGetAppIntegerValue((CFStringRef)prefName, APP_ID, &internalSuccess);
|
CFIndex result = CFPreferencesGetAppIntegerValue((CFStringRef)prefName,
|
||||||
|
APP_ID, &internalSuccess);
|
||||||
*success = internalSuccess;
|
*success = internalSuccess;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -723,7 +755,8 @@ static int prefIntRead(NSString* prefName, BOOL* success) {
|
||||||
|
|
||||||
// Writes a named integer value to the stored preferences.
|
// Writes a named integer value to the stored preferences.
|
||||||
static void prefIntWrite(NSString* prefName, int prefValue) {
|
static void prefIntWrite(NSString* prefName, int prefValue) {
|
||||||
CFPreferencesSetAppValue((CFStringRef)prefName, (CFNumberRef)[NSNumber numberWithInt:prefValue],
|
CFPreferencesSetAppValue((CFStringRef)prefName,
|
||||||
|
(CFNumberRef)[NSNumber numberWithInt:prefValue],
|
||||||
APP_ID);
|
APP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -736,7 +769,8 @@ static void prefDelete(NSString* prefName) {
|
||||||
static void prefSynchronize(void) { CFPreferencesAppSynchronize(APP_ID); }
|
static void prefSynchronize(void) { CFPreferencesAppSynchronize(APP_ID); }
|
||||||
|
|
||||||
// Internal version of accelGetData, with logging
|
// 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;
|
IOItemCount iSize = recordSize;
|
||||||
IOByteCount oSize = recordSize;
|
IOByteCount oSize = recordSize;
|
||||||
kern_return_t result;
|
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
|
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||||
const size_t InStructSize = recordSize;
|
const size_t InStructSize = recordSize;
|
||||||
size_t OutStructSize = recordSize;
|
size_t OutStructSize = recordSize;
|
||||||
result =
|
result = IOConnectCallStructMethod(connection,
|
||||||
IOConnectCallStructMethod(connection,
|
function, // magic kernel function number
|
||||||
function, // magic kernel function number
|
(const void*)iRecord, InStructSize,
|
||||||
(const void*)iRecord, InStructSize, (void*)oRecord, &OutStructSize);
|
(void*)oRecord, &OutStructSize);
|
||||||
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||||
result = IOConnectMethodStructureIStructureO(connection,
|
result = IOConnectMethodStructureIStructureO(
|
||||||
function, // magic kernel function number
|
connection,
|
||||||
iSize, &oSize, iRecord, oRecord);
|
function, // magic kernel function number
|
||||||
|
iSize, &oSize, iRecord, oRecord);
|
||||||
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||||
|
|
||||||
if (result != KERN_SUCCESS) {
|
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)")
|
// Returns the current OS X version and build (e.g. "10.4.7 (build 8J2135a)")
|
||||||
NSString* getOSVersion(void) {
|
NSString* getOSVersion(void) {
|
||||||
NSDictionary* dict = [NSDictionary
|
NSDictionary* dict =
|
||||||
dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
|
[NSDictionary dictionaryWithContentsOfFile:
|
||||||
|
@"/System/Library/CoreServices/SystemVersion.plist"];
|
||||||
NSString* versionString = [dict objectForKey:@"ProductVersion"];
|
NSString* versionString = [dict objectForKey:@"ProductVersion"];
|
||||||
NSString* buildString = [dict objectForKey:@"ProductBuildVersion"];
|
NSString* buildString = [dict objectForKey:@"ProductBuildVersion"];
|
||||||
NSString* wholeString = [NSString stringWithFormat:@"%@ (build %@)", versionString, buildString];
|
NSString* wholeString =
|
||||||
|
[NSString stringWithFormat:@"%@ (build %@)", versionString, buildString];
|
||||||
return wholeString;
|
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) {
|
nsresult nsIconChannel::Init(nsIURI* uri) {
|
||||||
NS_ASSERTION(uri, "no uri");
|
NS_ASSERTION(uri, "no uri");
|
||||||
|
|
@ -73,7 +74,8 @@ NS_IMETHODIMP nsIconChannel::GetCanceledReason(nsACString& aReason) {
|
||||||
return GetCanceledReasonImpl(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);
|
return CancelWithReasonImpl(aStatus, aReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,8 +123,8 @@ nsIconChannel::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
|
||||||
|
|
||||||
// nsIStreamListener methods
|
// nsIStreamListener methods
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aStream, uint64_t aOffset,
|
nsIconChannel::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aStream,
|
||||||
uint32_t aCount) {
|
uint64_t aOffset, uint32_t aCount) {
|
||||||
if (mListener) {
|
if (mListener) {
|
||||||
return mListener->OnDataAvailable(this, aStream, aOffset, aCount);
|
return mListener->OnDataAvailable(this, aStream, aOffset, aCount);
|
||||||
}
|
}
|
||||||
|
|
@ -156,13 +158,15 @@ nsIconChannel::GetURI(nsIURI** aURI) {
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::Open(nsIInputStream** _retval) {
|
nsIconChannel::Open(nsIInputStream** _retval) {
|
||||||
nsCOMPtr<nsIStreamListener> listener;
|
nsCOMPtr<nsIStreamListener> listener;
|
||||||
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
nsresult rv =
|
||||||
|
nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return MakeInputStream(_retval, false);
|
return MakeInputStream(_retval, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile, uint32_t* aDesiredImageSize,
|
nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile,
|
||||||
|
uint32_t* aDesiredImageSize,
|
||||||
nsACString& aContentType,
|
nsACString& aContentType,
|
||||||
nsACString& aFileExtension) {
|
nsACString& aFileExtension) {
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
@ -196,18 +200,21 @@ nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile** aLocalFile, uint32_t* a
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
|
nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
|
||||||
nsCOMPtr<nsIStreamListener> listener = aListener;
|
nsCOMPtr<nsIStreamListener> listener = aListener;
|
||||||
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
nsresult rv =
|
||||||
|
nsContentSecurityManager::doContentSecurityCheck(this, listener);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
mCallbacks = nullptr;
|
mCallbacks = nullptr;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(mLoadInfo->GetSecurityMode() == 0 || mLoadInfo->GetInitialSecurityCheckDone() ||
|
MOZ_ASSERT(
|
||||||
(mLoadInfo->GetSecurityMode() ==
|
mLoadInfo->GetSecurityMode() == 0 ||
|
||||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
|
mLoadInfo->GetInitialSecurityCheckDone() ||
|
||||||
mLoadInfo->GetLoadingPrincipal() &&
|
(mLoadInfo->GetSecurityMode() ==
|
||||||
mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()),
|
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
|
||||||
"security flags in loadInfo but doContentSecurityCheck() not called");
|
mLoadInfo->GetLoadingPrincipal() &&
|
||||||
|
mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()),
|
||||||
|
"security flags in loadInfo but doContentSecurityCheck() not called");
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> inStream;
|
nsCOMPtr<nsIInputStream> inStream;
|
||||||
rv = MakeInputStream(getter_AddRefs(inStream), true);
|
rv = MakeInputStream(getter_AddRefs(inStream), true);
|
||||||
|
|
@ -218,7 +225,8 @@ nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
|
||||||
|
|
||||||
// Init our stream pump
|
// Init our stream pump
|
||||||
nsCOMPtr<nsISerialEventTarget> target =
|
nsCOMPtr<nsISerialEventTarget> target =
|
||||||
nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo, mozilla::TaskCategory::Other);
|
nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo,
|
||||||
|
mozilla::TaskCategory::Other);
|
||||||
rv = mPump->Init(inStream, 0, 0, false, target);
|
rv = mPump->Init(inStream, 0, 0, false, target);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
mCallbacks = nullptr;
|
mCallbacks = nullptr;
|
||||||
|
|
@ -240,15 +248,16 @@ nsIconChannel::AsyncOpen(nsIStreamListener* aListener) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlocking) {
|
nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval,
|
||||||
|
bool aNonBlocking) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsCString contentType;
|
nsCString contentType;
|
||||||
nsAutoCString fileExt;
|
nsAutoCString fileExt;
|
||||||
nsCOMPtr<nsIFile> fileloc; // file we want an icon for
|
nsCOMPtr<nsIFile> fileloc; // file we want an icon for
|
||||||
uint32_t desiredImageSize;
|
uint32_t desiredImageSize;
|
||||||
nsresult rv =
|
nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(fileloc),
|
||||||
ExtractIconInfoFromUrl(getter_AddRefs(fileloc), &desiredImageSize, contentType, fileExt);
|
&desiredImageSize, contentType, fileExt);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
bool fileExists = false;
|
bool fileExists = false;
|
||||||
|
|
@ -265,7 +274,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool aNonBlock
|
||||||
|
|
||||||
CFURLRef macURL;
|
CFURLRef macURL;
|
||||||
if (NS_SUCCEEDED(localFileMac->GetCFURL(&macURL))) {
|
if (NS_SUCCEEDED(localFileMac->GetCFURL(&macURL))) {
|
||||||
iconImage = [[NSWorkspace sharedWorkspace] iconForFile:[(NSURL*)macURL path]];
|
iconImage =
|
||||||
|
[[NSWorkspace sharedWorkspace] iconForFile:[(NSURL*)macURL path]];
|
||||||
::CFRelease(macURL);
|
::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 we still don't have an icon, get the generic document icon.
|
||||||
if (!iconImage) {
|
if (!iconImage) {
|
||||||
iconImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeUnknown];
|
iconImage =
|
||||||
|
[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeUnknown];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iconImage) {
|
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
|
// 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
|
// 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
|
// 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.
|
// pixels. So we just always double the size here in order to prevent
|
||||||
uint32_t size = (desiredImageSize < 128) ? desiredImageSize * 2 : desiredImageSize;
|
// blurriness.
|
||||||
|
uint32_t size =
|
||||||
|
(desiredImageSize < 128) ? desiredImageSize * 2 : desiredImageSize;
|
||||||
uint32_t width = size;
|
uint32_t width = size;
|
||||||
uint32_t height = 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
|
// This gives us the image data in the format we want: BGRA, four bytes per
|
||||||
// pixel, in host endianness, with premultiplied alpha.
|
// pixel, in host endianness, with premultiplied alpha.
|
||||||
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
|
||||||
CGContextRef ctx =
|
CGContextRef ctx = CGBitmapContextCreate(
|
||||||
CGBitmapContextCreate(imageBuf, width, height, 8 /* bitsPerComponent */, width * 4, cs,
|
imageBuf, width, height, 8 /* bitsPerComponent */, width * 4, cs,
|
||||||
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
|
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
|
||||||
CGColorSpaceRelease(cs);
|
CGColorSpaceRelease(cs);
|
||||||
|
|
||||||
NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
|
NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
|
||||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:ctx
|
[NSGraphicsContext
|
||||||
flipped:NO]];
|
setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:ctx
|
||||||
|
flipped:NO]];
|
||||||
|
|
||||||
[iconImage drawInRect:NSMakeRect(0, 0, width, height)];
|
[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
|
// Now, create a pipe and stuff our data into it
|
||||||
nsCOMPtr<nsIInputStream> inStream;
|
nsCOMPtr<nsIInputStream> inStream;
|
||||||
nsCOMPtr<nsIOutputStream> outStream;
|
nsCOMPtr<nsIOutputStream> outStream;
|
||||||
NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream), bufferCapacity, bufferCapacity,
|
NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream),
|
||||||
aNonBlocking);
|
bufferCapacity, bufferCapacity, aNonBlocking);
|
||||||
|
|
||||||
uint32_t written;
|
uint32_t written;
|
||||||
rv = outStream->Write((char*)fileBuf.get(), bufferCapacity, &written);
|
rv = outStream->Write((char*)fileBuf.get(), bufferCapacity, &written);
|
||||||
|
|
@ -368,10 +382,14 @@ nsIconChannel::SetLoadFlags(uint32_t aLoadAttributes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) { return GetTRRModeImpl(aTRRMode); }
|
nsIconChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
|
||||||
|
return GetTRRModeImpl(aTRRMode);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) { return SetTRRModeImpl(aTRRMode); }
|
nsIconChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
|
||||||
|
return SetTRRModeImpl(aTRRMode);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::GetIsDocument(bool* aIsDocument) {
|
nsIconChannel::GetIsDocument(bool* aIsDocument) {
|
||||||
|
|
@ -415,17 +433,20 @@ nsIconChannel::SetContentDisposition(uint32_t aContentDisposition) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename) {
|
nsIconChannel::GetContentDispositionFilename(
|
||||||
|
nsAString& aContentDispositionFilename) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename) {
|
nsIconChannel::SetContentDispositionFilename(
|
||||||
|
const nsAString& aContentDispositionFilename) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader) {
|
nsIconChannel::GetContentDispositionHeader(
|
||||||
|
nsACString& aContentDispositionHeader) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -481,14 +502,16 @@ nsIconChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor** aNotificationCallbacks) {
|
nsIconChannel::GetNotificationCallbacks(
|
||||||
|
nsIInterfaceRequestor** aNotificationCallbacks) {
|
||||||
*aNotificationCallbacks = mCallbacks.get();
|
*aNotificationCallbacks = mCallbacks.get();
|
||||||
NS_IF_ADDREF(*aNotificationCallbacks);
|
NS_IF_ADDREF(*aNotificationCallbacks);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) {
|
nsIconChannel::SetNotificationCallbacks(
|
||||||
|
nsIInterfaceRequestor* aNotificationCallbacks) {
|
||||||
mCallbacks = aNotificationCallbacks;
|
mCallbacks = aNotificationCallbacks;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
|
|
||||||
@interface CrApplication ()
|
@interface CrApplication ()
|
||||||
@property(readwrite, getter=isHandlingSendEvent, nonatomic) BOOL handlingSendEvent;
|
@property(readwrite, getter=isHandlingSendEvent, nonatomic)
|
||||||
|
BOOL handlingSendEvent;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CrApplication
|
@implementation CrApplication
|
||||||
|
|
@ -19,7 +20,8 @@
|
||||||
+ (NSApplication*)sharedApplication {
|
+ (NSApplication*)sharedApplication {
|
||||||
NSApplication* app = [super sharedApplication];
|
NSApplication* app = [super sharedApplication];
|
||||||
if (![NSApp isKindOfClass:self]) {
|
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];
|
<< [[NSApp className] UTF8String];
|
||||||
DCHECK(false) << "NSApp is of wrong type";
|
DCHECK(false) << "NSApp is of wrong type";
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +61,8 @@ ScopedSendingEvent::ScopedSendingEvent()
|
||||||
[app_ setHandlingSendEvent:YES];
|
[app_ setHandlingSendEvent:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedSendingEvent::~ScopedSendingEvent() { [app_ setHandlingSendEvent:handling_]; }
|
ScopedSendingEvent::~ScopedSendingEvent() {
|
||||||
|
[app_ setHandlingSendEvent:handling_];
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chrome_application_mac
|
} // namespace chrome_application_mac
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ bool AmIBundled() {
|
||||||
if (GetProcessBundleLocation(&psn, &fsref) != noErr) return false;
|
if (GetProcessBundleLocation(&psn, &fsref) != noErr) return false;
|
||||||
|
|
||||||
FSCatalogInfo info;
|
FSCatalogInfo info;
|
||||||
if (FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info, NULL, NULL, NULL) != noErr) {
|
if (FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info, NULL, NULL, NULL) !=
|
||||||
|
noErr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ namespace {
|
||||||
|
|
||||||
void NoOp(void* info) {}
|
void NoOp(void* info) {}
|
||||||
|
|
||||||
const CFTimeInterval kCFTimeIntervalMax = std::numeric_limits<CFTimeInterval>::max();
|
const CFTimeInterval kCFTimeIntervalMax =
|
||||||
|
std::numeric_limits<CFTimeInterval>::max();
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
@ -57,12 +58,13 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
|
||||||
// as needed when ScheduleDelayedWork is called.
|
// as needed when ScheduleDelayedWork is called.
|
||||||
CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
|
CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
|
||||||
timer_context.info = this;
|
timer_context.info = this;
|
||||||
delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator
|
delayed_work_timer_ =
|
||||||
kCFTimeIntervalMax, // fire time
|
CFRunLoopTimerCreate(NULL, // allocator
|
||||||
kCFTimeIntervalMax, // interval
|
kCFTimeIntervalMax, // fire time
|
||||||
0, // flags
|
kCFTimeIntervalMax, // interval
|
||||||
0, // priority
|
0, // flags
|
||||||
RunDelayedWorkTimer, &timer_context);
|
0, // priority
|
||||||
|
RunDelayedWorkTimer, &timer_context);
|
||||||
CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
|
CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
|
||||||
|
|
||||||
CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
|
CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
|
||||||
|
|
@ -89,36 +91,42 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
|
||||||
nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
|
nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
|
||||||
0, // priority
|
0, // priority
|
||||||
&source_context);
|
&source_context);
|
||||||
CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_, kCFRunLoopCommonModes);
|
CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
|
|
||||||
CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
|
CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
|
||||||
observer_context.info = this;
|
observer_context.info = this;
|
||||||
pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator
|
pre_wait_observer_ =
|
||||||
kCFRunLoopBeforeWaiting,
|
CFRunLoopObserverCreate(NULL, // allocator
|
||||||
true, // repeat
|
kCFRunLoopBeforeWaiting,
|
||||||
0, // priority
|
true, // repeat
|
||||||
PreWaitObserver, &observer_context);
|
0, // priority
|
||||||
|
PreWaitObserver, &observer_context);
|
||||||
CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
|
CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
|
||||||
|
|
||||||
pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator
|
pre_source_observer_ =
|
||||||
kCFRunLoopBeforeSources,
|
CFRunLoopObserverCreate(NULL, // allocator
|
||||||
true, // repeat
|
kCFRunLoopBeforeSources,
|
||||||
0, // priority
|
true, // repeat
|
||||||
PreSourceObserver, &observer_context);
|
0, // priority
|
||||||
|
PreSourceObserver, &observer_context);
|
||||||
CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
|
CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
|
||||||
|
|
||||||
enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator
|
enter_exit_observer_ =
|
||||||
kCFRunLoopEntry | kCFRunLoopExit,
|
CFRunLoopObserverCreate(NULL, // allocator
|
||||||
true, // repeat
|
kCFRunLoopEntry | kCFRunLoopExit,
|
||||||
0, // priority
|
true, // repeat
|
||||||
EnterExitObserver, &observer_context);
|
0, // priority
|
||||||
|
EnterExitObserver, &observer_context);
|
||||||
CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
|
CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
|
||||||
|
|
||||||
root_power_domain_ = IORegisterForSystemPower(
|
root_power_domain_ = IORegisterForSystemPower(this, &power_notification_port_,
|
||||||
this, &power_notification_port_, PowerStateNotification, &power_notification_object_);
|
PowerStateNotification,
|
||||||
|
&power_notification_object_);
|
||||||
if (root_power_domain_ != MACH_PORT_NULL) {
|
if (root_power_domain_ != MACH_PORT_NULL) {
|
||||||
CFRunLoopAddSource(run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
|
CFRunLoopAddSource(
|
||||||
kCFRunLoopCommonModes);
|
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.
|
// same number of run loops must be running when this object is destroyed.
|
||||||
MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
|
MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
|
||||||
if (root_power_domain_ != MACH_PORT_NULL) {
|
if (root_power_domain_ != MACH_PORT_NULL) {
|
||||||
CFRunLoopRemoveSource(run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
|
CFRunLoopRemoveSource(
|
||||||
kCFRunLoopCommonModes);
|
run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
IODeregisterForSystemPower(&power_notification_object_);
|
IODeregisterForSystemPower(&power_notification_object_);
|
||||||
IOServiceClose(root_power_domain_);
|
IOServiceClose(root_power_domain_);
|
||||||
IONotificationPortDestroy(power_notification_port_);
|
IONotificationPortDestroy(power_notification_port_);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
|
CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
CFRelease(enter_exit_observer_);
|
CFRelease(enter_exit_observer_);
|
||||||
|
|
||||||
CFRunLoopRemoveObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
|
CFRunLoopRemoveObserver(run_loop_, pre_source_observer_,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
CFRelease(pre_source_observer_);
|
CFRelease(pre_source_observer_);
|
||||||
|
|
||||||
CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
|
CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
|
||||||
CFRelease(pre_wait_observer_);
|
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_);
|
CFRelease(nesting_deferred_work_source_);
|
||||||
|
|
||||||
CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
|
CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
|
||||||
|
|
@ -203,7 +215,8 @@ void MessagePumpCFRunLoopBase::ScheduleWork() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be called on the run loop thread.
|
// 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();
|
TimeDelta delta = delayed_work_time - TimeTicks::Now();
|
||||||
delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF();
|
delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF();
|
||||||
CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
|
CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
|
||||||
|
|
@ -211,7 +224,8 @@ void MessagePumpCFRunLoopBase::ScheduleDelayedWork(const TimeTicks& delayed_work
|
||||||
|
|
||||||
// Called from the run loop.
|
// Called from the run loop.
|
||||||
// static
|
// static
|
||||||
void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info) {
|
void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
|
||||||
|
void* info) {
|
||||||
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
||||||
|
|
||||||
// The timer won't fire again until it's reset.
|
// The timer won't fire again until it's reset.
|
||||||
|
|
@ -392,7 +406,8 @@ void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
|
||||||
// Called from the run loop.
|
// Called from the run loop.
|
||||||
// static
|
// static
|
||||||
void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
|
void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
|
||||||
CFRunLoopActivity activity, void* info) {
|
CFRunLoopActivity activity,
|
||||||
|
void* info) {
|
||||||
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
||||||
|
|
||||||
// Attempt to do some idle work before going to sleep.
|
// Attempt to do some idle work before going to sleep.
|
||||||
|
|
@ -408,7 +423,8 @@ void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
|
||||||
// Called from the run loop.
|
// Called from the run loop.
|
||||||
// static
|
// static
|
||||||
void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
|
void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
|
||||||
CFRunLoopActivity activity, void* info) {
|
CFRunLoopActivity activity,
|
||||||
|
void* info) {
|
||||||
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
||||||
|
|
||||||
// The run loop has reached the top of the loop and is about to begin
|
// 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.
|
// Called from the run loop.
|
||||||
// static
|
// static
|
||||||
void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
|
void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
|
||||||
CFRunLoopActivity activity, void* info) {
|
CFRunLoopActivity activity,
|
||||||
|
void* info) {
|
||||||
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
||||||
|
|
||||||
switch (activity) {
|
switch (activity) {
|
||||||
|
|
@ -463,7 +480,8 @@ void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
|
||||||
|
|
||||||
// Called from the run loop.
|
// Called from the run loop.
|
||||||
// static
|
// static
|
||||||
void MessagePumpCFRunLoopBase::PowerStateNotification(void* info, io_service_t service,
|
void MessagePumpCFRunLoopBase::PowerStateNotification(void* info,
|
||||||
|
io_service_t service,
|
||||||
uint32_t message_type,
|
uint32_t message_type,
|
||||||
void* message_argument) {
|
void* message_argument) {
|
||||||
// CFRunLoopTimer (NSTimer) is scheduled in terms of CFAbsoluteTime, which
|
// 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) {
|
switch (message_type) {
|
||||||
case kIOMessageSystemWillPowerOn:
|
case kIOMessageSystemWillPowerOn:
|
||||||
if (self->delayed_work_fire_time_ != kCFTimeIntervalMax) {
|
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;
|
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
|
// The system will wait for 30 seconds before entering sleep if neither
|
||||||
// IOAllowPowerChange nor IOCancelPowerChange are called. That would be
|
// IOAllowPowerChange nor IOCancelPowerChange are called. That would be
|
||||||
// pretty antisocial.
|
// pretty antisocial.
|
||||||
IOAllowPowerChange(self->root_power_domain_, reinterpret_cast<long>(message_argument));
|
IOAllowPowerChange(self->root_power_domain_,
|
||||||
|
reinterpret_cast<long>(message_argument));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -546,7 +566,8 @@ void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
|
||||||
int result;
|
int result;
|
||||||
do {
|
do {
|
||||||
MessagePumpScopedAutoreleasePool autorelease_pool(this);
|
MessagePumpScopedAutoreleasePool autorelease_pool(this);
|
||||||
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, kCFTimeIntervalMax, false);
|
result =
|
||||||
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, kCFTimeIntervalMax, false);
|
||||||
} while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
|
} while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -568,7 +589,8 @@ void MessagePumpCFRunLoop::Quit() {
|
||||||
|
|
||||||
// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
|
// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
|
||||||
void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
|
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
|
// Quit was called while loops other than those managed by this object
|
||||||
// were running further inside a run loop managed by this object. Now
|
// were running further inside a run loop managed by this object. Now
|
||||||
// that all unmanaged inner run loops are gone, stop the loop running
|
// that all unmanaged inner run loops are gone, stop the loop running
|
||||||
|
|
@ -595,7 +617,8 @@ MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
|
||||||
void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
|
void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
|
||||||
while (keep_running_) {
|
while (keep_running_) {
|
||||||
// NSRunLoop manages autorelease pools itself.
|
// NSRunLoop manages autorelease pools itself.
|
||||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
|
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||||
|
beforeDate:[NSDate distantFuture]];
|
||||||
}
|
}
|
||||||
|
|
||||||
keep_running_ = true;
|
keep_running_ = true;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,9 @@ void InitThreading() {
|
||||||
|
|
||||||
static BOOL multithreaded = [NSThread isMultiThreaded];
|
static BOOL multithreaded = [NSThread isMultiThreaded];
|
||||||
if (!multithreaded) {
|
if (!multithreaded) {
|
||||||
[NSThread detachNewThreadSelector:@selector(noOp) toTarget:[NoOp class] withObject:nil];
|
[NSThread detachNewThreadSelector:@selector(noOp)
|
||||||
|
toTarget:[NoOp class]
|
||||||
|
withObject:nil];
|
||||||
multithreaded = YES;
|
multithreaded = YES;
|
||||||
|
|
||||||
DCHECK([NSThread isMultiThreaded]);
|
DCHECK([NSThread isMultiThreaded]);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
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();
|
Result<Ok, LaunchError> retval = Ok();
|
||||||
|
|
||||||
char* argv_copy[argv.size() + 1];
|
char* argv_copy[argv.size() + 1];
|
||||||
|
|
@ -52,7 +53,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
||||||
|
|
||||||
EnvironmentArray env_storage;
|
EnvironmentArray env_storage;
|
||||||
const EnvironmentArray& vars =
|
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;
|
posix_spawn_file_actions_t file_actions;
|
||||||
int err = posix_spawn_file_actions_init(&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";
|
DLOG(WARNING) << "posix_spawn_file_actions_init failed";
|
||||||
return Err(LaunchError("posix_spawn_file_actions_init", err));
|
return Err(LaunchError("posix_spawn_file_actions_init", err));
|
||||||
}
|
}
|
||||||
auto file_actions_guard =
|
auto file_actions_guard = mozilla::MakeScopeExit(
|
||||||
mozilla::MakeScopeExit([&file_actions] { posix_spawn_file_actions_destroy(&file_actions); });
|
[&file_actions] { posix_spawn_file_actions_destroy(&file_actions); });
|
||||||
|
|
||||||
// Turn fds_to_remap array into a set of dup2 calls.
|
// 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()) {
|
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) {
|
if (rv != 0) {
|
||||||
DLOG(WARNING) << "posix_spawn_file_actions_addchdir_np failed";
|
DLOG(WARNING) << "posix_spawn_file_actions_addchdir_np failed";
|
||||||
return Err(LaunchError("posix_spawn_file_actions_addchdir", rv));
|
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";
|
DLOG(WARNING) << "posix_spawnattr_init failed";
|
||||||
return Err(LaunchError("posix_spawnattr_init", err));
|
return Err(LaunchError("posix_spawnattr_init", err));
|
||||||
}
|
}
|
||||||
auto spawnattr_guard =
|
auto spawnattr_guard = mozilla::MakeScopeExit(
|
||||||
mozilla::MakeScopeExit([&spawnattr] { posix_spawnattr_destroy(&spawnattr); });
|
[&spawnattr] { posix_spawnattr_destroy(&spawnattr); });
|
||||||
|
|
||||||
#if defined(XP_MACOSX) && defined(__aarch64__)
|
#if defined(XP_MACOSX) && defined(__aarch64__)
|
||||||
if (options.arch == PROCESS_ARCH_X86_64) {
|
if (options.arch == PROCESS_ARCH_X86_64) {
|
||||||
cpu_type_t cpu_pref = CPU_TYPE_X86_64;
|
cpu_type_t cpu_pref = CPU_TYPE_X86_64;
|
||||||
size_t count = 1;
|
size_t count = 1;
|
||||||
size_t ocount = 0;
|
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)) {
|
if ((rv != 0) || (ocount != count)) {
|
||||||
DLOG(WARNING) << "posix_spawnattr_setbinpref_np failed";
|
DLOG(WARNING) << "posix_spawnattr_setbinpref_np failed";
|
||||||
return Err(LaunchError("posix_spawnattr_setbinpref_np", rv));
|
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 pid = 0;
|
||||||
int spawn_succeeded =
|
int spawn_succeeded = (posix_spawnp(&pid, argv_copy[0], &file_actions,
|
||||||
(posix_spawnp(&pid, argv_copy[0], &file_actions, &spawnattr, argv_copy, vars.get()) == 0);
|
&spawnattr, argv_copy, vars.get()) == 0);
|
||||||
|
|
||||||
bool process_handle_valid = pid > 0;
|
bool process_handle_valid = pid > 0;
|
||||||
if (!spawn_succeeded || !process_handle_valid) {
|
if (!spawn_succeeded || !process_handle_valid) {
|
||||||
DLOG(WARNING) << "posix_spawnp failed";
|
DLOG(WARNING) << "posix_spawnp failed";
|
||||||
retval = Err(LaunchError("posix_spawnp", spawn_succeeded));
|
retval = Err(LaunchError("posix_spawnp", spawn_succeeded));
|
||||||
} else {
|
} 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 (options.wait) HANDLE_EINTR(waitpid(pid, 0, 0));
|
||||||
|
|
||||||
if (process_handle) *process_handle = pid;
|
if (process_handle) *process_handle = pid;
|
||||||
|
|
@ -159,7 +164,8 @@ Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
|
||||||
return retval;
|
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) {
|
ProcessHandle* process_handle) {
|
||||||
return LaunchApp(cl.argv(), options, process_handle);
|
return LaunchApp(cl.argv(), options, process_handle);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ ScopedNSAutoreleasePool::ScopedNSAutoreleasePool()
|
||||||
DCHECK(autorelease_pool_);
|
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
|
// Cycle the internal pool, allowing everything there to get cleaned up and
|
||||||
// start anew.
|
// start anew.
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,12 @@ static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
|
||||||
out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
|
out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
|
||||||
|
|
||||||
std::vector<typename StringType::value_type> out_buffer(elements);
|
std::vector<typename StringType::value_type> out_buffer(elements);
|
||||||
converted = CFStringGetBytes(cfstring, whole_string, encoding,
|
converted =
|
||||||
0, // lossByte
|
CFStringGetBytes(cfstring, whole_string, encoding,
|
||||||
false, // isExternalRepresentation
|
0, // lossByte
|
||||||
reinterpret_cast<UInt8*>(&out_buffer[0]), out_size,
|
false, // isExternalRepresentation
|
||||||
NULL); // usedBufLen
|
reinterpret_cast<UInt8*>(&out_buffer[0]), out_size,
|
||||||
|
NULL); // usedBufLen
|
||||||
if (converted == 0) return StringType();
|
if (converted == 0) return StringType();
|
||||||
|
|
||||||
out_buffer[elements - 1] = '\0';
|
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!
|
// Do not assert in this function since it is used by the asssertion code!
|
||||||
template <typename InStringType, typename OutStringType>
|
template <typename InStringType, typename OutStringType>
|
||||||
static OutStringType STLStringToSTLStringWithEncodingsT(const InStringType& in,
|
static OutStringType STLStringToSTLStringWithEncodingsT(
|
||||||
CFStringEncoding in_encoding,
|
const InStringType& in, CFStringEncoding in_encoding,
|
||||||
CFStringEncoding out_encoding) {
|
CFStringEncoding out_encoding) {
|
||||||
typename InStringType::size_type in_length = in.length();
|
typename InStringType::size_type in_length = in.length();
|
||||||
if (in_length == 0) return OutStringType();
|
if (in_length == 0) return OutStringType();
|
||||||
|
|
||||||
scoped_cftyperef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy(
|
scoped_cftyperef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy(
|
||||||
NULL, reinterpret_cast<const UInt8*>(in.data()),
|
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();
|
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|,
|
// Given an STL string |in| with an encoding specified by |in_encoding|,
|
||||||
// return it as a CFStringRef. Returns NULL on failure.
|
// return it as a CFStringRef. Returns NULL on failure.
|
||||||
template <typename StringType>
|
template <typename StringType>
|
||||||
static CFStringRef STLStringToCFStringWithEncodingsT(const StringType& in,
|
static CFStringRef STLStringToCFStringWithEncodingsT(
|
||||||
CFStringEncoding in_encoding) {
|
const StringType& in, CFStringEncoding in_encoding) {
|
||||||
typename StringType::size_type in_length = in.length();
|
typename StringType::size_type in_length = in.length();
|
||||||
if (in_length == 0) return CFSTR("");
|
if (in_length == 0) return CFSTR("");
|
||||||
|
|
||||||
return CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()),
|
return CFStringCreateWithBytes(
|
||||||
in_length * sizeof(typename StringType::value_type), in_encoding,
|
kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()),
|
||||||
false);
|
in_length * sizeof(typename StringType::value_type), in_encoding, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specify the byte ordering explicitly, otherwise CFString will be confused
|
// 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!
|
// Do not assert in this function since it is used by the asssertion code!
|
||||||
std::string SysWideToUTF8(const std::wstring& wide) {
|
std::string SysWideToUTF8(const std::wstring& wide) {
|
||||||
return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(wide, kWideStringEncoding,
|
return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(
|
||||||
kNarrowStringEncoding);
|
wide, kWideStringEncoding, kNarrowStringEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not assert in this function since it is used by the asssertion code!
|
// Do not assert in this function since it is used by the asssertion code!
|
||||||
std::wstring SysUTF8ToWide(const StringPiece& utf8) {
|
std::wstring SysUTF8ToWide(const StringPiece& utf8) {
|
||||||
return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(utf8, kNarrowStringEncoding,
|
return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(
|
||||||
kWideStringEncoding);
|
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
|
} // namespace base
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ NS_IMPL_ADDREF_INHERITED(MessagePumpForNonMainUIThreads, MessagePump)
|
||||||
NS_IMPL_RELEASE_INHERITED(MessagePumpForNonMainUIThreads, MessagePump)
|
NS_IMPL_RELEASE_INHERITED(MessagePumpForNonMainUIThreads, MessagePump)
|
||||||
NS_IMPL_QUERY_INTERFACE(MessagePumpForNonMainUIThreads, nsIThreadObserver)
|
NS_IMPL_QUERY_INTERFACE(MessagePumpForNonMainUIThreads, nsIThreadObserver)
|
||||||
|
|
||||||
MessagePumpForNonMainUIThreads::MessagePumpForNonMainUIThreads(nsISerialEventTarget* aEventTarget)
|
MessagePumpForNonMainUIThreads::MessagePumpForNonMainUIThreads(
|
||||||
|
nsISerialEventTarget* aEventTarget)
|
||||||
: mEventTarget(aEventTarget), keep_running_(true) {
|
: mEventTarget(aEventTarget), keep_running_(true) {
|
||||||
MOZ_ASSERT(mEventTarget);
|
MOZ_ASSERT(mEventTarget);
|
||||||
CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
|
CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
|
||||||
|
|
@ -36,13 +37,15 @@ MessagePumpForNonMainUIThreads::~MessagePumpForNonMainUIThreads() {
|
||||||
CFRelease(quit_source_);
|
CFRelease(quit_source_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagePumpForNonMainUIThreads::DoRun(base::MessagePump::Delegate* aDelegate) {
|
void MessagePumpForNonMainUIThreads::DoRun(
|
||||||
// If this is a chromium thread and no nsThread is associated with it, this call will create a
|
base::MessagePump::Delegate* aDelegate) {
|
||||||
// new nsThread.
|
// If this is a chromium thread and no nsThread is associated with it, this
|
||||||
|
// call will create a new nsThread.
|
||||||
nsIThread* thread = NS_GetCurrentThread();
|
nsIThread* thread = NS_GetCurrentThread();
|
||||||
MOZ_ASSERT(thread);
|
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));
|
nsCOMPtr<nsIThreadInternal> ti(do_QueryInterface(thread));
|
||||||
MOZ_ASSERT(ti);
|
MOZ_ASSERT(ti);
|
||||||
ti->SetObserver(this);
|
ti->SetObserver(this);
|
||||||
|
|
@ -63,7 +66,8 @@ void MessagePumpForNonMainUIThreads::DoRun(base::MessagePump::Delegate* aDelegat
|
||||||
|
|
||||||
// Now process the CFRunLoop. It exits after running once.
|
// Now process the CFRunLoop. It exits after running once.
|
||||||
// NSRunLoop manages autorelease pools itself.
|
// NSRunLoop manages autorelease pools itself.
|
||||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
|
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||||
|
beforeDate:[NSDate distantFuture]];
|
||||||
}
|
}
|
||||||
|
|
||||||
ti->SetObserver(nullptr);
|
ti->SetObserver(nullptr);
|
||||||
|
|
@ -77,14 +81,15 @@ void MessagePumpForNonMainUIThreads::Quit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP MessagePumpForNonMainUIThreads::OnDispatchedEvent() {
|
NS_IMETHODIMP MessagePumpForNonMainUIThreads::OnDispatchedEvent() {
|
||||||
// ScheduleWork will signal an input source to the run loop, making it exit so it can process the
|
// ScheduleWork will signal an input source to the run loop, making it exit so
|
||||||
// xpcom event.
|
// it can process the xpcom event.
|
||||||
ScheduleWork();
|
ScheduleWork();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
MessagePumpForNonMainUIThreads::OnProcessNextEvent(nsIThreadInternal* thread, bool mayWait) {
|
MessagePumpForNonMainUIThreads::OnProcessNextEvent(nsIThreadInternal* thread,
|
||||||
|
bool mayWait) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,28 +25,32 @@ void SetThisProcessName(const char* aProcessName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* currentName =
|
NSString* currentName = [[[NSBundle mainBundle] localizedInfoDictionary]
|
||||||
[[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:(NSString*)kCFBundleNameKey];
|
objectForKey:(NSString*)kCFBundleNameKey];
|
||||||
|
|
||||||
char formattedName[1024];
|
char formattedName[1024];
|
||||||
SprintfLiteral(formattedName, "%s %s", [currentName UTF8String], aProcessName);
|
SprintfLiteral(formattedName, "%s %s", [currentName UTF8String],
|
||||||
|
aProcessName);
|
||||||
|
|
||||||
aProcessName = formattedName;
|
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 CFTypeRef (*LSGetASNType)();
|
||||||
typedef OSStatus (*LSSetInformationItemType)(int, CFTypeRef, CFStringRef, CFStringRef,
|
typedef OSStatus (*LSSetInformationItemType)(int, CFTypeRef, CFStringRef,
|
||||||
CFDictionaryRef*);
|
CFStringRef, CFDictionaryRef*);
|
||||||
|
|
||||||
CFBundleRef launchServices = ::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
|
CFBundleRef launchServices =
|
||||||
|
::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
|
||||||
if (!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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sApplicationASN) {
|
if (!sApplicationASN) {
|
||||||
sApplicationASN =
|
sApplicationASN = ::CFBundleGetFunctionPointerForName(
|
||||||
::CFBundleGetFunctionPointerForName(launchServices, CFSTR("_LSGetCurrentApplicationASN"));
|
launchServices, CFSTR("_LSGetCurrentApplicationASN"));
|
||||||
if (!sApplicationASN) {
|
if (!sApplicationASN) {
|
||||||
NS_WARNING("Failed to set process name: Could not get function pointer "
|
NS_WARNING("Failed to set process name: Could not get function pointer "
|
||||||
"for LaunchServices");
|
"for LaunchServices");
|
||||||
|
|
@ -64,12 +68,13 @@ void SetThisProcessName(const char* aProcessName) {
|
||||||
LSSetInformationItemType setInformationItemFunc =
|
LSSetInformationItemType setInformationItemFunc =
|
||||||
reinterpret_cast<LSSetInformationItemType>(sApplicationInfoItem);
|
reinterpret_cast<LSSetInformationItemType>(sApplicationInfoItem);
|
||||||
|
|
||||||
void* displayNameKeyAddr =
|
void* displayNameKeyAddr = ::CFBundleGetDataPointerForName(
|
||||||
::CFBundleGetDataPointerForName(launchServices, CFSTR("_kLSDisplayNameKey"));
|
launchServices, CFSTR("_kLSDisplayNameKey"));
|
||||||
|
|
||||||
CFStringRef displayNameKey = nil;
|
CFStringRef displayNameKey = nil;
|
||||||
if (displayNameKeyAddr) {
|
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
|
// 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;
|
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");
|
NS_WARNING("Failed to set process name: Accessing launchServices failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFStringRef processName = ::CFStringCreateWithCString(nil, aProcessName, kCFStringEncodingASCII);
|
CFStringRef processName =
|
||||||
|
::CFStringCreateWithCString(nil, aProcessName, kCFStringEncodingASCII);
|
||||||
if (!processName) {
|
if (!processName) {
|
||||||
NS_WARNING("Failed to set process name: Could not create CFStringRef");
|
NS_WARNING("Failed to set process name: Could not create CFStringRef");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSErr err =
|
OSErr err = setInformationItemFunc(UNDOCUMENTED_SESSION_CONSTANT, currentAsn,
|
||||||
setInformationItemFunc(UNDOCUMENTED_SESSION_CONSTANT, currentAsn, displayNameKey, processName,
|
displayNameKey, processName,
|
||||||
nil); // Optional out param
|
nil); // Optional out param
|
||||||
::CFRelease(processName);
|
::CFRelease(processName);
|
||||||
if (err != noErr) {
|
if (err != noErr) {
|
||||||
NS_WARNING("Failed to set process name: LSSetInformationItemType err");
|
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);
|
memory_object_size_t memoryObjectSize = round_page(size);
|
||||||
|
|
||||||
kern_return_t kr = mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
|
kern_return_t kr =
|
||||||
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
|
mach_make_memory_entry_64(mach_task_self(), &memoryObjectSize, 0,
|
||||||
getter_Transfers(mPort), MACH_PORT_NULL);
|
MAP_MEM_NAMED_CREATE | VM_PROT_DEFAULT,
|
||||||
|
getter_Transfers(mPort), MACH_PORT_NULL);
|
||||||
if (kr != KERN_SUCCESS || memoryObjectSize < round_page(size)) {
|
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),
|
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n", size,
|
||||||
kr);
|
mach_error_string(kr), kr);
|
||||||
CloseHandle();
|
CloseHandle();
|
||||||
return false;
|
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,
|
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
|
||||||
fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE, mPort.get(), 0, false,
|
fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
|
||||||
vmProtection, vmProtection, VM_INHERIT_NONE);
|
mPort.get(), 0, false, vmProtection, vmProtection,
|
||||||
|
VM_INHERIT_NONE);
|
||||||
if (kr != KERN_SUCCESS) {
|
if (kr != KERN_SUCCESS) {
|
||||||
if (!fixed_address) {
|
if (!fixed_address) {
|
||||||
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n", size,
|
LOG_ERROR(
|
||||||
mach_task_self(), mach_port_t(mPort.get()), mach_error_string(kr), kr);
|
"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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +120,8 @@ bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
|
||||||
if (kr != KERN_SUCCESS) {
|
if (kr != KERN_SUCCESS) {
|
||||||
LOG_ERROR("Failed to unmap shared memory at unsuitable address "
|
LOG_ERROR("Failed to unmap shared memory at unsuitable address "
|
||||||
"(%zu bytes) from %x, port %x. %s (%x)\n",
|
"(%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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -129,8 +134,9 @@ bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
|
||||||
void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
|
void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
|
||||||
mach_vm_address_t address = 0;
|
mach_vm_address_t address = 0;
|
||||||
size = round_page(size);
|
size = round_page(size);
|
||||||
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0,
|
if (mach_vm_map(mach_task_self(), &address, size, 0, VM_FLAGS_ANYWHERE,
|
||||||
false, VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_NONE) != KERN_SUCCESS ||
|
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) {
|
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -146,9 +152,11 @@ void SharedMemoryBasic::Unmap() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vm_address_t address = toVMAddress(mMemory);
|
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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
mMemory = nullptr;
|
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 ipc
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,9 @@ static OSStatus getErrorCodeBool(Boolean success) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If given a NULL pointer, return the error code.
|
// 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.
|
// Convenience function to allow NULL input.
|
||||||
static void CFReleaseSafe(CFTypeRef cf) {
|
static void CFReleaseSafe(CFTypeRef cf) {
|
||||||
|
|
@ -86,8 +88,8 @@ static void CFReleaseSafe(CFTypeRef cf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver, nsITimerCallback,
|
NS_IMPL_ISUPPORTS(nsNetworkLinkService, nsINetworkLinkService, nsIObserver,
|
||||||
nsINamed)
|
nsITimerCallback, nsINamed)
|
||||||
|
|
||||||
nsNetworkLinkService::nsNetworkLinkService()
|
nsNetworkLinkService::nsNetworkLinkService()
|
||||||
: mLinkUp(true),
|
: mLinkUp(true),
|
||||||
|
|
@ -129,7 +131,8 @@ nsNetworkLinkService::GetNetworkID(nsACString& aNetworkID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsNetworkLinkService::GetPlatformDNSIndications(uint32_t* aPlatformDNSIndications) {
|
nsNetworkLinkService::GetPlatformDNSIndications(
|
||||||
|
uint32_t* aPlatformDNSIndications) {
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,8 +142,9 @@ void nsNetworkLinkService::GetDnsSuffixListInternal() {
|
||||||
|
|
||||||
auto sendNotification = mozilla::MakeScopeExit([self = RefPtr{this}] {
|
auto sendNotification = mozilla::MakeScopeExit([self = RefPtr{this}] {
|
||||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||||
"nsNetworkLinkService::GetDnsSuffixListInternal",
|
"nsNetworkLinkService::GetDnsSuffixListInternal", [self]() {
|
||||||
[self]() { self->NotifyObservers(NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, nullptr); }));
|
self->NotifyObservers(NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, nullptr);
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
nsTArray<nsCString> result;
|
nsTArray<nsCString> result;
|
||||||
|
|
@ -176,15 +180,17 @@ nsNetworkLinkService::GetResolvers(nsTArray<RefPtr<nsINetAddr>>& aResolvers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsNetworkLinkService::GetNativeResolvers(nsTArray<mozilla::net::NetAddr>& aResolvers) {
|
nsNetworkLinkService::GetNativeResolvers(
|
||||||
|
nsTArray<mozilla::net::NetAddr>& aResolvers) {
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SA_SIZE
|
#ifndef SA_SIZE
|
||||||
# define SA_SIZE(sa) \
|
# define SA_SIZE(sa) \
|
||||||
((!(sa) || ((struct sockaddr*)(sa))->sa_len == 0) \
|
((!(sa) || ((struct sockaddr*)(sa))->sa_len == 0) \
|
||||||
? sizeof(uint32_t) \
|
? sizeof(uint32_t) \
|
||||||
: 1 + ((((struct sockaddr*)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1)))
|
: 1 + ((((struct sockaddr*)(sa))->sa_len - 1) | \
|
||||||
|
(sizeof(uint32_t) - 1)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool getMac(struct sockaddr_dl* sdl, char* buf, size_t bufsize) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4],
|
snprintf(buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1],
|
||||||
mac[5]);
|
mac[2], mac[3], mac[4], mac[5]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the IP matches, get the MAC and 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,
|
static bool matchIp(struct sockaddr_dl* sdl, struct sockaddr_inarp* addr,
|
||||||
size_t bufsize) {
|
char* ip, char* buf, size_t bufsize) {
|
||||||
if (sdl->sdl_alen) {
|
if (sdl->sdl_alen) {
|
||||||
if (!strcmp(inet_ntoa(addr->sin_addr), ip)) {
|
if (!strcmp(inet_ntoa(addr->sin_addr), ip)) {
|
||||||
if (getMac(sdl, buf, bufsize)) {
|
if (getMac(sdl, buf, bufsize)) {
|
||||||
|
|
@ -275,8 +281,10 @@ static bool scanArp(char* ip, char* mac, size_t maclen) {
|
||||||
struct rt_msghdr* rtm;
|
struct rt_msghdr* rtm;
|
||||||
for (next = &buf[0]; next < lim; next += rtm->rtm_msglen) {
|
for (next = &buf[0]; next < lim; next += rtm->rtm_msglen) {
|
||||||
rtm = reinterpret_cast<struct rt_msghdr*>(next);
|
rtm = reinterpret_cast<struct rt_msghdr*>(next);
|
||||||
struct sockaddr_inarp* sin2 = reinterpret_cast<struct sockaddr_inarp*>(rtm + 1);
|
struct sockaddr_inarp* sin2 =
|
||||||
struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>((char*)sin2 + SA_SIZE(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)) {
|
if (matchIp(sdl, sin2, ip, mac, maclen)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -285,9 +293,10 @@ static bool scanArp(char* ip, char* mac, size_t maclen) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the mac address of rtm to `stringsToHash`. If it's not in arp table, append
|
// Append the mac address of rtm to `stringsToHash`. If it's not in arp table,
|
||||||
// ifname and IP address.
|
// append ifname and IP address.
|
||||||
static bool parseHashKey(struct rt_msghdr* rtm, nsTArray<nsCString>& stringsToHash,
|
static bool parseHashKey(struct rt_msghdr* rtm,
|
||||||
|
nsTArray<nsCString>& stringsToHash,
|
||||||
bool skipDstCheck) {
|
bool skipDstCheck) {
|
||||||
struct sockaddr* sa;
|
struct sockaddr* sa;
|
||||||
struct sockaddr_in* sockin;
|
struct sockaddr_in* sockin;
|
||||||
|
|
@ -317,8 +326,8 @@ static bool parseHashKey(struct rt_msghdr* rtm, nsTArray<nsCString>& stringsToHa
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr* gateway =
|
struct sockaddr* gateway = reinterpret_cast<struct sockaddr*>(
|
||||||
reinterpret_cast<struct sockaddr*>((char*)sa + RTAX_GATEWAY * SA_SIZE(sa));
|
(char*)sa + RTAX_GATEWAY * SA_SIZE(sa));
|
||||||
|
|
||||||
if (!gateway) {
|
if (!gateway) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -440,7 +449,8 @@ bool nsNetworkLinkService::RoutingFromKernel(nsTArray<nsCString>& aHash) {
|
||||||
sin->sin_addr = mRouteCheckIPv4;
|
sin->sin_addr = mRouteCheckIPv4;
|
||||||
|
|
||||||
if (write(sockfd, rtm, rtm->rtm_msglen) == -1) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -451,9 +461,11 @@ bool nsNetworkLinkService::RoutingFromKernel(nsTArray<nsCString>& aHash) {
|
||||||
return false;
|
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));
|
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);
|
return parseHashKey(rtm, aHash, true);
|
||||||
}
|
}
|
||||||
|
|
@ -489,8 +501,9 @@ bool nsNetworkLinkService::IPv4NetworkId(SHA1Sum* aSHA1) {
|
||||||
//
|
//
|
||||||
void nsNetworkLinkService::HashSortedPrefixesAndNetmasks(
|
void nsNetworkLinkService::HashSortedPrefixesAndNetmasks(
|
||||||
std::vector<prefix_and_netmask> prefixAndNetmaskStore, SHA1Sum* sha1) {
|
std::vector<prefix_and_netmask> prefixAndNetmaskStore, SHA1Sum* sha1) {
|
||||||
// getifaddrs does not guarantee the interfaces will always be in the same order.
|
// getifaddrs does not guarantee the interfaces will always be in the same
|
||||||
// We want to make sure the hash remains consistent Regardless of the interface order.
|
// order. We want to make sure the hash remains consistent Regardless of the
|
||||||
|
// interface order.
|
||||||
std::sort(prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(),
|
std::sort(prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(),
|
||||||
[](prefix_and_netmask a, prefix_and_netmask b) {
|
[](prefix_and_netmask a, prefix_and_netmask b) {
|
||||||
// compare prefixStore
|
// compare prefixStore
|
||||||
|
|
@ -521,7 +534,8 @@ bool nsNetworkLinkService::IPv6NetworkId(SHA1Sum* sha1) {
|
||||||
if ((AF_INET6 == ifa->ifa_addr->sa_family) &&
|
if ((AF_INET6 == ifa->ifa_addr->sa_family) &&
|
||||||
!(ifa->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))) {
|
!(ifa->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))) {
|
||||||
// only IPv6 interfaces that aren't pointtopoint or 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) {
|
if (sin_netmask) {
|
||||||
struct sockaddr_in6* sin_addr = (struct sockaddr_in6*)ifa->ifa_addr;
|
struct sockaddr_in6* sin_addr = (struct sockaddr_in6*)ifa->ifa_addr;
|
||||||
int scope = net::utils::ipv6_scope(sin_addr->sin6_addr.s6_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));
|
memset(&prefix, 0, sizeof(prefix));
|
||||||
// Get the prefix by combining the address and netmask.
|
// Get the prefix by combining the address and netmask.
|
||||||
for (size_t i = 0; i < sizeof(prefix); ++i) {
|
for (size_t i = 0; i < sizeof(prefix); ++i) {
|
||||||
prefix.s6_addr[i] =
|
prefix.s6_addr[i] = sin_addr->sin6_addr.s6_addr[i] &
|
||||||
sin_addr->sin6_addr.s6_addr[i] & sin_netmask->sin6_addr.s6_addr[i];
|
sin_netmask->sin6_addr.s6_addr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if prefix and netmask was already found
|
// 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(
|
auto foundPosition = std::find_if(
|
||||||
prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(),
|
prefixAndNetmaskStore.begin(), prefixAndNetmaskStore.end(),
|
||||||
[&prefixAndNetmask](prefix_and_netmask current) {
|
[&prefixAndNetmask](prefix_and_netmask current) {
|
||||||
return memcmp(&prefixAndNetmask.first, ¤t.first, sizeof(in6_addr)) == 0 &&
|
return memcmp(&prefixAndNetmask.first, ¤t.first,
|
||||||
memcmp(&prefixAndNetmask.second, ¤t.second, sizeof(in6_addr)) == 0;
|
sizeof(in6_addr)) == 0 &&
|
||||||
|
memcmp(&prefixAndNetmask.second, ¤t.second,
|
||||||
|
sizeof(in6_addr)) == 0;
|
||||||
});
|
});
|
||||||
if (foundPosition != prefixAndNetmaskStore.end()) {
|
if (foundPosition != prefixAndNetmaskStore.end()) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -557,7 +574,8 @@ bool nsNetworkLinkService::IPv6NetworkId(SHA1Sum* sha1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsNetworkLinkService::HashSortedPrefixesAndNetmasks(prefixAndNetmaskStore, sha1);
|
nsNetworkLinkService::HashSortedPrefixesAndNetmasks(prefixAndNetmaskStore,
|
||||||
|
sha1);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -577,15 +595,17 @@ void nsNetworkLinkService::calculateNetworkIdWithDelay(uint32_t aDelay) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
nsCOMPtr<nsIEventTarget> target =
|
||||||
|
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ALWAYS_SUCCEEDS(
|
MOZ_ALWAYS_SUCCEEDS(target->Dispatch(
|
||||||
target->Dispatch(NewRunnableMethod("nsNetworkLinkService::calculateNetworkIdInternal", this,
|
NewRunnableMethod("nsNetworkLinkService::calculateNetworkIdInternal",
|
||||||
&nsNetworkLinkService::calculateNetworkIdInternal),
|
this,
|
||||||
NS_DISPATCH_NORMAL));
|
&nsNetworkLinkService::calculateNetworkIdInternal),
|
||||||
|
NS_DISPATCH_NORMAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
@ -615,7 +635,8 @@ void nsNetworkLinkService::calculateNetworkIdInternal(void) {
|
||||||
SeedNetworkId(sha1);
|
SeedNetworkId(sha1);
|
||||||
uint8_t digest[SHA1Sum::kHashSize];
|
uint8_t digest[SHA1Sum::kHashSize];
|
||||||
sha1.finish(digest);
|
sha1.finish(digest);
|
||||||
nsAutoCString newString(reinterpret_cast<char*>(digest), SHA1Sum::kHashSize);
|
nsAutoCString newString(reinterpret_cast<char*>(digest),
|
||||||
|
SHA1Sum::kHashSize);
|
||||||
nsresult rv = Base64Encode(newString, output);
|
nsresult rv = Base64Encode(newString, output);
|
||||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||||
LOG(("networkid: id %s\n", output.get()));
|
LOG(("networkid: id %s\n", output.get()));
|
||||||
|
|
@ -652,16 +673,17 @@ void nsNetworkLinkService::calculateNetworkIdInternal(void) {
|
||||||
if (idChanged && !initialIDCalculation) {
|
if (idChanged && !initialIDCalculation) {
|
||||||
RefPtr<nsNetworkLinkService> self = this;
|
RefPtr<nsNetworkLinkService> self = this;
|
||||||
|
|
||||||
NS_DispatchToMainThread(
|
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||||
NS_NewRunnableFunction("nsNetworkLinkService::calculateNetworkIdInternal",
|
"nsNetworkLinkService::calculateNetworkIdInternal",
|
||||||
[self]() { self->OnNetworkIdChanged(); }));
|
[self]() { self->OnNetworkIdChanged(); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
initialIDCalculation = false;
|
initialIDCalculation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
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")) {
|
if (!strcmp(topic, "xpcom-shutdown")) {
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
@ -671,14 +693,17 @@ nsNetworkLinkService::Observe(nsISupports* subject, const char* topic, const cha
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
void nsNetworkLinkService::NetworkConfigChanged(SCDynamicStoreRef aStoreREf,
|
void nsNetworkLinkService::NetworkConfigChanged(SCDynamicStoreRef aStoreREf,
|
||||||
CFArrayRef aChangedKeys, void* aInfo) {
|
CFArrayRef aChangedKeys,
|
||||||
|
void* aInfo) {
|
||||||
LOG(("nsNetworkLinkService::NetworkConfigChanged"));
|
LOG(("nsNetworkLinkService::NetworkConfigChanged"));
|
||||||
|
|
||||||
bool ipConfigChanged = false;
|
bool ipConfigChanged = false;
|
||||||
bool dnsConfigChanged = false;
|
bool dnsConfigChanged = false;
|
||||||
for (CFIndex i = 0; i < CFArrayGetCount(aChangedKeys); ++i) {
|
for (CFIndex i = 0; i < CFArrayGetCount(aChangedKeys); ++i) {
|
||||||
CFStringRef key = static_cast<CFStringRef>(CFArrayGetValueAtIndex(aChangedKeys, i));
|
CFStringRef key =
|
||||||
if (CFStringHasSuffix(key, kSCEntNetIPv4) || CFStringHasSuffix(key, kSCEntNetIPv6)) {
|
static_cast<CFStringRef>(CFArrayGetValueAtIndex(aChangedKeys, i));
|
||||||
|
if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
|
||||||
|
CFStringHasSuffix(key, kSCEntNetIPv6)) {
|
||||||
ipConfigChanged = true;
|
ipConfigChanged = true;
|
||||||
}
|
}
|
||||||
if (CFStringHasSuffix(key, kSCEntNetDNS)) {
|
if (CFStringHasSuffix(key, kSCEntNetDNS)) {
|
||||||
|
|
@ -698,7 +723,8 @@ void nsNetworkLinkService::NetworkConfigChanged(SCDynamicStoreRef aStoreREf,
|
||||||
|
|
||||||
void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) {
|
void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) {
|
||||||
LOG(("nsNetworkLinkService::DNSConfigChanged"));
|
LOG(("nsNetworkLinkService::DNSConfigChanged"));
|
||||||
nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
nsCOMPtr<nsIEventTarget> target =
|
||||||
|
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -717,9 +743,9 @@ void nsNetworkLinkService::DNSConfigChanged(uint32_t aDelayMs) {
|
||||||
"nsNetworkLinkService::GetDnsSuffixListInternal", target));
|
"nsNetworkLinkService::GetDnsSuffixListInternal", target));
|
||||||
mDNSConfigChangedTimers.AppendElement(timer);
|
mDNSConfigChangedTimers.AppendElement(timer);
|
||||||
} else {
|
} else {
|
||||||
MOZ_ALWAYS_SUCCEEDS(target->Dispatch(
|
MOZ_ALWAYS_SUCCEEDS(target->Dispatch(NS_NewRunnableFunction(
|
||||||
NS_NewRunnableFunction("nsNetworkLinkService::GetDnsSuffixListInternal",
|
"nsNetworkLinkService::GetDnsSuffixListInternal",
|
||||||
[self = RefPtr{this}]() { self->GetDnsSuffixListInternal(); })));
|
[self = RefPtr{this}]() { self->GetDnsSuffixListInternal(); })));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -745,13 +771,15 @@ nsresult nsNetworkLinkService::Init(void) {
|
||||||
bzero(&addr, sizeof(addr));
|
bzero(&addr, sizeof(addr));
|
||||||
addr.sin_len = sizeof(addr);
|
addr.sin_len = sizeof(addr);
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
mReachability = ::SCNetworkReachabilityCreateWithAddress(nullptr, (struct sockaddr*)&addr);
|
mReachability = ::SCNetworkReachabilityCreateWithAddress(
|
||||||
|
nullptr, (struct sockaddr*)&addr);
|
||||||
if (!mReachability) {
|
if (!mReachability) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCNetworkReachabilityContext context = {0, this, nullptr, nullptr, nullptr};
|
SCNetworkReachabilityContext context = {0, this, nullptr, nullptr, nullptr};
|
||||||
if (!::SCNetworkReachabilitySetCallback(mReachability, ReachabilityChanged, &context)) {
|
if (!::SCNetworkReachabilitySetCallback(mReachability, ReachabilityChanged,
|
||||||
|
&context)) {
|
||||||
NS_WARNING("SCNetworkReachabilitySetCallback failed.");
|
NS_WARNING("SCNetworkReachabilitySetCallback failed.");
|
||||||
::CFRelease(mReachability);
|
::CFRelease(mReachability);
|
||||||
mReachability = nullptr;
|
mReachability = nullptr;
|
||||||
|
|
@ -759,24 +787,25 @@ nsresult nsNetworkLinkService::Init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SCDynamicStoreContext storeContext = {0, this, nullptr, nullptr, nullptr};
|
SCDynamicStoreContext storeContext = {0, this, nullptr, nullptr, nullptr};
|
||||||
mStoreRef = ::SCDynamicStoreCreate(nullptr, CFSTR("IPAndDNSChangeCallbackSCF"),
|
mStoreRef =
|
||||||
NetworkConfigChanged, &storeContext);
|
::SCDynamicStoreCreate(nullptr, CFSTR("IPAndDNSChangeCallbackSCF"),
|
||||||
|
NetworkConfigChanged, &storeContext);
|
||||||
|
|
||||||
CFStringRef patterns[4] = {nullptr, nullptr, nullptr, nullptr};
|
CFStringRef patterns[4] = {nullptr, nullptr, nullptr, nullptr};
|
||||||
OSStatus err = getErrorCodePtr(mStoreRef);
|
OSStatus err = getErrorCodePtr(mStoreRef);
|
||||||
if (err == noErr) {
|
if (err == noErr) {
|
||||||
// This pattern is "State:/Network/Service/[^/]+/IPv4".
|
// This pattern is "State:/Network/Service/[^/]+/IPv4".
|
||||||
patterns[0] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState,
|
patterns[0] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
|
||||||
kSCCompAnyRegex, kSCEntNetIPv4);
|
nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
|
||||||
// This pattern is "State:/Network/Service/[^/]+/IPv6".
|
// This pattern is "State:/Network/Service/[^/]+/IPv6".
|
||||||
patterns[1] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState,
|
patterns[1] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
|
||||||
kSCCompAnyRegex, kSCEntNetIPv6);
|
nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
|
||||||
// This pattern is "State:/Network/Service/[^/]+/DNS".
|
// This pattern is "State:/Network/Service/[^/]+/DNS".
|
||||||
patterns[2] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainState,
|
patterns[2] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
|
||||||
kSCCompAnyRegex, kSCEntNetDNS);
|
nullptr, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetDNS);
|
||||||
// This pattern is "Setup:/Network/Service/[^/]+/DNS".
|
// This pattern is "Setup:/Network/Service/[^/]+/DNS".
|
||||||
patterns[3] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(nullptr, kSCDynamicStoreDomainSetup,
|
patterns[3] = ::SCDynamicStoreKeyCreateNetworkServiceEntity(
|
||||||
kSCCompAnyRegex, kSCEntNetDNS);
|
nullptr, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetDNS);
|
||||||
if (!patterns[0] || !patterns[1] || !patterns[2] || !patterns[3]) {
|
if (!patterns[0] || !patterns[1] || !patterns[2] || !patterns[3]) {
|
||||||
err = -1;
|
err = -1;
|
||||||
}
|
}
|
||||||
|
|
@ -788,13 +817,15 @@ nsresult nsNetworkLinkService::Init(void) {
|
||||||
// that match that pattern list, then create our run loop
|
// that match that pattern list, then create our run loop
|
||||||
// source.
|
// source.
|
||||||
if (err == noErr) {
|
if (err == noErr) {
|
||||||
patternList = ::CFArrayCreate(nullptr, (const void**)patterns, 4, &kCFTypeArrayCallBacks);
|
patternList = ::CFArrayCreate(nullptr, (const void**)patterns, 4,
|
||||||
|
&kCFTypeArrayCallBacks);
|
||||||
if (!patternList) {
|
if (!patternList) {
|
||||||
err = -1;
|
err = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (err == noErr) {
|
if (err == noErr) {
|
||||||
err = getErrorCodeBool(::SCDynamicStoreSetNotificationKeys(mStoreRef, nullptr, patternList));
|
err = getErrorCodeBool(
|
||||||
|
::SCDynamicStoreSetNotificationKeys(mStoreRef, nullptr, patternList));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == noErr) {
|
if (err == noErr) {
|
||||||
|
|
@ -925,26 +956,31 @@ void nsNetworkLinkService::OnReachabilityChanged() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NotifyObservers(NS_NETWORK_LINK_TOPIC,
|
NotifyObservers(NS_NETWORK_LINK_TOPIC, mLinkUp ? NS_NETWORK_LINK_DATA_UP
|
||||||
mLinkUp ? NS_NETWORK_LINK_DATA_UP : NS_NETWORK_LINK_DATA_DOWN);
|
: 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());
|
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) {
|
if (observerService) {
|
||||||
observerService->NotifyObservers(static_cast<nsINetworkLinkService*>(this), aTopic,
|
observerService->NotifyObservers(
|
||||||
aData ? NS_ConvertASCIItoUTF16(aData).get() : nullptr);
|
static_cast<nsINetworkLinkService*>(this), aTopic,
|
||||||
|
aData ? NS_ConvertASCIItoUTF16(aData).get() : nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
void nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target,
|
void nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target,
|
||||||
SCNetworkConnectionFlags flags, void* info) {
|
SCNetworkConnectionFlags flags,
|
||||||
|
void* info) {
|
||||||
LOG(("nsNetworkLinkService::ReachabilityChanged"));
|
LOG(("nsNetworkLinkService::ReachabilityChanged"));
|
||||||
nsNetworkLinkService* service = static_cast<nsNetworkLinkService*>(info);
|
nsNetworkLinkService* service = static_cast<nsNetworkLinkService*>(info);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
NSBundle* bundle = [[[NSBundle alloc]
|
NSBundle* bundle = [[[NSBundle alloc]
|
||||||
initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"] autorelease];
|
initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"]
|
||||||
|
autorelease];
|
||||||
if (!bundle) {
|
if (!bundle) {
|
||||||
[pool release];
|
[pool release];
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
@ -41,7 +42,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
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) {
|
if (!scanResult) {
|
||||||
[pool release];
|
[pool release];
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
@ -73,7 +75,8 @@ nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
|
||||||
NSString* macString = [anObject bssid];
|
NSString* macString = [anObject bssid];
|
||||||
if (macString && ([macString length] == 17)) {
|
if (macString && ([macString length] == 17)) {
|
||||||
for (NSUInteger i = 0; i < 6; ++i) {
|
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];
|
NSScanner* scanner = [NSScanner scannerWithString:part];
|
||||||
unsigned int data = 0;
|
unsigned int data = 0;
|
||||||
if (![scanner scanHexInt:&data]) {
|
if (![scanner scanHexInt:&data]) {
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,15 @@ nsresult ReauthenticateUserMacOS(const nsAString& aPrompt,
|
||||||
localizedReason:prompt
|
localizedReason:prompt
|
||||||
reply:^(BOOL success, NSError* error) {
|
reply:^(BOOL success, NSError* error) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
// error is not particularly useful in this context, and we have no
|
// error is not particularly useful in this context, and
|
||||||
// mechanism to really return it. We could use it to set the nsresult,
|
// we have no mechanism to really return it. We could
|
||||||
// but this is a best-effort mechanism and there's no particular case for
|
// use it to set the nsresult, but this is a best-effort
|
||||||
// propagating up XPCOM. The one exception being a user account that
|
// mechanism and there's no particular case for
|
||||||
// has no passcode set, which we handle below.
|
// propagating up XPCOM. The one exception being a user
|
||||||
errorPasswordNotSet = error && [error code] == kPasswordNotSetErrorCode;
|
// account that has no passcode set, which we handle
|
||||||
|
// below.
|
||||||
|
errorPasswordNotSet =
|
||||||
|
error && [error code] == kPasswordNotSetErrorCode;
|
||||||
biometricSuccess = success || errorPasswordNotSet;
|
biometricSuccess = success || errorPasswordNotSet;
|
||||||
dispatch_semaphore_signal(sema);
|
dispatch_semaphore_signal(sema);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@
|
||||||
|
|
||||||
// Undocumented sandbox setup routines.
|
// Undocumented sandbox setup routines.
|
||||||
extern "C" int sandbox_init_with_parameters(const char* profile, uint64_t flags,
|
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" void sandbox_free_error(char* errorbuf);
|
||||||
extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...);
|
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);
|
static void Get(int32_t& aMajor, int32_t& aMinor);
|
||||||
|
|
||||||
private:
|
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 bool mCached;
|
||||||
static int32_t mOSXVersionMajor;
|
static int32_t mOSXVersionMajor;
|
||||||
static int32_t mOSXVersionMinor;
|
static int32_t mOSXVersionMinor;
|
||||||
|
|
@ -72,23 +74,26 @@ void OSXVersion::Get(int32_t& aMajor, int32_t& aMinor) {
|
||||||
aMinor = mOSXVersionMinor;
|
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;
|
SInt32 major = 0, minor = 0, bugfix = 0;
|
||||||
|
|
||||||
CFURLRef url = CFURLCreateWithString(
|
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);
|
CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
|
||||||
CFReadStreamOpen(stream);
|
CFReadStreamOpen(stream);
|
||||||
CFDictionaryRef sysVersionPlist = (CFDictionaryRef)CFPropertyListCreateWithStream(
|
CFDictionaryRef sysVersionPlist =
|
||||||
kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL);
|
(CFDictionaryRef)CFPropertyListCreateWithStream(
|
||||||
|
kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL);
|
||||||
CFReadStreamClose(stream);
|
CFReadStreamClose(stream);
|
||||||
CFRelease(stream);
|
CFRelease(stream);
|
||||||
CFRelease(url);
|
CFRelease(url);
|
||||||
|
|
||||||
CFStringRef versionString =
|
CFStringRef versionString = (CFStringRef)CFDictionaryGetValue(
|
||||||
(CFStringRef)CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion"));
|
sysVersionPlist, CFSTR("ProductVersion"));
|
||||||
CFArrayRef versions =
|
CFArrayRef versions = CFStringCreateArrayBySeparatingStrings(
|
||||||
CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, versionString, CFSTR("."));
|
kCFAllocatorDefault, versionString, CFSTR("."));
|
||||||
CFIndex count = CFArrayGetCount(versions);
|
CFIndex count = CFArrayGetCount(versions);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
CFStringRef component = (CFStringRef)CFArrayGetValueAtIndex(versions, 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");
|
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) {
|
if (this->shouldLog) {
|
||||||
aParams.push_back("-sbLogging");
|
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("-sbAppPath");
|
||||||
aParams.push_back(this->appPath);
|
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("-sbPluginPath");
|
||||||
aParams.push_back(this->pluginPath);
|
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) {
|
if (this->hasWindowServer) {
|
||||||
aParams.push_back("-sbAllowWindowServer");
|
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()) {
|
if (!this->testingReadPath1.empty()) {
|
||||||
aParams.push_back("-sbTestingReadPath");
|
aParams.push_back("-sbTestingReadPath");
|
||||||
aParams.push_back(this->testingReadPath1.c_str());
|
aParams.push_back(this->testingReadPath1.c_str());
|
||||||
|
|
@ -256,7 +267,8 @@ void MacSandboxInfo::AppendReadPathParams(std::vector<std::string>& aParams) con
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void MacSandboxInfo::AppendDebugWriteDirParam(std::vector<std::string>& aParams) const {
|
void MacSandboxInfo::AppendDebugWriteDirParam(
|
||||||
|
std::vector<std::string>& aParams) const {
|
||||||
if (!this->debugWriteDir.empty()) {
|
if (!this->debugWriteDir.empty()) {
|
||||||
aParams.push_back("-sbDebugWriteDir");
|
aParams.push_back("-sbDebugWriteDir");
|
||||||
aParams.push_back(this->debugWriteDir.c_str());
|
aParams.push_back(this->debugWriteDir.c_str());
|
||||||
|
|
@ -430,7 +442,8 @@ bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
|
||||||
profile.append(SandboxPolicyContentAudioAddend);
|
profile.append(SandboxPolicyContentAudioAddend);
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -465,7 +478,8 @@ bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage) {
|
||||||
params.push_back(nullptr);
|
params.push_back(nullptr);
|
||||||
|
|
||||||
char* errorbuf = NULL;
|
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 (rv) {
|
||||||
if (errorbuf) {
|
if (errorbuf) {
|
||||||
char* msg = NULL;
|
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
|
* command line arguments. Return false if any sandbox parameters needed
|
||||||
* for early startup of the sandbox are not present in the arguments.
|
* 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
|
// Ensure we find these paramaters in the command
|
||||||
// line arguments. Return false if any are missing.
|
// line arguments. Return false if any are missing.
|
||||||
bool foundSandboxLevel = false;
|
bool foundSandboxLevel = false;
|
||||||
|
|
@ -604,7 +619,8 @@ bool GetContentSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aI
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo,
|
bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv,
|
||||||
|
MacSandboxInfo& aInfo,
|
||||||
bool aSandboxingKindRequired = true) {
|
bool aSandboxingKindRequired = true) {
|
||||||
// Ensure we find these paramaters in the command
|
// Ensure we find these paramaters in the command
|
||||||
// line arguments. Return false if any are missing.
|
// line arguments. Return false if any are missing.
|
||||||
|
|
@ -650,11 +666,13 @@ bool GetUtilitySandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aI
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) {
|
bool GetSocketSandboxParamsFromArgs(int aArgc, char** aArgv,
|
||||||
|
MacSandboxInfo& aInfo) {
|
||||||
return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
|
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
|
// Ensure we find these paramaters in the command
|
||||||
// line arguments. Return false if any are missing.
|
// line arguments. Return false if any are missing.
|
||||||
bool foundAppPath = false;
|
bool foundAppPath = false;
|
||||||
|
|
@ -725,7 +743,8 @@ bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aIn
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) {
|
bool GetRDDSandboxParamsFromArgs(int aArgc, char** aArgv,
|
||||||
|
MacSandboxInfo& aInfo) {
|
||||||
return GetUtilitySandboxParamsFromArgs(aArgc, aArgv, aInfo, false);
|
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
|
* 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.
|
* not enabled for this process. Returns false if an error was encountered.
|
||||||
*/
|
*/
|
||||||
bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc, char** aArgv,
|
bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc,
|
||||||
std::string& aErrorMessage) {
|
char** aArgv, std::string& aErrorMessage) {
|
||||||
bool earlyStartupEnabled = false;
|
bool earlyStartupEnabled = false;
|
||||||
|
|
||||||
// Check for the -sbStartup CLI parameter which
|
// Check for the -sbStartup CLI parameter which
|
||||||
|
|
@ -796,7 +815,9 @@ bool IsMacSandboxStarted() { return sandbox_check(getpid(), NULL, 0) == 1; }
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// sandbox_check returns 1 if the specified process is sandboxed
|
// 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 */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@
|
||||||
NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService)
|
NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService)
|
||||||
|
|
||||||
nsParentalControlsService::nsParentalControlsService() : mEnabled(false) {
|
nsParentalControlsService::nsParentalControlsService() : mEnabled(false) {
|
||||||
mEnabled = CFPreferencesAppValueIsForced(CFSTR("restrictWeb"),
|
mEnabled = CFPreferencesAppValueIsForced(
|
||||||
CFSTR("com.apple.familycontrols.contentfilter"));
|
CFSTR("restrictWeb"), CFSTR("com.apple.familycontrols.contentfilter"));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsParentalControlsService::~nsParentalControlsService() {}
|
nsParentalControlsService::~nsParentalControlsService() {}
|
||||||
|
|
@ -37,13 +37,14 @@ nsParentalControlsService::GetLoggingEnabled(bool* aResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsParentalControlsService::Log(int16_t aEntryType, bool blocked, nsIURI* aSource,
|
nsParentalControlsService::Log(int16_t aEntryType, bool blocked,
|
||||||
nsIFile* aTarget) {
|
nsIURI* aSource, nsIFile* aTarget) {
|
||||||
// silently drop on the floor
|
// silently drop on the floor
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
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;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ namespace mozilla {
|
||||||
|
|
||||||
nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
||||||
struct proc_taskinfo pti;
|
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) {
|
PROC_PIDTASKINFO_SIZE) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -39,16 +40,16 @@ nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
||||||
mach_timebase_info_data_t timebase;
|
mach_timebase_info_data_t timebase;
|
||||||
GetTimeBase(&timebase);
|
GetTimeBase(&timebase);
|
||||||
|
|
||||||
*aResult = (pti.pti_total_user + pti.pti_total_system) * timebase.numer / timebase.denom /
|
*aResult = (pti.pti_total_user + pti.pti_total_system) * timebase.numer /
|
||||||
PR_NSEC_PER_MSEC;
|
timebase.denom / PR_NSEC_PER_MSEC;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
||||||
task_power_info_v2_data_t task_power_info;
|
task_power_info_v2_data_t task_power_info;
|
||||||
mach_msg_type_number_t count = TASK_POWER_INFO_V2_COUNT;
|
mach_msg_type_number_t count = TASK_POWER_INFO_V2_COUNT;
|
||||||
kern_return_t kr =
|
kern_return_t kr = task_info(mach_task_self(), TASK_POWER_INFO_V2,
|
||||||
task_info(mach_task_self(), TASK_POWER_INFO_V2, (task_info_t)&task_power_info, &count);
|
(task_info_t)&task_power_info, &count);
|
||||||
if (kr != KERN_SUCCESS) {
|
if (kr != KERN_SUCCESS) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +60,8 @@ nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
|
||||||
|
|
||||||
int GetCycleTimeFrequencyMHz() { return 0; }
|
int GetCycleTimeFrequencyMHz() { return 0; }
|
||||||
|
|
||||||
ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&& aRequests) {
|
ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(
|
||||||
|
nsTArray<ProcInfoRequest>&& aRequests) {
|
||||||
ProcInfoPromise::ResolveOrRejectValue result;
|
ProcInfoPromise::ResolveOrRejectValue result;
|
||||||
|
|
||||||
HashMap<base::ProcessId, ProcInfo> gathered;
|
HashMap<base::ProcessId, ProcInfo> gathered;
|
||||||
|
|
@ -81,14 +83,16 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
||||||
info.utilityActors = std::move(request.utilityInfo);
|
info.utilityActors = std::move(request.utilityInfo);
|
||||||
|
|
||||||
struct proc_taskinfo pti;
|
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) {
|
PROC_PIDTASKINFO_SIZE) {
|
||||||
// Can't read data for this process.
|
// Can't read data for this process.
|
||||||
// Probably either a sandboxing issue or a race condition, e.g.
|
// Probably either a sandboxing issue or a race condition, e.g.
|
||||||
// the process has been just been killed. Regardless, skip process.
|
// the process has been just been killed. Regardless, skip process.
|
||||||
continue;
|
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;
|
mach_port_t selectedTask;
|
||||||
// If we did not get a task from a child process, we use mach_task_self()
|
// 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.
|
// matches the value in the 'Memory' column of the Activity Monitor.
|
||||||
task_vm_info_data_t task_vm_info;
|
task_vm_info_data_t task_vm_info;
|
||||||
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
|
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;
|
info.memory = kr == KERN_SUCCESS ? task_vm_info.phys_footprint : 0;
|
||||||
|
|
||||||
// Now getting threads info
|
// Now getting threads info
|
||||||
|
|
@ -123,8 +128,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deallocate the thread list.
|
// Deallocate the thread list.
|
||||||
// Note that this deallocation is entirely undocumented, so the following code is based
|
// Note that this deallocation is entirely undocumented, so the following
|
||||||
// on guesswork and random examples found on the web.
|
// code is based on guesswork and random examples found on the web.
|
||||||
auto guardThreadCount = MakeScopeExit([&] {
|
auto guardThreadCount = MakeScopeExit([&] {
|
||||||
if (threadList == nullptr) {
|
if (threadList == nullptr) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -141,8 +146,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
||||||
// Basic thread info.
|
// Basic thread info.
|
||||||
thread_extended_info_data_t threadInfoData;
|
thread_extended_info_data_t threadInfoData;
|
||||||
count = THREAD_EXTENDED_INFO_COUNT;
|
count = THREAD_EXTENDED_INFO_COUNT;
|
||||||
kret =
|
kret = thread_info(threadList[i], THREAD_EXTENDED_INFO,
|
||||||
thread_info(threadList[i], THREAD_EXTENDED_INFO, (thread_info_t)&threadInfoData, &count);
|
(thread_info_t)&threadInfoData, &count);
|
||||||
if (kret != KERN_SUCCESS) {
|
if (kret != KERN_SUCCESS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -150,8 +155,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
||||||
// Getting the thread id.
|
// Getting the thread id.
|
||||||
thread_identifier_info identifierInfo;
|
thread_identifier_info identifierInfo;
|
||||||
count = THREAD_IDENTIFIER_INFO_COUNT;
|
count = THREAD_IDENTIFIER_INFO_COUNT;
|
||||||
kret = thread_info(threadList[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&identifierInfo,
|
kret = thread_info(threadList[i], THREAD_IDENTIFIER_INFO,
|
||||||
&count);
|
(thread_info_t)&identifierInfo, &count);
|
||||||
if (kret != KERN_SUCCESS) {
|
if (kret != KERN_SUCCESS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -162,7 +167,8 @@ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync(nsTArray<ProcInfoRequest>&
|
||||||
result.SetReject(NS_ERROR_OUT_OF_MEMORY);
|
result.SetReject(NS_ERROR_OUT_OF_MEMORY);
|
||||||
return result;
|
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->name.AssignASCII(threadInfoData.pth_name);
|
||||||
thread->tid = identifierInfo.thread_id;
|
thread->tid = identifierInfo.thread_id;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,21 @@ using namespace mozilla;
|
||||||
|
|
||||||
nsresult nsMacRemoteClient::Init() { return NS_OK; }
|
nsresult nsMacRemoteClient::Init() { return NS_OK; }
|
||||||
|
|
||||||
nsresult nsMacRemoteClient::SendCommandLine(const char* aProgram, const char* aProfile,
|
nsresult nsMacRemoteClient::SendCommandLine(
|
||||||
int32_t argc, char** argv,
|
const char* aProgram, const char* aProfile, int32_t argc, char** argv,
|
||||||
const char* aDesktopStartupID, char** aResponse,
|
const char* aDesktopStartupID, char** aResponse, bool* aSucceeded) {
|
||||||
bool* aSucceeded) {
|
|
||||||
mozilla::MacAutoreleasePool pool;
|
mozilla::MacAutoreleasePool pool;
|
||||||
|
|
||||||
*aSucceeded = false;
|
*aSucceeded = false;
|
||||||
|
|
||||||
nsString className;
|
nsString className;
|
||||||
BuildClassName(aProgram, aProfile, className);
|
BuildClassName(aProgram, aProfile, className);
|
||||||
NSString* serverNameString =
|
NSString* serverNameString = [NSString
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
||||||
length:className.Length()];
|
length:className.Length()];
|
||||||
|
|
||||||
CFMessagePortRef messageServer = CFMessagePortCreateRemote(0, (CFStringRef)serverNameString);
|
CFMessagePortRef messageServer =
|
||||||
|
CFMessagePortCreateRemote(0, (CFStringRef)serverNameString);
|
||||||
|
|
||||||
if (messageServer) {
|
if (messageServer) {
|
||||||
// Getting current process directory
|
// Getting current process directory
|
||||||
|
|
@ -48,7 +48,8 @@ nsresult nsMacRemoteClient::SendCommandLine(const char* aProgram, const char* aP
|
||||||
|
|
||||||
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:dict];
|
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);
|
CFMessagePortInvalidate(messageServer);
|
||||||
CFRelease(messageServer);
|
CFRelease(messageServer);
|
||||||
|
|
|
||||||
|
|
@ -22,20 +22,22 @@
|
||||||
#include "nsXPCOM.h"
|
#include "nsXPCOM.h"
|
||||||
#include "RemoteUtils.h"
|
#include "RemoteUtils.h"
|
||||||
|
|
||||||
CFDataRef messageServerCallback(CFMessagePortRef aLocal, int32_t aMsgid, CFDataRef aData,
|
CFDataRef messageServerCallback(CFMessagePortRef aLocal, int32_t aMsgid,
|
||||||
void* aInfo) {
|
CFDataRef aData, void* aInfo) {
|
||||||
// One of the clients submitted a structure.
|
// One of the clients submitted a structure.
|
||||||
static_cast<nsMacRemoteServer*>(aInfo)->HandleCommandLine(aData);
|
static_cast<nsMacRemoteServer*>(aInfo)->HandleCommandLine(aData);
|
||||||
|
|
||||||
return NULL;
|
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) {
|
void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
|
||||||
mozilla::MacAutoreleasePool pool;
|
mozilla::MacAutoreleasePool pool;
|
||||||
|
|
||||||
if (aData) {
|
if (aData) {
|
||||||
NSDictionary* dict = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData];
|
NSDictionary* dict =
|
||||||
|
[NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData];
|
||||||
if (dict && [dict isKindOfClass:[NSDictionary class]]) {
|
if (dict && [dict isKindOfClass:[NSDictionary class]]) {
|
||||||
NSArray* args = dict[@"args"];
|
NSArray* args = dict[@"args"];
|
||||||
if (!args) {
|
if (!args) {
|
||||||
|
|
@ -54,7 +56,8 @@ void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
|
||||||
argv[i] = arg;
|
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.
|
// Cleaning up C array.
|
||||||
delete[] argv;
|
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.
|
// This is the first instance ever.
|
||||||
// Let's register a notification listener here,
|
// Let's register a notification listener here,
|
||||||
// In case future instances would want to notify us about command line arguments
|
// In case future instances would want to notify us about command line
|
||||||
// passed to them. Note, that if mozilla process is restarting, we still need to
|
// arguments passed to them. Note, that if mozilla process is restarting, we
|
||||||
// register for notifications.
|
// still need to register for notifications.
|
||||||
|
|
||||||
mozilla::MacAutoreleasePool pool;
|
mozilla::MacAutoreleasePool pool;
|
||||||
|
|
||||||
nsString className;
|
nsString className;
|
||||||
BuildClassName(aAppName, aProfileName, className);
|
BuildClassName(aAppName, aProfileName, className);
|
||||||
|
|
||||||
NSString* serverNameString =
|
NSString* serverNameString = [NSString
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
||||||
length:className.Length()];
|
length:className.Length()];
|
||||||
|
|
||||||
CFMessagePortContext context;
|
CFMessagePortContext context;
|
||||||
context.copyDescription = NULL;
|
context.copyDescription = NULL;
|
||||||
|
|
@ -97,8 +101,9 @@ nsresult nsMacRemoteServer::Startup(const char* aAppName, const char* aProfileNa
|
||||||
context.release = NULL;
|
context.release = NULL;
|
||||||
context.retain = NULL;
|
context.retain = NULL;
|
||||||
context.version = NULL;
|
context.version = NULL;
|
||||||
mMessageServer = CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString,
|
mMessageServer =
|
||||||
messageServerCallback, &context, NULL);
|
CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString,
|
||||||
|
messageServerCallback, &context, NULL);
|
||||||
if (!mMessageServer) {
|
if (!mMessageServer) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,8 @@ static bool RestartApplication() {
|
||||||
// Set spawn attributes.
|
// Set spawn attributes.
|
||||||
size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]);
|
size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]);
|
||||||
size_t attr_ocount = 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) {
|
attr_ocount != attr_count) {
|
||||||
posix_spawnattr_destroy(&spawnattr);
|
posix_spawnattr_destroy(&spawnattr);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -89,7 +90,8 @@ static bool RestartApplication() {
|
||||||
gUI = self;
|
gUI = self;
|
||||||
[mWindow center];
|
[mWindow center];
|
||||||
|
|
||||||
[mWindow setTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]];
|
[mWindow setTitle:[[NSBundle mainBundle]
|
||||||
|
objectForInfoDictionaryKey:@"CFBundleName"]];
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +191,9 @@ static bool RestartApplication() {
|
||||||
[self setView:mErrorView animate:NO];
|
[self setView:mErrorView animate:NO];
|
||||||
|
|
||||||
[mErrorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
|
[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 setTitle:Str(ST_OK)];
|
||||||
|
|
||||||
[mErrorCloseButton setKeyEquivalent:@"\r"];
|
[mErrorCloseButton setKeyEquivalent:@"\r"];
|
||||||
|
|
@ -199,19 +203,22 @@ static bool RestartApplication() {
|
||||||
|
|
||||||
- (void)showReportInfo {
|
- (void)showReportInfo {
|
||||||
NSDictionary* boldAttr = @{
|
NSDictionary* boldAttr = @{
|
||||||
NSFontAttributeName : [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]],
|
NSFontAttributeName :
|
||||||
|
[NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]],
|
||||||
NSForegroundColorAttributeName : NSColor.textColor,
|
NSForegroundColorAttributeName : NSColor.textColor,
|
||||||
};
|
};
|
||||||
NSDictionary* normalAttr = @{
|
NSDictionary* normalAttr = @{
|
||||||
NSFontAttributeName : [NSFont systemFontOfSize:[NSFont smallSystemFontSize]],
|
NSFontAttributeName :
|
||||||
|
[NSFont systemFontOfSize:[NSFont smallSystemFontSize]],
|
||||||
NSForegroundColorAttributeName : NSColor.textColor,
|
NSForegroundColorAttributeName : NSColor.textColor,
|
||||||
};
|
};
|
||||||
|
|
||||||
[mViewReportTextView setString:@""];
|
[mViewReportTextView setString:@""];
|
||||||
for (Json::ValueConstIterator iter = gQueryParameters.begin(); iter != gQueryParameters.end();
|
for (Json::ValueConstIterator iter = gQueryParameters.begin();
|
||||||
++iter) {
|
iter != gQueryParameters.end(); ++iter) {
|
||||||
NSAttributedString* key = [[NSAttributedString alloc] initWithString:NSSTR(iter.name() + ": ")
|
NSAttributedString* key =
|
||||||
attributes:boldAttr];
|
[[NSAttributedString alloc] initWithString:NSSTR(iter.name() + ": ")
|
||||||
|
attributes:boldAttr];
|
||||||
string str;
|
string str;
|
||||||
if (iter->isString()) {
|
if (iter->isString()) {
|
||||||
str = iter->asString();
|
str = iter->asString();
|
||||||
|
|
@ -220,24 +227,27 @@ static bool RestartApplication() {
|
||||||
builder["indentation"] = "";
|
builder["indentation"] = "";
|
||||||
str = writeString(builder, *iter);
|
str = writeString(builder, *iter);
|
||||||
}
|
}
|
||||||
NSAttributedString* value = [[NSAttributedString alloc] initWithString:NSSTR(str + "\n")
|
NSAttributedString* value =
|
||||||
attributes:normalAttr];
|
[[NSAttributedString alloc] initWithString:NSSTR(str + "\n")
|
||||||
|
attributes:normalAttr];
|
||||||
[[mViewReportTextView textStorage] appendAttributedString:key];
|
[[mViewReportTextView textStorage] appendAttributedString:key];
|
||||||
[[mViewReportTextView textStorage] appendAttributedString:value];
|
[[mViewReportTextView textStorage] appendAttributedString:value];
|
||||||
[key release];
|
[key release];
|
||||||
[value release];
|
[value release];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSAttributedString* extra =
|
NSAttributedString* extra = [[NSAttributedString alloc]
|
||||||
[[NSAttributedString alloc] initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
|
initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
|
||||||
attributes:normalAttr];
|
attributes:normalAttr];
|
||||||
[[mViewReportTextView textStorage] appendAttributedString:extra];
|
[[mViewReportTextView textStorage] appendAttributedString:extra];
|
||||||
[extra release];
|
[extra release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)maybeSubmitReport {
|
- (void)maybeSubmitReport {
|
||||||
if ([mSubmitReportButton state] == NSOnState) {
|
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
|
// disable all the controls
|
||||||
[self enableControls:NO];
|
[self enableControls:NO];
|
||||||
[mSubmitReportButton setEnabled:NO];
|
[mSubmitReportButton setEnabled:NO];
|
||||||
|
|
@ -258,7 +268,8 @@ static bool RestartApplication() {
|
||||||
- (IBAction)submitReportClicked:(id)sender {
|
- (IBAction)submitReportClicked:(id)sender {
|
||||||
[self updateSubmit];
|
[self updateSubmit];
|
||||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
||||||
[userDefaults setBool:([mSubmitReportButton state] == NSOnState) forKey:@"submitReport"];
|
[userDefaults setBool:([mSubmitReportButton state] == NSOnState)
|
||||||
|
forKey:@"submitReport"];
|
||||||
[userDefaults synchronize];
|
[userDefaults synchronize];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -288,14 +299,16 @@ static bool RestartApplication() {
|
||||||
- (IBAction)includeURLClicked:(id)sender {
|
- (IBAction)includeURLClicked:(id)sender {
|
||||||
[self updateURL];
|
[self updateURL];
|
||||||
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
|
||||||
[userDefaults setBool:([mIncludeURLButton state] == NSOnState) forKey:@"IncludeURL"];
|
[userDefaults setBool:([mIncludeURLButton state] == NSOnState)
|
||||||
|
forKey:@"IncludeURL"];
|
||||||
[userDefaults synchronize];
|
[userDefaults synchronize];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)textDidChange:(NSNotification*)aNotification {
|
- (void)textDidChange:(NSNotification*)aNotification {
|
||||||
// update comment parameter
|
// update comment parameter
|
||||||
if ([[[mCommentText textStorage] mutableString] length] > 0)
|
if ([[[mCommentText textStorage] mutableString] length] > 0)
|
||||||
gQueryParameters["Comments"] = [[[mCommentText textStorage] mutableString] UTF8String];
|
gQueryParameters["Comments"] =
|
||||||
|
[[[mCommentText textStorage] mutableString] UTF8String];
|
||||||
else
|
else
|
||||||
gQueryParameters.removeMember("Comments");
|
gQueryParameters.removeMember("Comments");
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +321,8 @@ static bool RestartApplication() {
|
||||||
if (([[aTextView string] lengthOfBytesUsingEncoding:NSUTF8StringEncoding] +
|
if (([[aTextView string] lengthOfBytesUsingEncoding:NSUTF8StringEncoding] +
|
||||||
[replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] -
|
[replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] -
|
||||||
[[[aTextView string] substringWithRange:affectedCharRange]
|
[[[aTextView string] substringWithRange:affectedCharRange]
|
||||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) > MAX_COMMENT_LENGTH) {
|
lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) >
|
||||||
|
MAX_COMMENT_LENGTH) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
|
|
@ -331,8 +345,8 @@ static bool RestartApplication() {
|
||||||
if (gRestartArgs.size() == 0) {
|
if (gRestartArgs.size() == 0) {
|
||||||
[mRestartButton removeFromSuperview];
|
[mRestartButton removeFromSuperview];
|
||||||
if (!gRTLlayout) {
|
if (!gRTLlayout) {
|
||||||
closeFrame.origin.x =
|
closeFrame.origin.x = restartFrame.origin.x +
|
||||||
restartFrame.origin.x + (restartFrame.size.width - closeFrame.size.width);
|
(restartFrame.size.width - closeFrame.size.width);
|
||||||
} else {
|
} else {
|
||||||
closeFrame.origin.x = restartFrame.origin.x;
|
closeFrame.origin.x = restartFrame.origin.x;
|
||||||
}
|
}
|
||||||
|
|
@ -357,7 +371,8 @@ static bool RestartApplication() {
|
||||||
// possibly resize window if both buttons no longer fit
|
// possibly resize window if both buttons no longer fit
|
||||||
// leave 20 px from either side of the window, and 12 px
|
// leave 20 px from either side of the window, and 12 px
|
||||||
// between the buttons
|
// 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) {
|
if (neededWidth > windowFrame.size.width) {
|
||||||
windowFrame.size.width = neededWidth;
|
windowFrame.size.width = neededWidth;
|
||||||
|
|
@ -379,7 +394,8 @@ static bool RestartApplication() {
|
||||||
[checkbox setFrame:frame];
|
[checkbox setFrame:frame];
|
||||||
}
|
}
|
||||||
// keep existing spacing on left side, + 20 px spare on right
|
// 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) {
|
if (neededWidth > windowFrame.size.width) {
|
||||||
windowFrame.size.width = neededWidth;
|
windowFrame.size.width = neededWidth;
|
||||||
[mWindow setFrame:windowFrame display:true animate:NO];
|
[mWindow setFrame:windowFrame display:true animate:NO];
|
||||||
|
|
@ -395,8 +411,9 @@ static bool RestartApplication() {
|
||||||
// now pin all the controls (except quit/submit) in place,
|
// now pin all the controls (except quit/submit) in place,
|
||||||
// if we lengthen the window after this, it's just to lengthen
|
// if we lengthen the window after this, it's just to lengthen
|
||||||
// the progress text, so nothing above that text should move.
|
// the progress text, so nothing above that text should move.
|
||||||
NSView* views[] = {mSubmitReportButton, mViewReportButton, mCommentScrollView,
|
NSView* views[] = {mSubmitReportButton, mViewReportButton,
|
||||||
mIncludeURLButton, mProgressIndicator, mProgressText};
|
mCommentScrollView, mIncludeURLButton,
|
||||||
|
mProgressIndicator, mProgressText};
|
||||||
for (auto view : views) {
|
for (auto view : views) {
|
||||||
[view setAutoresizingMask:NSViewMinYMargin];
|
[view setAutoresizingMask:NSViewMinYMargin];
|
||||||
}
|
}
|
||||||
|
|
@ -454,7 +471,9 @@ static bool RestartApplication() {
|
||||||
|
|
||||||
- (void)updateSubmit {
|
- (void)updateSubmit {
|
||||||
if ([mSubmitReportButton state] == NSOnState) {
|
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];
|
[mProgressText setHidden:NO];
|
||||||
// enable all the controls
|
// enable all the controls
|
||||||
[self enableControls:YES];
|
[self enableControls:YES];
|
||||||
|
|
@ -490,18 +509,24 @@ static bool RestartApplication() {
|
||||||
[NSApp terminate:self];
|
[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
|
// 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 {
|
- (bool)setupPost {
|
||||||
NSURL* url =
|
NSURL* url = [NSURL
|
||||||
[NSURL URLWithString:[NSSTR(gSendURL)
|
URLWithString:[NSSTR(gSendURL) stringByAddingPercentEscapesUsingEncoding:
|
||||||
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
NSUTF8StringEncoding]];
|
||||||
if (!url) return false;
|
if (!url) return false;
|
||||||
|
|
||||||
mPost = [[HTTPMultipartUpload alloc] initWithURL:url];
|
mPost = [[HTTPMultipartUpload alloc] initWithURL:url];
|
||||||
|
|
@ -514,7 +539,8 @@ static bool RestartApplication() {
|
||||||
Json::StreamWriterBuilder builder;
|
Json::StreamWriterBuilder builder;
|
||||||
builder["indentation"] = "";
|
builder["indentation"] = "";
|
||||||
string output = writeString(builder, gQueryParameters).append("\r\n");
|
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];
|
[mPost setParameters:parameters];
|
||||||
[parameters release];
|
[parameters release];
|
||||||
|
|
@ -535,7 +561,8 @@ static bool RestartApplication() {
|
||||||
// if data is nil, we probably logged an error in uploadThread
|
// if data is nil, we probably logged an error in uploadThread
|
||||||
if (data != nil && response != nil) {
|
if (data != nil && response != nil) {
|
||||||
ostringstream message;
|
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());
|
LogMessage(message.str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -563,9 +590,13 @@ static bool RestartApplication() {
|
||||||
|
|
||||||
[mProgressIndicator stopAnimation:self];
|
[mProgressIndicator stopAnimation:self];
|
||||||
if (success) {
|
if (success) {
|
||||||
[self setStringFitVertically:mProgressText string:Str(ST_REPORTSUBMITSUCCESS) resizeWindow:YES];
|
[self setStringFitVertically:mProgressText
|
||||||
|
string:Str(ST_REPORTSUBMITSUCCESS)
|
||||||
|
resizeWindow:YES];
|
||||||
} else {
|
} else {
|
||||||
[self setStringFitVertically:mProgressText string:Str(ST_SUBMITFAILED) resizeWindow:YES];
|
[self setStringFitVertically:mProgressText
|
||||||
|
string:Str(ST_SUBMITFAILED)
|
||||||
|
resizeWindow:YES];
|
||||||
}
|
}
|
||||||
// quit after 5 seconds
|
// quit after 5 seconds
|
||||||
[self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0];
|
[self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0];
|
||||||
|
|
@ -582,13 +613,16 @@ static bool RestartApplication() {
|
||||||
LogMessage("Crash report submission failed: " + message);
|
LogMessage("Crash report submission failed: " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
[self performSelectorOnMainThread:@selector(uploadComplete:) withObject:data waitUntilDone:YES];
|
[self performSelectorOnMainThread:@selector(uploadComplete:)
|
||||||
|
withObject:data
|
||||||
|
waitUntilDone:YES];
|
||||||
|
|
||||||
[autoreleasepool release];
|
[autoreleasepool release];
|
||||||
}
|
}
|
||||||
|
|
||||||
// to get auto-quit when we close the window
|
// to get auto-quit when we close the window
|
||||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication {
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:
|
||||||
|
(NSApplication*)theApplication {
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -621,10 +655,12 @@ static bool RestartApplication() {
|
||||||
|
|
||||||
- (void)setPlaceholder:(NSString*)placeholder {
|
- (void)setPlaceholder:(NSString*)placeholder {
|
||||||
NSColor* txtColor = [NSColor disabledControlTextColor];
|
NSColor* txtColor = [NSColor disabledControlTextColor];
|
||||||
NSDictionary* txtDict =
|
NSDictionary* txtDict = [NSDictionary
|
||||||
[NSDictionary dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, nil];
|
dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName,
|
||||||
mPlaceHolderString = [[NSMutableAttributedString alloc] initWithString:placeholder
|
nil];
|
||||||
attributes:txtDict];
|
mPlaceHolderString =
|
||||||
|
[[NSMutableAttributedString alloc] initWithString:placeholder
|
||||||
|
attributes:txtDict];
|
||||||
if (gRTLlayout)
|
if (gRTLlayout)
|
||||||
[mPlaceHolderString setAlignment:NSTextAlignmentRight
|
[mPlaceHolderString setAlignment:NSTextAlignmentRight
|
||||||
range:NSMakeRange(0, [placeholder length])];
|
range:NSMakeRange(0, [placeholder length])];
|
||||||
|
|
@ -649,9 +685,11 @@ static bool RestartApplication() {
|
||||||
txtColor = [NSColor textColor];
|
txtColor = [NSColor textColor];
|
||||||
else
|
else
|
||||||
txtColor = [NSColor disabledControlTextColor];
|
txtColor = [NSColor disabledControlTextColor];
|
||||||
NSDictionary* txtDict =
|
NSDictionary* txtDict = [NSDictionary
|
||||||
[NSDictionary dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, nil];
|
dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName,
|
||||||
colorString = [[NSAttributedString alloc] initWithString:[self string] attributes:txtDict];
|
nil];
|
||||||
|
colorString = [[NSAttributedString alloc] initWithString:[self string]
|
||||||
|
attributes:txtDict];
|
||||||
[[self textStorage] setAttributedString:colorString];
|
[[self textStorage] setAttributedString:colorString];
|
||||||
[self setInsertionPointColor:txtColor];
|
[self setInsertionPointColor:txtColor];
|
||||||
[colorString release];
|
[colorString release];
|
||||||
|
|
@ -671,14 +709,16 @@ bool UIInit() {
|
||||||
gMainPool = [[NSAutoreleasePool alloc] init];
|
gMainPool = [[NSAutoreleasePool alloc] init];
|
||||||
[NSApplication sharedApplication];
|
[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) {
|
if (gAutoSubmit) {
|
||||||
gUI = [[CrashReporterUI alloc] init];
|
gUI = [[CrashReporterUI alloc] init];
|
||||||
} else {
|
} else {
|
||||||
[[NSBundle mainBundle] loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
|
[[NSBundle mainBundle]
|
||||||
owner:NSApp
|
loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu")
|
||||||
topLevelObjects:nil];
|
owner:NSApp
|
||||||
|
topLevelObjects:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -724,9 +764,10 @@ bool UIGetIniPath(string& path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UIGetSettingsPath(const string& vendor, const string& product, string& settingsPath) {
|
bool UIGetSettingsPath(const string& vendor, const string& product,
|
||||||
NSArray* paths =
|
string& settingsPath) {
|
||||||
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
NSArray* paths = NSSearchPathForDirectoriesInDomains(
|
||||||
|
NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||||
NSString* destPath = [paths firstObject];
|
NSString* destPath = [paths firstObject];
|
||||||
|
|
||||||
// Note that MacOS ignores the vendor when creating the profile hierarchy -
|
// 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;
|
if (errno != EXDEV) return false;
|
||||||
|
|
||||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
NSString* source = [fileManager stringWithFileSystemRepresentation:file.c_str()
|
NSString* source =
|
||||||
length:file.length()];
|
[fileManager stringWithFileSystemRepresentation:file.c_str()
|
||||||
NSString* dest = [fileManager stringWithFileSystemRepresentation:newfile.c_str()
|
length:file.length()];
|
||||||
length:newfile.length()];
|
NSString* dest =
|
||||||
|
[fileManager stringWithFileSystemRepresentation:newfile.c_str()
|
||||||
|
length:newfile.length()];
|
||||||
if (!source || !dest) return false;
|
if (!source || !dest) return false;
|
||||||
|
|
||||||
[fileManager moveItemAtPath:source toPath:dest error:NULL];
|
[fileManager moveItemAtPath:source toPath:dest error:NULL];
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,8 @@ bool IsBinaryArmExecutable(const char* executablePath) {
|
||||||
bool isArmExecutable = false;
|
bool isArmExecutable = false;
|
||||||
|
|
||||||
CFURLRef url = ::CFURLCreateFromFileSystemRepresentation(
|
CFURLRef url = ::CFURLCreateFromFileSystemRepresentation(
|
||||||
kCFAllocatorDefault, (const UInt8*)executablePath, strlen(executablePath), false);
|
kCFAllocatorDefault, (const UInt8*)executablePath, strlen(executablePath),
|
||||||
|
false);
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +69,8 @@ bool IsBinaryArmExecutable(const char* executablePath) {
|
||||||
|
|
||||||
CFIndex archCount = ::CFArrayGetCount(archs);
|
CFIndex archCount = ::CFArrayGetCount(archs);
|
||||||
for (CFIndex i = 0; i < archCount; i++) {
|
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;
|
int currentArchInt = 0;
|
||||||
if (!::CFNumberGetValue(currentArch, kCFNumberIntType, ¤tArchInt)) {
|
if (!::CFNumberGetValue(currentArch, kCFNumberIntType, ¤tArchInt)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -161,7 +163,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
|
||||||
// Launch helper to perform post processing for the update; this is the Mac
|
// Launch helper to perform post processing for the update; this is the Mac
|
||||||
// analogue of LaunchWinPostProcess (PostUpdateWin).
|
// analogue of LaunchWinPostProcess (PostUpdateWin).
|
||||||
NSString* iniPath = [NSString stringWithUTF8String:aAppBundle];
|
NSString* iniPath = [NSString stringWithUTF8String:aAppBundle];
|
||||||
iniPath = [iniPath stringByAppendingPathComponent:@"Contents/Resources/updater.ini"];
|
iniPath = [iniPath
|
||||||
|
stringByAppendingPathComponent:@"Contents/Resources/updater.ini"];
|
||||||
|
|
||||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
if (![fileManager fileExistsAtPath:iniPath]) {
|
if (![fileManager fileExistsAtPath:iniPath]) {
|
||||||
|
|
@ -171,8 +174,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
|
||||||
|
|
||||||
int readResult;
|
int readResult;
|
||||||
mozilla::UniquePtr<char[]> values[2];
|
mozilla::UniquePtr<char[]> values[2];
|
||||||
readResult =
|
readResult = ReadStrings([iniPath UTF8String], "ExeRelPath\0ExeArg\0", 2,
|
||||||
ReadStrings([iniPath UTF8String], "ExeRelPath\0ExeArg\0", 2, values, "PostUpdateMac");
|
values, "PostUpdateMac");
|
||||||
if (readResult) {
|
if (readResult) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +197,8 @@ void LaunchMacPostProcess(const char* aAppBundle) {
|
||||||
exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath];
|
exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath];
|
||||||
|
|
||||||
mozilla::UniquePtr<char[]> optVal;
|
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];
|
NSTask* task = [[NSTask alloc] init];
|
||||||
[task setLaunchPath:exeFullPath];
|
[task setLaunchPath:exeFullPath];
|
||||||
|
|
@ -223,8 +227,10 @@ id ConnectToUpdateServer() {
|
||||||
updateServer = (id)[NSConnection
|
updateServer = (id)[NSConnection
|
||||||
rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server"
|
rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server"
|
||||||
host:nil
|
host:nil
|
||||||
usingNameServer:[NSSocketPortNameServer sharedInstance]];
|
usingNameServer:[NSSocketPortNameServer
|
||||||
if (!updateServer || ![updateServer respondsToSelector:@selector(abort)] ||
|
sharedInstance]];
|
||||||
|
if (!updateServer ||
|
||||||
|
![updateServer respondsToSelector:@selector(abort)] ||
|
||||||
![updateServer respondsToSelector:@selector(getArguments)] ||
|
![updateServer respondsToSelector:@selector(getArguments)] ||
|
||||||
![updateServer respondsToSelector:@selector(shutdown)]) {
|
![updateServer respondsToSelector:@selector(shutdown)]) {
|
||||||
NSLog(@"Server doesn't exist or doesn't provide correct selectors.");
|
NSLog(@"Server doesn't exist or doesn't provide correct selectors.");
|
||||||
|
|
@ -262,9 +268,13 @@ void CleanupElevatedMacUpdate(bool aFailureOccurred) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NSFileManager* manager = [NSFileManager defaultManager];
|
NSFileManager* manager = [NSFileManager defaultManager];
|
||||||
[manager removeItemAtPath:@"/Library/PrivilegedHelperTools/org.mozilla.updater" error:nil];
|
[manager
|
||||||
[manager removeItemAtPath:@"/Library/LaunchDaemons/org.mozilla.updater.plist" error:nil];
|
removeItemAtPath:@"/Library/PrivilegedHelperTools/org.mozilla.updater"
|
||||||
const char* launchctlArgs[] = {"/bin/launchctl", "remove", "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"
|
// The following call will terminate the current process due to the "remove"
|
||||||
// argument in launchctlArgs.
|
// argument in launchctlArgs.
|
||||||
LaunchChild(3, launchctlArgs);
|
LaunchChild(3, launchctlArgs);
|
||||||
|
|
@ -282,13 +292,15 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
NSArray* updaterArguments = [updateServer performSelector:@selector(getArguments)];
|
NSArray* updaterArguments =
|
||||||
|
[updateServer performSelector:@selector(getArguments)];
|
||||||
*argc = [updaterArguments count];
|
*argc = [updaterArguments count];
|
||||||
char** tempArgv = (char**)malloc(sizeof(char*) * (*argc));
|
char** tempArgv = (char**)malloc(sizeof(char*) * (*argc));
|
||||||
for (int i = 0; i < *argc; i++) {
|
for (int i = 0; i < *argc; i++) {
|
||||||
int argLen = [[updaterArguments objectAtIndex:i] length] + 1;
|
int argLen = [[updaterArguments objectAtIndex:i] length] + 1;
|
||||||
tempArgv[i] = (char*)malloc(argLen);
|
tempArgv[i] = (char*)malloc(argLen);
|
||||||
strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String], argLen);
|
strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String],
|
||||||
|
argLen);
|
||||||
}
|
}
|
||||||
*argv = tempArgv;
|
*argv = tempArgv;
|
||||||
} @catch (NSException* e) {
|
} @catch (NSException* e) {
|
||||||
|
|
@ -334,7 +346,8 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
|
||||||
|
|
||||||
- (BOOL)runServer {
|
- (BOOL)runServer {
|
||||||
NSPort* serverPort = [NSSocketPort port];
|
NSPort* serverPort = [NSSocketPort port];
|
||||||
NSConnection* server = [NSConnection connectionWithReceivePort:serverPort sendPort:serverPort];
|
NSConnection* server = [NSConnection connectionWithReceivePort:serverPort
|
||||||
|
sendPort:serverPort];
|
||||||
[server setRootObject:self];
|
[server setRootObject:self];
|
||||||
if ([server registerName:@"org.mozilla.updater.server"
|
if ([server registerName:@"org.mozilla.updater.server"
|
||||||
withNameServer:[NSSocketPortNameServer sharedInstance]] == NO) {
|
withNameServer:[NSSocketPortNameServer sharedInstance]] == NO) {
|
||||||
|
|
@ -343,8 +356,9 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ([self shouldKeepRunning] && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
while ([self shouldKeepRunning] &&
|
||||||
beforeDate:[NSDate distantFuture]])
|
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||||
|
beforeDate:[NSDate distantFuture]])
|
||||||
;
|
;
|
||||||
return ![self wasAborted];
|
return ![self wasAborted];
|
||||||
}
|
}
|
||||||
|
|
@ -394,9 +408,11 @@ bool IsOwnedByGroupAdmin(const char* aAppBundle) {
|
||||||
NSString* appDir = [NSString stringWithUTF8String:aAppBundle];
|
NSString* appDir = [NSString stringWithUTF8String:aAppBundle];
|
||||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
|
|
||||||
NSDictionary* attributes = [fileManager attributesOfItemAtPath:appDir error:nil];
|
NSDictionary* attributes = [fileManager attributesOfItemAtPath:appDir
|
||||||
|
error:nil];
|
||||||
bool isOwnedByAdmin = false;
|
bool isOwnedByAdmin = false;
|
||||||
if (attributes && [[attributes valueForKey:NSFileGroupOwnerAccountID] intValue] == 80) {
|
if (attributes &&
|
||||||
|
[[attributes valueForKey:NSFileGroupOwnerAccountID] intValue] == 80) {
|
||||||
isOwnedByAdmin = true;
|
isOwnedByAdmin = true;
|
||||||
}
|
}
|
||||||
return isOwnedByAdmin;
|
return isOwnedByAdmin;
|
||||||
|
|
@ -425,13 +441,14 @@ void SetGroupOwnershipAndPermissions(const char* aAppBundle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSArray* permKeys =
|
NSArray* permKeys = [NSArray
|
||||||
[NSArray arrayWithObjects:NSFileGroupOwnerAccountID, NSFilePosixPermissions, nil];
|
arrayWithObjects:NSFileGroupOwnerAccountID, NSFilePosixPermissions, nil];
|
||||||
// For all descendants of Firefox.app, set group ownership to 80 ("admin") and
|
// For all descendants of Firefox.app, set group ownership to 80 ("admin") and
|
||||||
// ensure write permission for the group.
|
// ensure write permission for the group.
|
||||||
for (NSString* currPath in paths) {
|
for (NSString* currPath in paths) {
|
||||||
NSString* child = [appDir stringByAppendingPathComponent:currPath];
|
NSString* child = [appDir stringByAppendingPathComponent:currPath];
|
||||||
NSDictionary* oldAttributes = [fileManager attributesOfItemAtPath:child error:&error];
|
NSDictionary* oldAttributes = [fileManager attributesOfItemAtPath:child
|
||||||
|
error:&error];
|
||||||
if (error) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -440,12 +457,20 @@ void SetGroupOwnershipAndPermissions(const char* aAppBundle) {
|
||||||
if ([oldAttributes fileType] == NSFileTypeSymbolicLink) {
|
if ([oldAttributes fileType] == NSFileTypeSymbolicLink) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NSNumber* oldPerms = (NSNumber*)[oldAttributes valueForKey:NSFilePosixPermissions];
|
NSNumber* oldPerms =
|
||||||
|
(NSNumber*)[oldAttributes valueForKey:NSFilePosixPermissions];
|
||||||
NSArray* permObjects = [NSArray
|
NSArray* permObjects = [NSArray
|
||||||
arrayWithObjects:[NSNumber numberWithUnsignedLong:80],
|
arrayWithObjects:[NSNumber numberWithUnsignedLong:80],
|
||||||
[NSNumber numberWithUnsignedLong:[oldPerms shortValue] | 020], nil];
|
[NSNumber
|
||||||
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:permObjects forKeys:permKeys];
|
numberWithUnsignedLong:[oldPerms shortValue] |
|
||||||
if (![fileManager setAttributes:attributes ofItemAtPath:child error:&error] || error) {
|
020],
|
||||||
|
nil];
|
||||||
|
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:permObjects
|
||||||
|
forKeys:permKeys];
|
||||||
|
if (![fileManager setAttributes:attributes
|
||||||
|
ofItemAtPath:child
|
||||||
|
error:&error] ||
|
||||||
|
error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -483,7 +508,9 @@ bool PerformInstallationFromDMG(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
NSString* bundlePath = [NSString stringWithUTF8String:argv[2]];
|
NSString* bundlePath = [NSString stringWithUTF8String:argv[2]];
|
||||||
NSString* destPath = [NSString stringWithUTF8String:argv[3]];
|
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);
|
RegisterAppWithLaunchServices(destPath);
|
||||||
StripQuarantineBit(destPath);
|
StripQuarantineBit(destPath);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,14 @@ static const char* sUpdatePath;
|
||||||
NSWindow* w = [progressBar window];
|
NSWindow* w = [progressBar window];
|
||||||
|
|
||||||
[w setTitle:[NSString stringWithUTF8String:sLabels.title.get()]];
|
[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];
|
NSRect origTextFrame = [progressTextField frame];
|
||||||
[progressTextField sizeToFit];
|
[progressTextField sizeToFit];
|
||||||
|
|
||||||
int widthAdjust = progressTextField.frame.size.width - origTextFrame.size.width;
|
int widthAdjust =
|
||||||
|
progressTextField.frame.size.width - origTextFrame.size.width;
|
||||||
|
|
||||||
if (widthAdjust > 0) {
|
if (widthAdjust > 0) {
|
||||||
NSRect f;
|
NSRect f;
|
||||||
|
|
@ -118,7 +120,9 @@ int ShowProgressUI(bool indeterminate) {
|
||||||
|
|
||||||
sIndeterminate = indeterminate;
|
sIndeterminate = indeterminate;
|
||||||
[NSApplication sharedApplication];
|
[NSApplication sharedApplication];
|
||||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:nil];
|
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
|
||||||
|
owner:NSApp
|
||||||
|
topLevelObjects:nil];
|
||||||
[NSApp run];
|
[NSApp run];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ class nsOSXSystemProxySettings : public nsISystemProxySettings {
|
||||||
nsresult GetAutoconfigURL(nsAutoCString& aResult) const;
|
nsresult GetAutoconfigURL(nsAutoCString& aResult) const;
|
||||||
|
|
||||||
// Find the SystemConfiguration proxy & port for a given URI
|
// Find the SystemConfiguration proxy & port for a given URI
|
||||||
nsresult FindSCProxyPort(const nsACString& aScheme, nsACString& aResultHost, int32_t& aResultPort,
|
nsresult FindSCProxyPort(const nsACString& aScheme, nsACString& aResultHost,
|
||||||
bool& aResultSocksProxy);
|
int32_t& aResultPort, bool& aResultSocksProxy);
|
||||||
|
|
||||||
// is host:port on the proxy exception list?
|
// is host:port on the proxy exception list?
|
||||||
bool IsInExceptionList(const nsACString& aHost) const;
|
bool IsInExceptionList(const nsACString& aHost) const;
|
||||||
|
|
@ -69,22 +69,26 @@ nsOSXSystemProxySettings::GetMainThreadOnly(bool* aMainThreadOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mapping of URI schemes to SystemConfiguration keys
|
// Mapping of URI schemes to SystemConfiguration keys
|
||||||
const nsOSXSystemProxySettings::SchemeMapping nsOSXSystemProxySettings::gSchemeMappingList[] = {
|
const nsOSXSystemProxySettings::SchemeMapping
|
||||||
{"http", kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort,
|
nsOSXSystemProxySettings::gSchemeMappingList[] = {
|
||||||
false},
|
{"http", kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy,
|
||||||
{"https", kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort,
|
kSCPropNetProxiesHTTPPort, false},
|
||||||
false},
|
{"https", kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy,
|
||||||
{"ftp", kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy, kSCPropNetProxiesFTPPort, false},
|
kSCPropNetProxiesHTTPSPort, false},
|
||||||
{"socks", kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort,
|
{"ftp", kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy,
|
||||||
true},
|
kSCPropNetProxiesFTPPort, false},
|
||||||
{NULL, NULL, NULL, NULL, 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();
|
static_cast<nsOSXSystemProxySettings*>(aInfo)->ProxyHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsOSXSystemProxySettings::nsOSXSystemProxySettings() : mSystemDynamicStore(NULL), mProxyDict(NULL) {
|
nsOSXSystemProxySettings::nsOSXSystemProxySettings()
|
||||||
|
: mSystemDynamicStore(NULL), mProxyDict(NULL) {
|
||||||
mContext = (SCDynamicStoreContext){0, this, NULL, NULL, NULL};
|
mContext = (SCDynamicStoreContext){0, this, NULL, NULL, NULL};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,15 +98,16 @@ nsresult nsOSXSystemProxySettings::Init() {
|
||||||
// Register for notification of proxy setting changes
|
// Register for notification of proxy setting changes
|
||||||
// See:
|
// See:
|
||||||
// http://developer.apple.com/documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/chapter_4_section_5.html
|
// http://developer.apple.com/documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/chapter_4_section_5.html
|
||||||
mSystemDynamicStore =
|
mSystemDynamicStore = SCDynamicStoreCreate(NULL, CFSTR("Mozilla"),
|
||||||
SCDynamicStoreCreate(NULL, CFSTR("Mozilla"), ProxyHasChangedWrapper, &mContext);
|
ProxyHasChangedWrapper, &mContext);
|
||||||
if (!mSystemDynamicStore) return NS_ERROR_FAILURE;
|
if (!mSystemDynamicStore) return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
// Set up the store to monitor any changes to the proxies
|
// Set up the store to monitor any changes to the proxies
|
||||||
CFStringRef proxiesKey = SCDynamicStoreKeyCreateProxies(NULL);
|
CFStringRef proxiesKey = SCDynamicStoreKeyCreateProxies(NULL);
|
||||||
if (!proxiesKey) return NS_ERROR_FAILURE;
|
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);
|
CFRelease(proxiesKey);
|
||||||
if (!keyArray) return NS_ERROR_FAILURE;
|
if (!keyArray) return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
|
@ -113,7 +118,8 @@ nsresult nsOSXSystemProxySettings::Init() {
|
||||||
CFRunLoopSourceRef storeRLSource =
|
CFRunLoopSourceRef storeRLSource =
|
||||||
SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
|
SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
|
||||||
if (!storeRLSource) return NS_ERROR_FAILURE;
|
if (!storeRLSource) return NS_ERROR_FAILURE;
|
||||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLSource, kCFRunLoopCommonModes);
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLSource,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
CFRelease(storeRLSource);
|
CFRelease(storeRLSource);
|
||||||
|
|
||||||
// Load the initial copy of proxy info
|
// Load the initial copy of proxy info
|
||||||
|
|
@ -135,7 +141,8 @@ nsOSXSystemProxySettings::~nsOSXSystemProxySettings() {
|
||||||
if (mSystemDynamicStore) {
|
if (mSystemDynamicStore) {
|
||||||
// Invalidate the dynamic store's run loop source
|
// Invalidate the dynamic store's run loop source
|
||||||
// to get the store out of the run loop
|
// to get the store out of the run loop
|
||||||
CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
|
CFRunLoopSourceRef rls =
|
||||||
|
SCDynamicStoreCreateRunLoopSource(NULL, mSystemDynamicStore, 0);
|
||||||
if (rls) {
|
if (rls) {
|
||||||
CFRunLoopSourceInvalidate(rls);
|
CFRunLoopSourceInvalidate(rls);
|
||||||
CFRelease(rls);
|
CFRelease(rls);
|
||||||
|
|
@ -158,20 +165,24 @@ void nsOSXSystemProxySettings::ProxyHasChanged() {
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsOSXSystemProxySettings::FindSCProxyPort(const nsACString& aScheme,
|
nsresult nsOSXSystemProxySettings::FindSCProxyPort(const nsACString& aScheme,
|
||||||
nsACString& aResultHost, int32_t& aResultPort,
|
nsACString& aResultHost,
|
||||||
|
int32_t& aResultPort,
|
||||||
bool& aResultSocksProxy) {
|
bool& aResultSocksProxy) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NS_ENSURE_TRUE(mProxyDict != NULL, NS_ERROR_FAILURE);
|
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)
|
// 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;
|
continue;
|
||||||
|
|
||||||
// Check the proxy is enabled
|
// Check the proxy is enabled
|
||||||
NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled];
|
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;
|
if ([enabled intValue] == 0) continue;
|
||||||
|
|
||||||
// Get the proxy host
|
// Get the proxy host
|
||||||
|
|
@ -198,17 +209,21 @@ nsresult nsOSXSystemProxySettings::FindSCProxyPort(const nsACString& aScheme,
|
||||||
bool nsOSXSystemProxySettings::IsAutoconfigEnabled() const {
|
bool nsOSXSystemProxySettings::IsAutoconfigEnabled() const {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NSNumber* value = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigEnable];
|
NSNumber* value = [mProxyDict
|
||||||
NS_ENSURE_TRUE(value == NULL || [value isKindOfClass:[NSNumber class]], false);
|
objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigEnable];
|
||||||
|
NS_ENSURE_TRUE(value == NULL || [value isKindOfClass:[NSNumber class]],
|
||||||
|
false);
|
||||||
return ([value intValue] != 0);
|
return ([value intValue] != 0);
|
||||||
|
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(false);
|
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;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NSString* value = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigURLString];
|
NSString* value = [mProxyDict
|
||||||
|
objectForKey:(NSString*)kSCPropNetProxiesProxyAutoConfigURLString];
|
||||||
if (value != NULL) {
|
if (value != NULL) {
|
||||||
NS_ENSURE_TRUE([value isKindOfClass:[NSString class]], NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE([value isKindOfClass:[NSString class]], NS_ERROR_FAILURE);
|
||||||
aResult.Assign([value UTF8String]);
|
aResult.Assign([value UTF8String]);
|
||||||
|
|
@ -220,20 +235,25 @@ nsresult nsOSXSystemProxySettings::GetAutoconfigURL(nsAutoCString& aResult) cons
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
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_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NS_ENSURE_TRUE(mProxyDict != NULL, false);
|
NS_ENSURE_TRUE(mProxyDict != NULL, false);
|
||||||
|
|
||||||
NSArray* exceptionList = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
|
NSArray* exceptionList =
|
||||||
NS_ENSURE_TRUE(exceptionList == NULL || [exceptionList isKindOfClass:[NSArray class]], false);
|
[mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
|
||||||
|
NS_ENSURE_TRUE(
|
||||||
|
exceptionList == NULL || [exceptionList isKindOfClass:[NSArray class]],
|
||||||
|
false);
|
||||||
|
|
||||||
NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator];
|
NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator];
|
||||||
NSString* currentValue = NULL;
|
NSString* currentValue = NULL;
|
||||||
while ((currentValue = [exceptionEnumerator nextObject])) {
|
while ((currentValue = [exceptionEnumerator nextObject])) {
|
||||||
NS_ENSURE_TRUE([currentValue isKindOfClass:[NSString class]], false);
|
NS_ENSURE_TRUE([currentValue isKindOfClass:[NSString class]], false);
|
||||||
nsAutoCString overrideStr([currentValue UTF8String]);
|
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);
|
NS_OBJC_END_TRY_BLOCK_RETURN(false);
|
||||||
|
|
@ -257,7 +277,8 @@ nsresult nsOSXSystemProxySettings::GetPACURI(nsACString& aResult) {
|
||||||
|
|
||||||
nsresult nsOSXSystemProxySettings::GetProxyForURI(const nsACString& aSpec,
|
nsresult nsOSXSystemProxySettings::GetProxyForURI(const nsACString& aSpec,
|
||||||
const nsACString& aScheme,
|
const nsACString& aScheme,
|
||||||
const nsACString& aHost, const int32_t aPort,
|
const nsACString& aHost,
|
||||||
|
const int32_t aPort,
|
||||||
nsACString& aResult) {
|
nsACString& aResult) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
|
|
@ -283,7 +304,8 @@ using namespace mozilla::net;
|
||||||
|
|
||||||
class OSXSystemProxySettingsAsync final : public nsOSXSystemProxySettings {
|
class OSXSystemProxySettingsAsync final : public nsOSXSystemProxySettings {
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_REFCOUNTING_INHERITED(OSXSystemProxySettingsAsync, nsOSXSystemProxySettings)
|
NS_INLINE_DECL_REFCOUNTING_INHERITED(OSXSystemProxySettingsAsync,
|
||||||
|
nsOSXSystemProxySettings)
|
||||||
NS_DECL_NSISYSTEMPROXYSETTINGS
|
NS_DECL_NSISYSTEMPROXYSETTINGS
|
||||||
|
|
||||||
OSXSystemProxySettingsAsync();
|
OSXSystemProxySettingsAsync();
|
||||||
|
|
@ -314,7 +336,8 @@ void OSXSystemProxySettingsAsync::OnProxyConfigChangedInternal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxies (for now: PROXY and SOCKS)
|
// 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
|
// Check the proxy is enabled
|
||||||
NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled];
|
NSNumber* enabled = [mProxyDict objectForKey:(NSString*)keys->mEnabled];
|
||||||
if (!(enabled == NULL || [enabled isKindOfClass:[NSNumber class]])) {
|
if (!(enabled == NULL || [enabled isKindOfClass:[NSNumber class]])) {
|
||||||
|
|
@ -342,17 +365,20 @@ void OSXSystemProxySettingsAsync::OnProxyConfigChangedInternal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t resultPort = [port intValue];
|
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);
|
config.Rules().mProxyServers[server.Type()] = std::move(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
// exceptions
|
// exceptions
|
||||||
NSArray* exceptionList = [mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
|
NSArray* exceptionList =
|
||||||
|
[mProxyDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList];
|
||||||
if (exceptionList != NULL && [exceptionList isKindOfClass:[NSArray class]]) {
|
if (exceptionList != NULL && [exceptionList isKindOfClass:[NSArray class]]) {
|
||||||
NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator];
|
NSEnumerator* exceptionEnumerator = [exceptionList objectEnumerator];
|
||||||
NSString* currentValue = NULL;
|
NSString* currentValue = NULL;
|
||||||
while ((currentValue = [exceptionEnumerator nextObject])) {
|
while ((currentValue = [exceptionEnumerator nextObject])) {
|
||||||
if (currentValue != NULL && [currentValue isKindOfClass:[NSString class]]) {
|
if (currentValue != NULL &&
|
||||||
|
[currentValue isKindOfClass:[NSString class]]) {
|
||||||
nsCString overrideStr([currentValue UTF8String]);
|
nsCString overrideStr([currentValue UTF8String]);
|
||||||
config.ByPassRules().mExceptions.AppendElement(std::move(overrideStr));
|
config.ByPassRules().mExceptions.AppendElement(std::move(overrideStr));
|
||||||
}
|
}
|
||||||
|
|
@ -374,8 +400,10 @@ OSXSystemProxySettingsAsync::GetPACURI(nsACString& aResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec, const nsACString& aScheme,
|
OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec,
|
||||||
const nsACString& aHost, const int32_t aPort,
|
const nsACString& aScheme,
|
||||||
|
const nsACString& aHost,
|
||||||
|
const int32_t aPort,
|
||||||
nsACString& aResult) {
|
nsACString& aResult) {
|
||||||
for (const auto& bypassRule : mConfig.ByPassRules().mExceptions) {
|
for (const auto& bypassRule : mConfig.ByPassRules().mExceptions) {
|
||||||
if (mozilla::toolkit::system::IsHostProxyEntry(aHost, bypassRule)) {
|
if (mozilla::toolkit::system::IsHostProxyEntry(aHost, bypassRule)) {
|
||||||
|
|
@ -389,9 +417,10 @@ OSXSystemProxySettingsAsync::GetProxyForURI(const nsACString& aSpec, const nsACS
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_COMPONENT_FACTORY(nsOSXSystemProxySettings) {
|
NS_IMPL_COMPONENT_FACTORY(nsOSXSystemProxySettings) {
|
||||||
auto settings = mozilla::StaticPrefs::network_proxy_detect_system_proxy_changes()
|
auto settings =
|
||||||
? mozilla::MakeRefPtr<OSXSystemProxySettingsAsync>()
|
mozilla::StaticPrefs::network_proxy_detect_system_proxy_changes()
|
||||||
: mozilla::MakeRefPtr<nsOSXSystemProxySettings>();
|
? mozilla::MakeRefPtr<OSXSystemProxySettingsAsync>()
|
||||||
|
: mozilla::MakeRefPtr<nsOSXSystemProxySettings>();
|
||||||
if (NS_SUCCEEDED(settings->Init())) {
|
if (NS_SUCCEEDED(settings->Init())) {
|
||||||
return settings.forget().downcast<nsISupports>();
|
return settings.forget().downcast<nsISupports>();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
// NSApplication delegate for Mac OS X Cocoa API.
|
// 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;
|
// As of 10.4 Tiger, the system can send six kinds of Apple Events to an
|
||||||
// a well-behaved XUL app should have some kind of handling for all of them.
|
// application; a well-behaved XUL app should have some kind of handling for all
|
||||||
|
// of them.
|
||||||
//
|
//
|
||||||
// See
|
// See
|
||||||
// http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/SApps_handle_AEs/chapter_11_section_3.html
|
// 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
|
// 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
|
// 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.
|
// 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.
|
// Create the delegate. This should be around for the lifetime of the app.
|
||||||
id<NSApplicationDelegate> delegate = [[MacApplicationDelegate alloc] init];
|
id<NSApplicationDelegate> delegate = [[MacApplicationDelegate alloc] init];
|
||||||
|
|
@ -164,9 +167,11 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
NSAppleEventManager* aeMgr = [NSAppleEventManager sharedAppleEventManager];
|
NSAppleEventManager* aeMgr = [NSAppleEventManager sharedAppleEventManager];
|
||||||
[aeMgr removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
|
[aeMgr removeEventHandlerForEventClass:kInternetEventClass
|
||||||
|
andEventID:kAEGetURL];
|
||||||
[aeMgr removeEventHandlerForEventClass:'WWW!' andEventID:'OURL'];
|
[aeMgr removeEventHandlerForEventClass:'WWW!' andEventID:'OURL'];
|
||||||
[aeMgr removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
|
[aeMgr removeEventHandlerForEventClass:kCoreEventClass
|
||||||
|
andEventID:kAEOpenDocuments];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
|
|
||||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
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 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
|
// 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'.
|
// 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();
|
nsCOMPtr<nsINativeAppSupport> nas = NS_GetNativeAppSupport();
|
||||||
NS_ENSURE_TRUE(nas, NO);
|
NS_ENSURE_TRUE(nas, NO);
|
||||||
|
|
||||||
|
|
@ -187,9 +193,10 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The method that NSApplication calls when documents are requested to be opened.
|
// The method that NSApplication calls when documents are requested to be
|
||||||
// It will be called once for each selected document.
|
// opened. It will be called once for each selected document.
|
||||||
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename {
|
- (BOOL)application:(NSApplication*)theApplication
|
||||||
|
openFile:(NSString*)filename {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NSURL* url = [NSURL fileURLWithPath:filename];
|
NSURL* url = [NSURL fileURLWithPath:filename];
|
||||||
|
|
@ -199,10 +206,12 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
if (!urlString) return NO;
|
if (!urlString) return NO;
|
||||||
|
|
||||||
// Add the URL to any command line we're currently setting up.
|
// 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;
|
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;
|
if (NS_FAILED(rv)) return NO;
|
||||||
|
|
||||||
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
||||||
|
|
@ -212,14 +221,16 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
if (NS_FAILED(rv)) return NO;
|
if (NS_FAILED(rv)) return NO;
|
||||||
|
|
||||||
nsCOMPtr<nsIFile> workingDir;
|
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)) {
|
if (NS_FAILED(rv)) {
|
||||||
// Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope.
|
// Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope.
|
||||||
workingDir = nullptr;
|
workingDir = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* argv[3] = {nullptr, "-file", filePath.get()};
|
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_FAILED(rv)) return NO;
|
||||||
|
|
||||||
if (NS_SUCCEEDED(cmdLine->Run())) return YES;
|
if (NS_SUCCEEDED(cmdLine->Run())) return YES;
|
||||||
|
|
@ -229,10 +240,11 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NO);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The method that NSApplication calls when documents are requested to be printed
|
// The method that NSApplication calls when documents are requested to be
|
||||||
// from the Finder (under the "File" menu).
|
// printed from the Finder (under the "File" menu). It will be called once for
|
||||||
// It will be called once for each selected document.
|
// each selected document.
|
||||||
- (BOOL)application:(NSApplication*)theApplication printFile:(NSString*)filename {
|
- (BOOL)application:(NSApplication*)theApplication
|
||||||
|
printFile:(NSString*)filename {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,7 +268,8 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
if (NS_FAILED(rv) || !dockMenuInterface) return menu;
|
if (NS_FAILED(rv) || !dockMenuInterface) return menu;
|
||||||
|
|
||||||
RefPtr<mozilla::widget::NativeMenuMac> dockMenu =
|
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.
|
// Give the menu the opportunity to update itself before display.
|
||||||
dockMenu->MenuWillOpen();
|
dockMenu->MenuWillOpen();
|
||||||
|
|
@ -288,16 +301,21 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
- (void)applicationWillFinishLaunching:(NSNotification*)notification {
|
- (void)applicationWillFinishLaunching:(NSNotification*)notification {
|
||||||
// We provide our own full screen menu item, so we don't want the OS providing
|
// We provide our own full screen menu item, so we don't want the OS providing
|
||||||
// one as well.
|
// 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:]
|
// If we don't handle applicationShouldTerminate:, a call to [NSApp terminate:]
|
||||||
// (from the browser or from the OS) can result in an unclean shutdown.
|
// (from the browser or from the OS) can result in an unclean shutdown.
|
||||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender {
|
- (NSApplicationTerminateReply)applicationShouldTerminate:
|
||||||
nsCOMPtr<nsIObserverService> obsServ = do_GetService("@mozilla.org/observer-service;1");
|
(NSApplication*)sender {
|
||||||
|
nsCOMPtr<nsIObserverService> obsServ =
|
||||||
|
do_GetService("@mozilla.org/observer-service;1");
|
||||||
if (!obsServ) return NSTerminateNow;
|
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;
|
if (!cancelQuit) return NSTerminateNow;
|
||||||
|
|
||||||
cancelQuit->SetData(false);
|
cancelQuit->SetData(false);
|
||||||
|
|
@ -307,7 +325,8 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
cancelQuit->GetData(&abortQuit);
|
cancelQuit->GetData(&abortQuit);
|
||||||
if (abortQuit) return NSTerminateCancel;
|
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) {
|
if (appService) {
|
||||||
bool userAllowedQuit = true;
|
bool userAllowedQuit = true;
|
||||||
appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
|
appService->Quit(nsIAppStartup::eForceQuit, 0, &userAllowedQuit);
|
||||||
|
|
@ -325,22 +344,28 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
|
|
||||||
AutoAutoreleasePool pool;
|
AutoAutoreleasePool pool;
|
||||||
|
|
||||||
bool isGetURLEvent = ([event eventClass] == kInternetEventClass && [event eventID] == kAEGetURL);
|
bool isGetURLEvent = ([event eventClass] == kInternetEventClass &&
|
||||||
|
[event eventID] == kAEGetURL);
|
||||||
if (isGetURLEvent) sProcessedGetURLEvent = true;
|
if (isGetURLEvent) sProcessedGetURLEvent = true;
|
||||||
|
|
||||||
if (isGetURLEvent || ([event eventClass] == 'WWW!' && [event eventID] == 'OURL')) {
|
if (isGetURLEvent ||
|
||||||
NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
|
([event eventClass] == 'WWW!' && [event eventID] == 'OURL')) {
|
||||||
|
NSString* urlString =
|
||||||
|
[[event paramDescriptorForKeyword:keyDirectObject] stringValue];
|
||||||
NSURL* url = [NSURL URLWithString:urlString];
|
NSURL* url = [NSURL URLWithString:urlString];
|
||||||
|
|
||||||
[self openURL:url];
|
[self openURL:url];
|
||||||
} else if ([event eventClass] == kCoreEventClass && [event eventID] == kAEOpenDocuments) {
|
} else if ([event eventClass] == kCoreEventClass &&
|
||||||
NSAppleEventDescriptor* fileListDescriptor = [event paramDescriptorForKeyword:keyDirectObject];
|
[event eventID] == kAEOpenDocuments) {
|
||||||
|
NSAppleEventDescriptor* fileListDescriptor =
|
||||||
|
[event paramDescriptorForKeyword:keyDirectObject];
|
||||||
if (!fileListDescriptor) return;
|
if (!fileListDescriptor) return;
|
||||||
|
|
||||||
// Descriptor list indexing is one-based...
|
// Descriptor list indexing is one-based...
|
||||||
NSInteger numberOfFiles = [fileListDescriptor numberOfItems];
|
NSInteger numberOfFiles = [fileListDescriptor numberOfItems];
|
||||||
for (NSInteger i = 1; i <= numberOfFiles; i++) {
|
for (NSInteger i = 1; i <= numberOfFiles; i++) {
|
||||||
NSString* urlString = [[fileListDescriptor descriptorAtIndex:i] stringValue];
|
NSString* urlString =
|
||||||
|
[[fileListDescriptor descriptorAtIndex:i] stringValue];
|
||||||
if (!urlString) continue;
|
if (!urlString) continue;
|
||||||
|
|
||||||
// We need a path, not a URL
|
// We need a path, not a URL
|
||||||
|
|
@ -359,12 +384,15 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
|
|
||||||
- (BOOL)application:(NSApplication*)application
|
- (BOOL)application:(NSApplication*)application
|
||||||
continueUserActivity:(NSUserActivity*)userActivity
|
continueUserActivity:(NSUserActivity*)userActivity
|
||||||
#if defined(MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
#if defined(MAC_OS_X_VERSION_10_14) && \
|
||||||
restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>>*))restorationHandler {
|
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||||
|
restorationHandler:
|
||||||
|
(void (^)(NSArray<id<NSUserActivityRestoring>>*))restorationHandler {
|
||||||
#else
|
#else
|
||||||
restorationHandler:(void (^)(NSArray*))restorationHandler {
|
restorationHandler:(void (^)(NSArray*))restorationHandler {
|
||||||
#endif
|
#endif
|
||||||
if (![userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
if (![userActivity.activityType
|
||||||
|
isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,7 +406,8 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)openURL:(NSURL*)url {
|
- (BOOL)openURL:(NSURL*)url {
|
||||||
if (!url || !url.scheme || [url.scheme caseInsensitiveCompare:@"chrome"] == NSOrderedSame) {
|
if (!url || !url.scheme ||
|
||||||
|
[url.scheme caseInsensitiveCompare:@"chrome"] == NSOrderedSame) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,14 +419,16 @@ void ProcessPendingGetURLAppleEvents() {
|
||||||
|
|
||||||
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
||||||
nsCOMPtr<nsIFile> workingDir;
|
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)) {
|
if (NS_FAILED(rv)) {
|
||||||
// Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope.
|
// Couldn't find a working dir. Uh oh. Good job cmdline::Init can cope.
|
||||||
workingDir = nullptr;
|
workingDir = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* argv[3] = {nullptr, "-url", urlString};
|
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)) {
|
if (NS_FAILED(rv)) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ void LaunchChildMac(int aArgc, char** aArgv, pid_t* aPid) {
|
||||||
for (int i = 1; i < aArgc; i++) {
|
for (int i = 1; i < aArgc; i++) {
|
||||||
[arguments addObject:[NSString stringWithUTF8String:aArgv[i]]];
|
[arguments addObject:[NSString stringWithUTF8String:aArgv[i]]];
|
||||||
}
|
}
|
||||||
NSTask* child = [NSTask launchedTaskWithLaunchPath:launchPath arguments:arguments];
|
NSTask* child = [NSTask launchedTaskWithLaunchPath:launchPath
|
||||||
|
arguments:arguments];
|
||||||
if (aPid) {
|
if (aPid) {
|
||||||
*aPid = [child processIdentifier];
|
*aPid = [child processIdentifier];
|
||||||
// We used to use waitpid to wait for the process to terminate. This is
|
// We used to use waitpid to wait for the process to terminate. This is
|
||||||
|
|
@ -43,31 +44,36 @@ bool InstallPrivilegedHelper() {
|
||||||
AuthorizationRef authRef = NULL;
|
AuthorizationRef authRef = NULL;
|
||||||
OSStatus status = AuthorizationCreate(
|
OSStatus status = AuthorizationCreate(
|
||||||
NULL, kAuthorizationEmptyEnvironment,
|
NULL, kAuthorizationEmptyEnvironment,
|
||||||
kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed, &authRef);
|
kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed,
|
||||||
|
&authRef);
|
||||||
if (status != errAuthorizationSuccess) {
|
if (status != errAuthorizationSuccess) {
|
||||||
// AuthorizationCreate really shouldn't fail.
|
// AuthorizationCreate really shouldn't fail.
|
||||||
NSLog(@"AuthorizationCreate failed! NSOSStatusErrorDomain / %d", (int)status);
|
NSLog(@"AuthorizationCreate failed! NSOSStatusErrorDomain / %d",
|
||||||
|
(int)status);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL result = NO;
|
BOOL result = NO;
|
||||||
AuthorizationItem authItem = {kSMRightBlessPrivilegedHelper, 0, NULL, 0};
|
AuthorizationItem authItem = {kSMRightBlessPrivilegedHelper, 0, NULL, 0};
|
||||||
AuthorizationRights authRights = {1, &authItem};
|
AuthorizationRights authRights = {1, &authItem};
|
||||||
AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed |
|
AuthorizationFlags flags =
|
||||||
kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
|
kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed |
|
||||||
|
kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
|
||||||
|
|
||||||
// Obtain the right to install our privileged helper tool.
|
// Obtain the right to install our privileged helper tool.
|
||||||
status =
|
status = AuthorizationCopyRights(authRef, &authRights,
|
||||||
AuthorizationCopyRights(authRef, &authRights, kAuthorizationEmptyEnvironment, flags, NULL);
|
kAuthorizationEmptyEnvironment, flags, NULL);
|
||||||
if (status != errAuthorizationSuccess) {
|
if (status != errAuthorizationSuccess) {
|
||||||
NSLog(@"AuthorizationCopyRights failed! NSOSStatusErrorDomain / %d", (int)status);
|
NSLog(@"AuthorizationCopyRights failed! NSOSStatusErrorDomain / %d",
|
||||||
|
(int)status);
|
||||||
} else {
|
} else {
|
||||||
CFErrorRef cfError;
|
CFErrorRef cfError;
|
||||||
// This does all the work of verifying the helper tool against the
|
// This does all the work of verifying the helper tool against the
|
||||||
// application and vice-versa. Once verification has passed, the embedded
|
// application and vice-versa. Once verification has passed, the embedded
|
||||||
// launchd.plist is extracted and placed in /Library/LaunchDaemons and then
|
// launchd.plist is extracted and placed in /Library/LaunchDaemons and then
|
||||||
// loaded. The executable is placed in /Library/PrivilegedHelperTools.
|
// 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);
|
&cfError);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
NSLog(@"Unable to install helper!");
|
NSLog(@"Unable to install helper!");
|
||||||
|
|
@ -90,7 +96,8 @@ void AbortElevatedUpdate() {
|
||||||
updateServer = (id)[NSConnection
|
updateServer = (id)[NSConnection
|
||||||
rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server"
|
rootProxyForConnectionWithRegisteredName:@"org.mozilla.updater.server"
|
||||||
host:nil
|
host:nil
|
||||||
usingNameServer:[NSSocketPortNameServer sharedInstance]];
|
usingNameServer:[NSSocketPortNameServer
|
||||||
|
sharedInstance]];
|
||||||
if (updateServer && [updateServer respondsToSelector:@selector(abort)]) {
|
if (updateServer && [updateServer respondsToSelector:@selector(abort)]) {
|
||||||
[updateServer performSelector:@selector(abort)];
|
[updateServer performSelector:@selector(abort)];
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -59,30 +59,37 @@ static bool AskUserIfWeShouldLaunchExistingInstall() {
|
||||||
|
|
||||||
ErrorResult rv;
|
ErrorResult rv;
|
||||||
nsAutoCString mozTitle, mozMessage, mozLaunchExisting, mozLaunchFromDMG;
|
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()) {
|
if (rv.Failed()) {
|
||||||
return false;
|
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()) {
|
if (rv.Failed()) {
|
||||||
return false;
|
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()) {
|
if (rv.Failed()) {
|
||||||
return false;
|
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()) {
|
if (rv.Failed()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
NSString* title = [NSString
|
||||||
NSString* message =
|
stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
NSString* message = [NSString
|
||||||
|
stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||||
NSString* launchExisting =
|
NSString* launchExisting =
|
||||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozLaunchExisting.get())];
|
[NSString stringWithUTF8String:reinterpret_cast<const char*>(
|
||||||
|
mozLaunchExisting.get())];
|
||||||
NSString* launchFromDMG =
|
NSString* launchFromDMG =
|
||||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozLaunchFromDMG.get())];
|
[NSString stringWithUTF8String:reinterpret_cast<const char*>(
|
||||||
|
mozLaunchFromDMG.get())];
|
||||||
|
|
||||||
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
||||||
|
|
||||||
|
|
@ -144,18 +151,20 @@ static bool AskUserIfWeShouldInstall() {
|
||||||
if (rv.Failed()) {
|
if (rv.Failed()) {
|
||||||
return false;
|
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()) {
|
if (rv.Failed()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
NSString* title = [NSString
|
||||||
NSString* message =
|
stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
NSString* message = [NSString
|
||||||
NSString* install =
|
stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozInstall.get())];
|
NSString* install = [NSString
|
||||||
NSString* dontInstall =
|
stringWithUTF8String:reinterpret_cast<const char*>(mozInstall.get())];
|
||||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozDontInstall.get())];
|
NSString* dontInstall = [NSString
|
||||||
|
stringWithUTF8String:reinterpret_cast<const char*>(mozDontInstall.get())];
|
||||||
|
|
||||||
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
||||||
|
|
||||||
|
|
@ -179,15 +188,15 @@ static bool AskUserIfWeShouldInstall() {
|
||||||
// AskUserIfWeShouldInstall
|
// AskUserIfWeShouldInstall
|
||||||
// |
|
// |
|
||||||
// | ---> [NSApp run]
|
// | ---> [NSApp run]
|
||||||
// | |
|
// | |
|
||||||
// | | -----> task
|
// | | ---> task
|
||||||
// | | | -----------> [alert runModal]
|
// | | | ----> [alert runModal]
|
||||||
// | | | | (User selects button)
|
// | | | | (User selects button)
|
||||||
// | | | <--------------- done
|
// | | | <--------- done
|
||||||
// | | |
|
// | | |
|
||||||
// | | | -----------> [NSApp stop:nil]
|
// | | | -----> [NSApp stop:nil]
|
||||||
// | | | <-----------
|
// | | | <-----
|
||||||
// | | <--------
|
// | | <-----
|
||||||
// | <-------
|
// | <-------
|
||||||
// done
|
// done
|
||||||
__block NSInteger result = -1;
|
__block NSInteger result = -1;
|
||||||
|
|
@ -225,9 +234,10 @@ static void ShowInstallFailedDialog() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* title = [NSString stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
NSString* title = [NSString
|
||||||
NSString* message =
|
stringWithUTF8String:reinterpret_cast<const char*>(mozTitle.get())];
|
||||||
[NSString stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
NSString* message = [NSString
|
||||||
|
stringWithUTF8String:reinterpret_cast<const char*>(mozMessage.get())];
|
||||||
|
|
||||||
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
||||||
|
|
||||||
|
|
@ -322,8 +332,9 @@ static bool InstallFromPath(NSString* aBundlePath, NSString* aDestPath) {
|
||||||
NSString* destDir = [aDestPath stringByDeletingLastPathComponent];
|
NSString* destDir = [aDestPath stringByDeletingLastPathComponent];
|
||||||
if (!installSuccessful && ![fileManager isWritableFileAtPath:destDir]) {
|
if (!installSuccessful && ![fileManager isWritableFileAtPath:destDir]) {
|
||||||
NSString* updaterBinPath = [NSString pathWithComponents:@[
|
NSString* updaterBinPath = [NSString pathWithComponents:@[
|
||||||
aBundlePath, @"Contents", @"MacOS", [NSString stringWithUTF8String:UPDATER_APP], @"Contents",
|
aBundlePath, @"Contents", @"MacOS",
|
||||||
@"MacOS", [NSString stringWithUTF8String:UPDATER_BIN]
|
[NSString stringWithUTF8String:UPDATER_APP], @"Contents", @"MacOS",
|
||||||
|
[NSString stringWithUTF8String:UPDATER_BIN]
|
||||||
]];
|
]];
|
||||||
|
|
||||||
NSArray* arguments = @[ @"-dmgInstall", aBundlePath, aDestPath ];
|
NSArray* arguments = @[ @"-dmgInstall", aBundlePath, aDestPath ];
|
||||||
|
|
@ -354,7 +365,8 @@ static bool InstallFromPath(NSString* aBundlePath, NSString* aDestPath) {
|
||||||
bool IsAppRunningFromDmg() {
|
bool IsAppRunningFromDmg() {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
const char* path = [[[NSBundle mainBundle] bundlePath] fileSystemRepresentation];
|
const char* path =
|
||||||
|
[[[NSBundle mainBundle] bundlePath] fileSystemRepresentation];
|
||||||
|
|
||||||
struct statfs statfsBuf;
|
struct statfs statfsBuf;
|
||||||
if (statfs(path, &statfsBuf) != 0) {
|
if (statfs(path, &statfsBuf) != 0) {
|
||||||
|
|
@ -388,11 +400,13 @@ bool IsAppRunningFromDmg() {
|
||||||
|
|
||||||
// Get the IOMedia object:
|
// Get the IOMedia object:
|
||||||
// (Note: IOServiceGetMatchingServices takes ownership of serviceDict's ref.)
|
// (Note: IOServiceGetMatchingServices takes ownership of serviceDict's ref.)
|
||||||
CFMutableDictionaryRef serviceDict = IOBSDNameMatching(kIOMasterPortDefault, 0, bsdDeviceName);
|
CFMutableDictionaryRef serviceDict =
|
||||||
|
IOBSDNameMatching(kIOMasterPortDefault, 0, bsdDeviceName);
|
||||||
if (!serviceDict) {
|
if (!serviceDict) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
io_service_t media = IOServiceGetMatchingService(kIOMasterPortDefault, serviceDict);
|
io_service_t media =
|
||||||
|
IOServiceGetMatchingService(kIOMasterPortDefault, serviceDict);
|
||||||
if (!media || !IOObjectConformsTo(media, "IOMedia")) {
|
if (!media || !IOObjectConformsTo(media, "IOMedia")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -401,14 +415,16 @@ bool IsAppRunningFromDmg() {
|
||||||
// (taking care to start with `media` itself):
|
// (taking care to start with `media` itself):
|
||||||
io_service_t imageDrive = IO_OBJECT_NULL;
|
io_service_t imageDrive = IO_OBJECT_NULL;
|
||||||
io_iterator_t iter;
|
io_iterator_t iter;
|
||||||
if (IORegistryEntryCreateIterator(media, kIOServicePlane,
|
if (IORegistryEntryCreateIterator(
|
||||||
kIORegistryIterateRecursively | kIORegistryIterateParents,
|
media, kIOServicePlane,
|
||||||
&iter) != KERN_SUCCESS) {
|
kIORegistryIterateRecursively | kIORegistryIterateParents,
|
||||||
|
&iter) != KERN_SUCCESS) {
|
||||||
IOObjectRelease(media);
|
IOObjectRelease(media);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const char* imageClass =
|
const char* imageClass = nsCocoaFeatures::OnMontereyOrLater()
|
||||||
nsCocoaFeatures::OnMontereyOrLater() ? "AppleDiskImageDevice" : "IOHDIXHDDrive";
|
? "AppleDiskImageDevice"
|
||||||
|
: "IOHDIXHDDrive";
|
||||||
for (imageDrive = media; imageDrive; imageDrive = IOIteratorNext(iter)) {
|
for (imageDrive = media; imageDrive; imageDrive = IOIteratorNext(iter)) {
|
||||||
if (IOObjectConformsTo(imageDrive, imageClass)) {
|
if (IOObjectConformsTo(imageDrive, imageClass)) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -446,20 +462,22 @@ bool MaybeInstallAndRelaunch() {
|
||||||
// The Applications directory may not be at /Applications, although in
|
// The Applications directory may not be at /Applications, although in
|
||||||
// practice we're unlikely to encounter since run-from-.dmg is really an
|
// practice we're unlikely to encounter since run-from-.dmg is really an
|
||||||
// issue with novice mac users. Still, look it up correctly:
|
// issue with novice mac users. Still, look it up correctly:
|
||||||
NSArray* applicationsDirs =
|
NSArray* applicationsDirs = NSSearchPathForDirectoriesInDomains(
|
||||||
NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES);
|
NSApplicationDirectory, NSLocalDomainMask, YES);
|
||||||
NSString* applicationsDir = applicationsDirs[0];
|
NSString* applicationsDir = applicationsDirs[0];
|
||||||
|
|
||||||
// Sanity check dir exists
|
// Sanity check dir exists
|
||||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
BOOL isDir;
|
BOOL isDir;
|
||||||
if (![fileManager fileExistsAtPath:applicationsDir isDirectory:&isDir] || !isDir) {
|
if (![fileManager fileExistsAtPath:applicationsDir isDirectory:&isDir] ||
|
||||||
|
!isDir) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
|
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||||
NSString* appName = [bundlePath lastPathComponent];
|
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
|
// 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
|
// tell without asking if we're dealing with the edge case of an
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@
|
||||||
#include "UIKitDirProvider.h"
|
#include "UIKitDirProvider.h"
|
||||||
|
|
||||||
bool GetUIKitDirectory(bool aLocal, nsACString& aUserDir) {
|
bool GetUIKitDirectory(bool aLocal, nsACString& aUserDir) {
|
||||||
NSSearchPathDirectory directory = aLocal ? NSCachesDirectory : NSApplicationSupportDirectory;
|
NSSearchPathDirectory directory =
|
||||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
aLocal ? NSCachesDirectory : NSApplicationSupportDirectory;
|
||||||
|
NSArray* paths =
|
||||||
|
NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
||||||
if ([paths count] == 0) {
|
if ([paths count] == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ static bool sBuildingCommandLine = false;
|
||||||
void AddToCommandLine(const char* inArgText) {
|
void AddToCommandLine(const char* inArgText) {
|
||||||
if (sArgsUsed >= sArgsAllocated - 1) {
|
if (sArgsUsed >= sArgsAllocated - 1) {
|
||||||
// realloc does not free the given pointer if allocation fails
|
// realloc does not free the given pointer if allocation fails
|
||||||
char** temp =
|
char** temp = static_cast<char**>(
|
||||||
static_cast<char**>(realloc(sArgs, (sArgsAllocated + kArgsGrowSize) * sizeof(char*)));
|
realloc(sArgs, (sArgsAllocated + kArgsGrowSize) * sizeof(char*)));
|
||||||
if (!temp) return;
|
if (!temp) return;
|
||||||
sArgs = temp;
|
sArgs = temp;
|
||||||
sArgsAllocated += kArgsGrowSize;
|
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
|
// if the parent is in the foreground. This will be communicated in a
|
||||||
// command-line argument to the child.
|
// command-line argument to the child.
|
||||||
if (forRestart) {
|
if (forRestart) {
|
||||||
NSRunningApplication* frontApp = [[NSWorkspace sharedWorkspace] frontmostApplication];
|
NSRunningApplication* frontApp =
|
||||||
|
[[NSWorkspace sharedWorkspace] frontmostApplication];
|
||||||
if ([frontApp isEqual:[NSRunningApplication currentApplication]]) {
|
if ([frontApp isEqual:[NSRunningApplication currentApplication]]) {
|
||||||
AddToCommandLine("-foreground");
|
AddToCommandLine("-foreground");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,8 @@ nsNativeAppSupportCocoa::ReOpen() {
|
||||||
windowList->HasMoreElements(&more);
|
windowList->HasMoreElements(&more);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NSWindow* cocoaWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
|
NSWindow* cocoaWindow =
|
||||||
|
(NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||||
if (![cocoaWindow isMiniaturized]) {
|
if (![cocoaWindow isMiniaturized]) {
|
||||||
haveNonMiniaturized = true;
|
haveNonMiniaturized = true;
|
||||||
break; // have un-minimized windows, nothing to do
|
break; // have un-minimized windows, nothing to do
|
||||||
|
|
@ -154,7 +155,8 @@ nsNativeAppSupportCocoa::ReOpen() {
|
||||||
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
|
||||||
|
|
||||||
nsresult rv;
|
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);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return cmdLine->Run();
|
return cmdLine->Run();
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,10 @@ bool IsRecursivelyWritable(const char* aPath) {
|
||||||
NSString* rootPath = [NSString stringWithUTF8String:aPath];
|
NSString* rootPath = [NSString stringWithUTF8String:aPath];
|
||||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
NSError* error = nil;
|
NSError* error = nil;
|
||||||
NSArray* subPaths = [fileManager subpathsOfDirectoryAtPath:rootPath error:&error];
|
NSArray* subPaths = [fileManager subpathsOfDirectoryAtPath:rootPath
|
||||||
NSMutableArray* paths = [NSMutableArray arrayWithCapacity:[subPaths count] + 1];
|
error:&error];
|
||||||
|
NSMutableArray* paths =
|
||||||
|
[NSMutableArray arrayWithCapacity:[subPaths count] + 1];
|
||||||
[paths addObject:@""];
|
[paths addObject:@""];
|
||||||
[paths addObjectsFromArray:subPaths];
|
[paths addObjectsFromArray:subPaths];
|
||||||
|
|
||||||
|
|
@ -26,7 +28,8 @@ bool IsRecursivelyWritable(const char* aPath) {
|
||||||
for (NSString* currPath in paths) {
|
for (NSString* currPath in paths) {
|
||||||
NSString* child = [rootPath stringByAppendingPathComponent:currPath];
|
NSString* child = [rootPath stringByAppendingPathComponent:currPath];
|
||||||
|
|
||||||
NSDictionary* attributes = [fileManager attributesOfItemAtPath:child error:&error];
|
NSDictionary* attributes = [fileManager attributesOfItemAtPath:child
|
||||||
|
error:&error];
|
||||||
if (error) {
|
if (error) {
|
||||||
[pool drain];
|
[pool drain];
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
#include "nsILocalFileMac.h"
|
#include "nsILocalFileMac.h"
|
||||||
#include "nsIURI.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) {
|
NS_IMETHODIMP nsLocalHandlerAppMac::GetName(nsAString& aName) {
|
||||||
if (mExecutable) {
|
if (mExecutable) {
|
||||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(mExecutable);
|
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(mExecutable);
|
||||||
|
|
@ -30,7 +31,8 @@ NS_IMETHODIMP nsLocalHandlerAppMac::GetName(nsAString& aName) {
|
||||||
* somewhere more central (see bug 389922).
|
* somewhere more central (see bug 389922).
|
||||||
*/
|
*/
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsLocalHandlerAppMac::LaunchWithURI(nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
|
nsLocalHandlerAppMac::LaunchWithURI(
|
||||||
|
nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
@ -45,14 +47,15 @@ nsLocalHandlerAppMac::LaunchWithURI(nsIURI* aURI, mozilla::dom::BrowsingContext*
|
||||||
aURI->GetAsciiSpec(uriSpec);
|
aURI->GetAsciiSpec(uriSpec);
|
||||||
|
|
||||||
const UInt8* uriString = reinterpret_cast<const UInt8*>(uriSpec.get());
|
const UInt8* uriString = reinterpret_cast<const UInt8*>(uriSpec.get());
|
||||||
CFURLRef uri =
|
CFURLRef uri = ::CFURLCreateWithBytes(NULL, uriString, uriSpec.Length(),
|
||||||
::CFURLCreateWithBytes(NULL, uriString, uriSpec.Length(), kCFStringEncodingUTF8, NULL);
|
kCFStringEncodingUTF8, NULL);
|
||||||
if (!uri) {
|
if (!uri) {
|
||||||
::CFRelease(appURL);
|
::CFRelease(appURL);
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
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) {
|
if (!uris) {
|
||||||
::CFRelease(uri);
|
::CFRelease(uri);
|
||||||
::CFRelease(appURL);
|
::CFRelease(appURL);
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@
|
||||||
#include "nsMIMEInfoMac.h"
|
#include "nsMIMEInfoMac.h"
|
||||||
#include "nsILocalFileMac.h"
|
#include "nsILocalFileMac.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
|
||||||
NS_IMETHODIMP nsMIMEInfoMac::GetDefaultDescription(nsAString& aDefaultDescription) {
|
// .app suffix)
|
||||||
|
NS_IMETHODIMP nsMIMEInfoMac::GetDefaultDescription(
|
||||||
|
nsAString& aDefaultDescription) {
|
||||||
nsCOMPtr<nsIFile> defaultApp = GetDefaultApplication();
|
nsCOMPtr<nsIFile> defaultApp = GetDefaultApplication();
|
||||||
if (defaultApp) {
|
if (defaultApp) {
|
||||||
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(defaultApp);
|
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(defaultApp);
|
||||||
|
|
@ -43,7 +45,8 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile* aFile) {
|
||||||
if (mPreferredAction == useHelperApp) {
|
if (mPreferredAction == useHelperApp) {
|
||||||
// we don't yet support passing content by value (rather than reference)
|
// we don't yet support passing content by value (rather than reference)
|
||||||
// to web apps. at some point, we will probably want to.
|
// 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);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
rv = localHandlerApp->GetExecutable(getter_AddRefs(application));
|
rv = localHandlerApp->GetExecutable(getter_AddRefs(application));
|
||||||
|
|
@ -68,7 +71,8 @@ nsMIMEInfoMac::LaunchWithFile(nsIFile* aFile) {
|
||||||
tempFile->GetFSRef(&tempFileRef);
|
tempFile->GetFSRef(&tempFileRef);
|
||||||
|
|
||||||
FSRef appFSRef;
|
FSRef appFSRef;
|
||||||
if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef, nullptr) == noErr) {
|
if (::LSGetApplicationForItem(&tempFileRef, kLSRolesAll, &appFSRef,
|
||||||
|
nullptr) == noErr) {
|
||||||
app = (do_CreateInstance("@mozilla.org/file/local;1"));
|
app = (do_CreateInstance("@mozilla.org/file/local;1"));
|
||||||
if (!app) return NS_ERROR_FAILURE;
|
if (!app) return NS_ERROR_FAILURE;
|
||||||
app->InitWithFSRef(&appFSRef);
|
app->InitWithFSRef(&appFSRef);
|
||||||
|
|
@ -91,8 +95,9 @@ nsresult nsMIMEInfoMac::LoadUriInternal(nsIURI* aURI) {
|
||||||
nsAutoCString uri;
|
nsAutoCString uri;
|
||||||
aURI->GetSpec(uri);
|
aURI->GetSpec(uri);
|
||||||
if (!uri.IsEmpty()) {
|
if (!uri.IsEmpty()) {
|
||||||
CFURLRef myURLRef = ::CFURLCreateWithBytes(kCFAllocatorDefault, (const UInt8*)uri.get(),
|
CFURLRef myURLRef =
|
||||||
strlen(uri.get()), kCFStringEncodingUTF8, NULL);
|
::CFURLCreateWithBytes(kCFAllocatorDefault, (const UInt8*)uri.get(),
|
||||||
|
strlen(uri.get()), kCFStringEncodingUTF8, NULL);
|
||||||
if (myURLRef) {
|
if (myURLRef) {
|
||||||
OSStatus status = ::LSOpenCFURLRef(myURLRef, NULL);
|
OSStatus status = ::LSOpenCFURLRef(myURLRef, NULL);
|
||||||
if (status == noErr) rv = NS_OK;
|
if (status == noErr) rv = NS_OK;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@
|
||||||
#import <ApplicationServices/ApplicationServices.h>
|
#import <ApplicationServices/ApplicationServices.h>
|
||||||
|
|
||||||
// chrome URL's
|
// 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"
|
#define BRAND_BUNDLE_URL "chrome://branding/locale/brand.properties"
|
||||||
|
|
||||||
nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) {
|
nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) {
|
||||||
|
|
@ -34,18 +35,20 @@ nsresult GetDefaultBundleURL(const nsACString& aScheme, CFURLRef* aBundleURL) {
|
||||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
CFStringRef schemeCFString = ::CFStringCreateWithBytes(
|
CFStringRef schemeCFString = ::CFStringCreateWithBytes(
|
||||||
kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aScheme).get(), aScheme.Length(),
|
kCFAllocatorDefault, (const UInt8*)PromiseFlatCString(aScheme).get(),
|
||||||
kCFStringEncodingUTF8, false);
|
aScheme.Length(), kCFStringEncodingUTF8, false);
|
||||||
|
|
||||||
if (schemeCFString) {
|
if (schemeCFString) {
|
||||||
CFStringRef lookupCFString =
|
CFStringRef lookupCFString =
|
||||||
::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString);
|
::CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:"), schemeCFString);
|
||||||
|
|
||||||
if (lookupCFString) {
|
if (lookupCFString) {
|
||||||
CFURLRef lookupCFURL = ::CFURLCreateWithString(NULL, lookupCFString, NULL);
|
CFURLRef lookupCFURL =
|
||||||
|
::CFURLCreateWithString(NULL, lookupCFString, NULL);
|
||||||
|
|
||||||
if (lookupCFURL) {
|
if (lookupCFURL) {
|
||||||
*aBundleURL = ::LSCopyDefaultApplicationURLForURL(lookupCFURL, kLSRolesAll, NULL);
|
*aBundleURL =
|
||||||
|
::LSCopyDefaultApplicationURLForURL(lookupCFURL, kLSRolesAll, NULL);
|
||||||
if (*aBundleURL) {
|
if (*aBundleURL) {
|
||||||
rv = NS_OK;
|
rv = NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -88,15 +91,15 @@ using mozilla::LogLevel;
|
||||||
|
|
||||||
nsOSHelperAppService::~nsOSHelperAppService() {}
|
nsOSHelperAppService::~nsOSHelperAppService() {}
|
||||||
|
|
||||||
nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolScheme,
|
nsresult nsOSHelperAppService::OSProtocolHandlerExists(
|
||||||
bool* aHandlerExists) {
|
const char* aProtocolScheme, bool* aHandlerExists) {
|
||||||
// CFStringCreateWithBytes() can fail even if we're not out of memory --
|
// CFStringCreateWithBytes() can fail even if we're not out of memory --
|
||||||
// for example if the 'bytes' parameter is something very weird (like
|
// 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
|
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||||
// specified in the 'encoding' parameter. See bug 548719.
|
// specified in the 'encoding' parameter. See bug 548719.
|
||||||
CFStringRef schemeString =
|
CFStringRef schemeString = ::CFStringCreateWithBytes(
|
||||||
::CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)aProtocolScheme,
|
kCFAllocatorDefault, (const UInt8*)aProtocolScheme,
|
||||||
strlen(aProtocolScheme), kCFStringEncodingUTF8, false);
|
strlen(aProtocolScheme), kCFStringEncodingUTF8, false);
|
||||||
if (schemeString) {
|
if (schemeString) {
|
||||||
// LSCopyDefaultHandlerForURLScheme() can fail to find the default handler
|
// LSCopyDefaultHandlerForURLScheme() can fail to find the default handler
|
||||||
// for aProtocolScheme when it's never been explicitly set (using
|
// for aProtocolScheme when it's never been explicitly set (using
|
||||||
|
|
@ -118,8 +121,8 @@ nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolSche
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme,
|
NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(
|
||||||
nsAString& _retval) {
|
const nsACString& aScheme, nsAString& _retval) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
@ -136,14 +139,17 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString&
|
||||||
|
|
||||||
// Get the human-readable name of the bundle
|
// Get the human-readable name of the bundle
|
||||||
CFStringRef bundleName =
|
CFStringRef bundleName =
|
||||||
(CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle, kCFBundleNameKey);
|
(CFStringRef)::CFBundleGetValueForInfoDictionaryKey(handlerBundle,
|
||||||
|
kCFBundleNameKey);
|
||||||
|
|
||||||
if (bundleName) {
|
if (bundleName) {
|
||||||
AutoTArray<UniChar, 255> buffer;
|
AutoTArray<UniChar, 255> buffer;
|
||||||
CFIndex bundleNameLength = ::CFStringGetLength(bundleName);
|
CFIndex bundleNameLength = ::CFStringGetLength(bundleName);
|
||||||
buffer.SetLength(bundleNameLength);
|
buffer.SetLength(bundleNameLength);
|
||||||
::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength), buffer.Elements());
|
::CFStringGetCharacters(bundleName, CFRangeMake(0, bundleNameLength),
|
||||||
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), bundleNameLength);
|
buffer.Elements());
|
||||||
|
_retval.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
|
||||||
|
bundleNameLength);
|
||||||
rv = NS_OK;
|
rv = NS_OK;
|
||||||
}
|
}
|
||||||
::CFRelease(handlerBundle);
|
::CFRelease(handlerBundle);
|
||||||
|
|
@ -155,8 +161,8 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString&
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
|
NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
|
||||||
bool* _retval) {
|
const nsACString& aScheme, bool* _retval) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
@ -164,7 +170,8 @@ NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACS
|
||||||
CFURLRef handlerBundleURL;
|
CFURLRef handlerBundleURL;
|
||||||
rv = GetDefaultBundleURL(aScheme, &handlerBundleURL);
|
rv = GetDefaultBundleURL(aScheme, &handlerBundleURL);
|
||||||
if (NS_SUCCEEDED(rv) && 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;
|
rv = NS_ERROR_NOT_AVAILABLE;
|
||||||
CFBundleRef appBundle = ::CFBundleGetMainBundle();
|
CFBundleRef appBundle = ::CFBundleGetMainBundle();
|
||||||
if (appBundle) {
|
if (appBundle) {
|
||||||
|
|
@ -181,23 +188,25 @@ NS_IMETHODIMP nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACS
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppPath,
|
nsresult nsOSHelperAppService::GetFileTokenForPath(
|
||||||
nsIFile** aFile) {
|
const char16_t* aPlatformAppPath, nsIFile** aFile) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsresult rv;
|
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);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
CFURLRef pathAsCFURL;
|
CFURLRef pathAsCFURL;
|
||||||
CFStringRef pathAsCFString = ::CFStringCreateWithCharacters(
|
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 (!pathAsCFString) return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
if (::CFStringGetCharacterAtIndex(pathAsCFString, 0) == '/') {
|
if (::CFStringGetCharacterAtIndex(pathAsCFString, 0) == '/') {
|
||||||
// we have a Posix path
|
// we have a Posix path
|
||||||
pathAsCFURL =
|
pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString,
|
||||||
::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString, kCFURLPOSIXPathStyle, false);
|
kCFURLPOSIXPathStyle, false);
|
||||||
if (!pathAsCFURL) {
|
if (!pathAsCFURL) {
|
||||||
::CFRelease(pathAsCFString);
|
::CFRelease(pathAsCFString);
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
@ -214,8 +223,8 @@ nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppP
|
||||||
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAsCFURL =
|
pathAsCFURL = ::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString,
|
||||||
::CFURLCreateWithFileSystemPath(nullptr, pathAsCFString, kCFURLHFSPathStyle, false);
|
kCFURLHFSPathStyle, false);
|
||||||
if (!pathAsCFURL) {
|
if (!pathAsCFURL) {
|
||||||
::CFRelease(pathAsCFString);
|
::CFRelease(pathAsCFString);
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
@ -259,7 +268,8 @@ static CFArrayRef GetMIMETypesHandledByApp(FSRef* aAppRef) {
|
||||||
if (!infoDict) {
|
if (!infoDict) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
CFTypeRef cfObject = ::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes"));
|
CFTypeRef cfObject =
|
||||||
|
::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes"));
|
||||||
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
|
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
|
||||||
::CFRelease(infoDict);
|
::CFRelease(infoDict);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -307,7 +317,8 @@ static CFArrayRef GetMIMETypesHandledByApp(FSRef* aAppRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||||
const nsACString& aFileExt, bool* aFound,
|
const nsACString& aFileExt,
|
||||||
|
bool* aFound,
|
||||||
nsIMIMEInfo** aMIMEInfo) {
|
nsIMIMEInfo** aMIMEInfo) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
|
|
@ -318,7 +329,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||||
const nsCString& flatExt = PromiseFlatCString(aFileExt);
|
const nsCString& flatExt = PromiseFlatCString(aFileExt);
|
||||||
|
|
||||||
MOZ_LOG(sLog, LogLevel::Debug,
|
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.
|
// Create a Mac-specific MIME info so we can use Mac-specific members.
|
||||||
RefPtr<nsMIMEInfoMac> mimeInfoMac = new nsMIMEInfoMac(aMIMEType);
|
RefPtr<nsMIMEInfoMac> mimeInfoMac = new nsMIMEInfoMac(aMIMEType);
|
||||||
|
|
@ -337,13 +349,15 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||||
CFStringRef cfMIMEType = NULL;
|
CFStringRef cfMIMEType = NULL;
|
||||||
|
|
||||||
if (!aMIMEType.IsEmpty()) {
|
if (!aMIMEType.IsEmpty()) {
|
||||||
typeIsOctetStream = aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM);
|
typeIsOctetStream =
|
||||||
|
aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM);
|
||||||
CFURLRef appURL = NULL;
|
CFURLRef appURL = NULL;
|
||||||
// CFStringCreateWithCString() can fail even if we're not out of memory --
|
// CFStringCreateWithCString() can fail even if we're not out of memory --
|
||||||
// for example if the 'cStr' parameter is something very weird (like
|
// 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
|
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||||
// specified in the 'encoding' parameter. See bug 548719.
|
// specified in the 'encoding' parameter. See bug 548719.
|
||||||
cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(), kCFStringEncodingUTF8);
|
cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
if (cfMIMEType) {
|
if (cfMIMEType) {
|
||||||
err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL);
|
err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL);
|
||||||
if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) {
|
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
|
// 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
|
// "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
|
||||||
// specified in the 'encoding' parameter. See bug 548719.
|
// specified in the 'encoding' parameter. See bug 548719.
|
||||||
CFStringRef cfExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
|
CFStringRef cfExt =
|
||||||
|
::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
|
||||||
if (cfExt) {
|
if (cfExt) {
|
||||||
err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt, kLSRolesAll,
|
err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt,
|
||||||
&extAppFSRef, nullptr);
|
kLSRolesAll, &extAppFSRef, nullptr);
|
||||||
if (err == noErr) {
|
if (err == noErr) {
|
||||||
haveAppForExt = true;
|
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);
|
::CFRelease(cfExt);
|
||||||
}
|
}
|
||||||
|
|
@ -375,7 +391,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||||
|
|
||||||
if (haveAppForType && haveAppForExt) {
|
if (haveAppForType && haveAppForExt) {
|
||||||
// Do aMIMEType and aFileExt match?
|
// 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;
|
typeAppIsDefault = true;
|
||||||
*aFound = true;
|
*aFound = true;
|
||||||
}
|
}
|
||||||
|
|
@ -418,9 +435,10 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||||
CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef);
|
CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef);
|
||||||
if (extAppMIMETypes) {
|
if (extAppMIMETypes) {
|
||||||
if (cfMIMEType) {
|
if (cfMIMEType) {
|
||||||
if (::CFArrayContainsValue(extAppMIMETypes,
|
if (::CFArrayContainsValue(
|
||||||
::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)),
|
extAppMIMETypes,
|
||||||
cfMIMEType)) {
|
::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)),
|
||||||
|
cfMIMEType)) {
|
||||||
extAppIsDefault = true;
|
extAppIsDefault = true;
|
||||||
*aFound = 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
|
// the doc for this method says that if we have a MIME type (in
|
||||||
// aMIMEType), we need to give it preference.)
|
// aMIMEType), we need to give it preference.)
|
||||||
NSURLFileTypeMappings* map = [NSURLFileTypeMappings sharedMappings];
|
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;
|
NSString* typeStr = map ? [map MIMETypeForExtension:extStr] : NULL;
|
||||||
if (typeStr) {
|
if (typeStr) {
|
||||||
nsAutoCString mimeType;
|
nsAutoCString mimeType;
|
||||||
mimeType.Assign((char*)[typeStr cStringUsingEncoding:NSASCIIStringEncoding]);
|
mimeType.Assign(
|
||||||
|
(char*)[typeStr cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||||
mimeInfoMac->SetMIMEType(mimeType);
|
mimeInfoMac->SetMIMEType(mimeType);
|
||||||
haveAppForType = true;
|
haveAppForType = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -476,7 +496,8 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||||
if (haveAppForExt) mimeInfoMac->AppendExtension(aFileExt);
|
if (haveAppForExt) mimeInfoMac->AppendExtension(aFileExt);
|
||||||
|
|
||||||
nsresult rv;
|
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)) {
|
if (NS_FAILED(rv)) {
|
||||||
[localPool release];
|
[localPool release];
|
||||||
return rv;
|
return rv;
|
||||||
|
|
@ -485,20 +506,22 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||||
CFStringRef cfAppName = NULL;
|
CFStringRef cfAppName = NULL;
|
||||||
if (typeAppIsDefault) {
|
if (typeAppIsDefault) {
|
||||||
app->InitWithFSRef(&typeAppFSRef);
|
app->InitWithFSRef(&typeAppFSRef);
|
||||||
::LSCopyItemAttribute((const FSRef*)&typeAppFSRef, kLSRolesAll, kLSItemDisplayName,
|
::LSCopyItemAttribute((const FSRef*)&typeAppFSRef, kLSRolesAll,
|
||||||
(CFTypeRef*)&cfAppName);
|
kLSItemDisplayName, (CFTypeRef*)&cfAppName);
|
||||||
} else {
|
} else {
|
||||||
app->InitWithFSRef(&extAppFSRef);
|
app->InitWithFSRef(&extAppFSRef);
|
||||||
::LSCopyItemAttribute((const FSRef*)&extAppFSRef, kLSRolesAll, kLSItemDisplayName,
|
::LSCopyItemAttribute((const FSRef*)&extAppFSRef, kLSRolesAll,
|
||||||
(CFTypeRef*)&cfAppName);
|
kLSItemDisplayName, (CFTypeRef*)&cfAppName);
|
||||||
}
|
}
|
||||||
if (cfAppName) {
|
if (cfAppName) {
|
||||||
AutoTArray<UniChar, 255> buffer;
|
AutoTArray<UniChar, 255> buffer;
|
||||||
CFIndex appNameLength = ::CFStringGetLength(cfAppName);
|
CFIndex appNameLength = ::CFStringGetLength(cfAppName);
|
||||||
buffer.SetLength(appNameLength);
|
buffer.SetLength(appNameLength);
|
||||||
::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength), buffer.Elements());
|
::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength),
|
||||||
|
buffer.Elements());
|
||||||
nsAutoString appName;
|
nsAutoString appName;
|
||||||
appName.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), appNameLength);
|
appName.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
|
||||||
|
appNameLength);
|
||||||
mimeInfoMac->SetDefaultDescription(appName);
|
mimeInfoMac->SetDefaultDescription(appName);
|
||||||
::CFRelease(cfAppName);
|
::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
|
// If we have a MIME type, make sure its extension list is included in our
|
||||||
// list.
|
// list.
|
||||||
NSURLFileTypeMappings* map = [NSURLFileTypeMappings sharedMappings];
|
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;
|
NSArray* extensionsList = map ? [map extensionsForMIMEType:typeStr] : NULL;
|
||||||
if (extensionsList) {
|
if (extensionsList) {
|
||||||
for (NSString* extension in extensionsList) {
|
for (NSString* extension in extensionsList) {
|
||||||
nsAutoCString ext;
|
nsAutoCString ext;
|
||||||
ext.Assign((char*)[extension cStringUsingEncoding:NSASCIIStringEncoding]);
|
ext.Assign(
|
||||||
|
(char*)[extension cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||||
mimeInfoMac->AppendExtension(ext);
|
mimeInfoMac->AppendExtension(ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CFStringRef cfType =
|
if (CFStringRef cfType = ::CFStringCreateWithCString(
|
||||||
::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8)) {
|
NULL, mimeType.get(), kCFStringEncodingUTF8)) {
|
||||||
if (CFStringRef cfTypeDesc = ::UTTypeCopyDescription(cfType)) {
|
if (CFStringRef cfTypeDesc = ::UTTypeCopyDescription(cfType)) {
|
||||||
AutoTArray<UniChar, 255> buffer;
|
AutoTArray<UniChar, 255> buffer;
|
||||||
CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc);
|
CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc);
|
||||||
buffer.SetLength(typeDescLength);
|
buffer.SetLength(typeDescLength);
|
||||||
::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength), buffer.Elements());
|
::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength),
|
||||||
|
buffer.Elements());
|
||||||
nsAutoString typeDesc;
|
nsAutoString typeDesc;
|
||||||
typeDesc.Assign(reinterpret_cast<char16_t*>(buffer.Elements()), typeDescLength);
|
typeDesc.Assign(reinterpret_cast<char16_t*>(buffer.Elements()),
|
||||||
|
typeDescLength);
|
||||||
mimeInfoMac->SetDescription(typeDesc);
|
mimeInfoMac->SetDescription(typeDesc);
|
||||||
::CFRelease(cfTypeDesc);
|
::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];
|
[localPool release];
|
||||||
mimeInfoMac.forget(aMIMEInfo);
|
mimeInfoMac.forget(aMIMEInfo);
|
||||||
|
|
@ -552,14 +580,17 @@ nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found,
|
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme,
|
||||||
|
bool* found,
|
||||||
nsIHandlerInfo** _retval) {
|
nsIHandlerInfo** _retval) {
|
||||||
NS_ASSERTION(!aScheme.IsEmpty(), "No scheme was specified!");
|
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;
|
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_ENSURE_TRUE(handlerInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||||
NS_ADDREF(*_retval = handlerInfo);
|
NS_ADDREF(*_retval = handlerInfo);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsLocalHandlerAppUIKit::LaunchWithURI(nsIURI* aURI,
|
nsLocalHandlerAppUIKit::LaunchWithURI(
|
||||||
mozilla::dom::BrowsingContext* aBrowsingContext) {
|
nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@
|
||||||
#include "nsMIMEInfoUIKit.h"
|
#include "nsMIMEInfoUIKit.h"
|
||||||
|
|
||||||
NS_IMETHODIMP
|
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() {}
|
nsOSHelperAppService::~nsOSHelperAppService() {}
|
||||||
|
|
||||||
nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aProtocolScheme,
|
nsresult nsOSHelperAppService::OSProtocolHandlerExists(
|
||||||
bool* aHandlerExists) {
|
const char* aProtocolScheme, bool* aHandlerExists) {
|
||||||
*aHandlerExists = false;
|
*aHandlerExists = false;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval) {
|
nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme,
|
||||||
|
nsAString& _retval) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme, bool* _retval) {
|
nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
|
||||||
|
const nsACString& aScheme, bool* _retval) {
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t* aPlatformAppPath,
|
nsresult nsOSHelperAppService::GetFileTokenForPath(
|
||||||
nsIFile** aFile) {
|
const char16_t* aPlatformAppPath, nsIFile** aFile) {
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType, const nsACString& aFileExt,
|
nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aType,
|
||||||
|
const nsACString& aFileExt,
|
||||||
nsIMIMEInfo** aMIMEInfo) {
|
nsIMIMEInfo** aMIMEInfo) {
|
||||||
return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo);
|
return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt,
|
||||||
|
aMIMEInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
|
NS_IMETHODIMP nsOSHelperAppService::GetMIMEInfoFromOS(
|
||||||
const nsACString& aFileExt, bool* aFound,
|
const nsACString& aMIMEType, const nsACString& aFileExt, bool* aFound,
|
||||||
nsIMIMEInfo** aMIMEInfo) {
|
nsIMIMEInfo** aMIMEInfo) {
|
||||||
*aMIMEInfo = nullptr;
|
*aMIMEInfo = nullptr;
|
||||||
*aFound = false;
|
*aFound = false;
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme, bool* found,
|
nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString& aScheme,
|
||||||
|
bool* found,
|
||||||
nsIHandlerInfo** _retval) {
|
nsIHandlerInfo** _retval) {
|
||||||
*found = false;
|
*found = false;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@ static void ToolbarThemePrefChanged(const char* aPref, void* aUserInfo);
|
||||||
if (XRE_IsParentProcess()) {
|
if (XRE_IsParentProcess()) {
|
||||||
mozilla::Preferences::RegisterCallbackAndCall(
|
mozilla::Preferences::RegisterCallbackAndCall(
|
||||||
&ToolbarThemePrefChanged,
|
&ToolbarThemePrefChanged,
|
||||||
nsDependentCString(mozilla::StaticPrefs::GetPrefName_browser_theme_toolbar_theme()));
|
nsDependentCString(
|
||||||
|
mozilla::StaticPrefs::GetPrefName_browser_theme_toolbar_theme()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sInstance;
|
return sInstance;
|
||||||
|
|
@ -60,9 +61,10 @@ static void ToolbarThemePrefChanged(const char* aPref, void* aUserInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSSet*)keyPathsForValuesAffectingEffectiveAppearance {
|
+ (NSSet*)keyPathsForValuesAffectingEffectiveAppearance {
|
||||||
// Automatically notify any key-value observers of our effectiveAppearance property whenever the
|
// Automatically notify any key-value observers of our effectiveAppearance
|
||||||
// pref or the NSApp's effectiveAppearance change.
|
// property whenever the pref or the NSApp's effectiveAppearance change.
|
||||||
return [NSSet setWithObjects:@"toolbarTheme", @"_app.effectiveAppearance", nil];
|
return
|
||||||
|
[NSSet setWithObjects:@"toolbarTheme", @"_app.effectiveAppearance", nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSAppearance*)effectiveAppearance {
|
- (NSAppearance*)effectiveAppearance {
|
||||||
|
|
|
||||||
|
|
@ -52,15 +52,16 @@ void SetDesktopImage(nsIFile* aImage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use existing options for this screen
|
// Use existing options for this screen
|
||||||
NSDictionary* screenOptions =
|
NSDictionary* screenOptions = [[NSWorkspace sharedWorkspace]
|
||||||
[[NSWorkspace sharedWorkspace] desktopImageOptionsForScreen:currentScreen];
|
desktopImageOptionsForScreen:currentScreen];
|
||||||
|
|
||||||
NSError* error = nil;
|
NSError* error = nil;
|
||||||
if (![[NSWorkspace sharedWorkspace] setDesktopImageURL:url
|
if (![[NSWorkspace sharedWorkspace] setDesktopImageURL:url
|
||||||
forScreen:currentScreen
|
forScreen:currentScreen
|
||||||
options:screenOptions
|
options:screenOptions
|
||||||
error:&error]) {
|
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)
|
NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
|
||||||
#endif
|
#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) {
|
static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
|
||||||
switch (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion)) {
|
switch (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion)) {
|
||||||
|
|
@ -78,10 +80,11 @@ static OperatingSystem OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
|
||||||
return OperatingSystem::Unknown;
|
return OperatingSystem::Unknown;
|
||||||
}
|
}
|
||||||
// The following three functions are derived from Chromium code
|
// The following three functions are derived from Chromium code
|
||||||
static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort, CFStringRef propertyName) {
|
static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort,
|
||||||
return IORegistryEntrySearchCFProperty(dspPort, kIOServicePlane, propertyName,
|
CFStringRef propertyName) {
|
||||||
kCFAllocatorDefault,
|
return IORegistryEntrySearchCFProperty(
|
||||||
kIORegistryIterateRecursively | kIORegistryIterateParents);
|
dspPort, kIOServicePlane, propertyName, kCFAllocatorDefault,
|
||||||
|
kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t IntValueOfCFData(CFDataRef d) {
|
static uint32_t IntValueOfCFData(CFDataRef d) {
|
||||||
|
|
@ -100,29 +103,33 @@ void GfxInfo::GetDeviceInfo() {
|
||||||
|
|
||||||
CFMutableDictionaryRef pci_dev_dict = IOServiceMatching("IOPCIDevice");
|
CFMutableDictionaryRef pci_dev_dict = IOServiceMatching("IOPCIDevice");
|
||||||
io_iterator_t io_iter;
|
io_iterator_t io_iter;
|
||||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict, &io_iter) !=
|
if (IOServiceGetMatchingServices(kIOMasterPortDefault, pci_dev_dict,
|
||||||
kIOReturnSuccess) {
|
&io_iter) != kIOReturnSuccess) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(false,
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
"Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)");
|
false,
|
||||||
|
"Failed to detect any GPUs (couldn't enumerate IOPCIDevice services)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
io_registry_entry_t entry = IO_OBJECT_NULL;
|
io_registry_entry_t entry = IO_OBJECT_NULL;
|
||||||
while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
|
while ((entry = IOIteratorNext(io_iter)) != IO_OBJECT_NULL) {
|
||||||
constexpr uint32_t kClassCodeDisplayVGA = 0x30000;
|
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) {
|
if (class_code_ref) {
|
||||||
const uint32_t class_code = IntValueOfCFData((CFDataRef)class_code_ref);
|
const uint32_t class_code = IntValueOfCFData((CFDataRef)class_code_ref);
|
||||||
CFRelease(class_code_ref);
|
CFRelease(class_code_ref);
|
||||||
|
|
||||||
if (class_code == kClassCodeDisplayVGA) {
|
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) {
|
if (vendor_id_ref) {
|
||||||
mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
|
mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
|
||||||
"0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
|
"0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
|
||||||
CFRelease(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) {
|
if (device_id_ref) {
|
||||||
mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
|
mAdapterDeviceID[mNumGPUsDetected].AppendPrintf(
|
||||||
"0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
|
"0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
|
||||||
|
|
@ -145,14 +152,15 @@ void GfxInfo::GetDeviceInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CFMutableDictionaryRef agx_dev_dict = IOServiceMatching("AGXAccelerator");
|
CFMutableDictionaryRef agx_dev_dict = IOServiceMatching("AGXAccelerator");
|
||||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict, &io_iter) ==
|
if (IOServiceGetMatchingServices(kIOMasterPortDefault, agx_dev_dict,
|
||||||
kIOReturnSuccess) {
|
&io_iter) == kIOReturnSuccess) {
|
||||||
io_registry_entry_t entry = IO_OBJECT_NULL;
|
io_registry_entry_t entry = IO_OBJECT_NULL;
|
||||||
while ((entry = IOIteratorNext(io_iter)) != 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) {
|
if (vendor_id_ref) {
|
||||||
mAdapterVendorID[mNumGPUsDetected].AppendPrintf("0x%04x",
|
mAdapterVendorID[mNumGPUsDetected].AppendPrintf(
|
||||||
IntValueOfCFData((CFDataRef)vendor_id_ref));
|
"0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
|
||||||
CFRelease(vendor_id_ref);
|
CFRelease(vendor_id_ref);
|
||||||
++mNumGPUsDetected;
|
++mNumGPUsDetected;
|
||||||
}
|
}
|
||||||
|
|
@ -189,22 +197,32 @@ NS_IMETHODIMP
|
||||||
GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
|
GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
|
||||||
|
|
||||||
/* readonly attribute bool HasBattery; */
|
/* 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; */
|
/* readonly attribute DOMString DWriteVersion; */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) { return NS_ERROR_FAILURE; }
|
GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) { return NS_ERROR_FAILURE; }
|
GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
/* readonly attribute DOMString cleartypeParameters; */
|
/* readonly attribute DOMString cleartypeParameters; */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) { return NS_ERROR_FAILURE; }
|
GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
/* readonly attribute DOMString windowProtocol; */
|
/* readonly attribute DOMString windowProtocol; */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) { return NS_ERROR_NOT_IMPLEMENTED; }
|
GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
/* readonly attribute DOMString testType; */
|
/* readonly attribute DOMString testType; */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
@ -348,14 +366,20 @@ GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
|
||||||
|
|
||||||
/* readonly attribute DOMString adapterSubsysID; */
|
/* readonly attribute DOMString adapterSubsysID; */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) { return NS_ERROR_FAILURE; }
|
GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
/* readonly attribute DOMString adapterSubsysID2; */
|
/* readonly attribute DOMString adapterSubsysID2; */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) { return NS_ERROR_FAILURE; }
|
GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) { return NS_ERROR_NOT_IMPLEMENTED; }
|
GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
/* readonly attribute boolean isGPU2Active; */
|
/* readonly attribute boolean isGPU2Active; */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
@ -372,60 +396,70 @@ void GfxInfo::AddCrashReportAnnotations() {
|
||||||
GetAdapterDriverVersion(driverVersion);
|
GetAdapterDriverVersion(driverVersion);
|
||||||
CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
|
CopyUTF16toUTF8(driverVersion, narrowDriverVersion);
|
||||||
|
|
||||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID, narrowVendorID);
|
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
|
||||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID, narrowDeviceID);
|
narrowVendorID);
|
||||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDriverVersion,
|
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
|
||||||
narrowDriverVersion);
|
narrowDeviceID);
|
||||||
|
CrashReporter::AnnotateCrashReport(
|
||||||
|
CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't support checking driver versions on Mac.
|
// We don't support checking driver versions on Mac.
|
||||||
#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \
|
#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, device, features, blockOn, ruleId) \
|
||||||
APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, DRIVER_COMPARISON_IGNORED, \
|
APPEND_TO_DRIVER_BLOCKLIST(os, device, features, blockOn, \
|
||||||
V(0, 0, 0, 0), ruleId, "")
|
DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), ruleId, \
|
||||||
|
"")
|
||||||
|
|
||||||
const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
|
const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
|
||||||
if (!sDriverInfo->Length()) {
|
if (!sDriverInfo->Length()) {
|
||||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||||
OperatingSystem::OSX, DeviceFamily::RadeonX1000, nsIGfxInfo::FEATURE_OPENGL_LAYERS,
|
OperatingSystem::OSX, DeviceFamily::RadeonX1000,
|
||||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
|
nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||||
|
"FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
|
||||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||||
OperatingSystem::OSX, DeviceFamily::Geforce7300GT, nsIGfxInfo::FEATURE_WEBGL_OPENGL,
|
OperatingSystem::OSX, DeviceFamily::Geforce7300GT,
|
||||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
|
nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
|
"FEATURE_FAILURE_MAC_7300_NO_WEBGL");
|
||||||
nsIGfxInfo::FEATURE_GL_SWIZZLE,
|
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
OperatingSystem::OSX, DeviceFamily::IntelHDGraphicsToIvyBridge,
|
||||||
"FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
|
nsIGfxInfo::FEATURE_GL_SWIZZLE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||||
// We block texture swizzling everwhere on mac because it's broken in some configurations
|
"FEATURE_FAILURE_MAC_INTELHD4000_NO_SWIZZLE");
|
||||||
// and we want to support GPU switching.
|
// 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(
|
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||||
OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_GL_SWIZZLE,
|
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.
|
// Older generation Intel devices do not perform well with WebRender.
|
||||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||||
OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked, nsIGfxInfo::FEATURE_WEBRENDER,
|
OperatingSystem::OSX, DeviceFamily::IntelWebRenderBlocked,
|
||||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
|
nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||||
|
"FEATURE_FAILURE_INTEL_GEN5_OR_OLDER");
|
||||||
|
|
||||||
// Intel HD3000 disabled due to bug 1661505
|
// Intel HD3000 disabled due to bug 1661505
|
||||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||||
OperatingSystem::OSX, DeviceFamily::IntelSandyBridge, nsIGfxInfo::FEATURE_WEBRENDER,
|
OperatingSystem::OSX, DeviceFamily::IntelSandyBridge,
|
||||||
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
|
nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||||
|
"FEATURE_FAILURE_INTEL_MAC_HD3000_NO_WEBRENDER");
|
||||||
|
|
||||||
// wgpu doesn't safely support OOB behavior on Metal yet.
|
// wgpu doesn't safely support OOB behavior on Metal yet.
|
||||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX, DeviceFamily::All,
|
IMPLEMENT_MAC_DRIVER_BLOCKLIST(
|
||||||
nsIGfxInfo::FEATURE_WEBGPU, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
OperatingSystem::OSX, DeviceFamily::All, nsIGfxInfo::FEATURE_WEBGPU,
|
||||||
"FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS");
|
nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
|
||||||
|
"FEATURE_FAILURE_MAC_WGPU_NO_METAL_BOUNDS_CHECKS");
|
||||||
}
|
}
|
||||||
return *sDriverInfo;
|
return *sDriverInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
OperatingSystem GfxInfo::GetOperatingSystem() { return OSXVersionToOperatingSystem(mOSXVersion); }
|
OperatingSystem GfxInfo::GetOperatingSystem() {
|
||||||
|
return OSXVersionToOperatingSystem(mOSXVersion);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
|
nsresult GfxInfo::GetFeatureStatusImpl(
|
||||||
nsAString& aSuggestedDriverVersion,
|
int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
|
||||||
const nsTArray<GfxDriverInfo>& aDriverInfo,
|
const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
|
||||||
nsACString& aFailureId,
|
OperatingSystem* aOS /* = nullptr */) {
|
||||||
OperatingSystem* aOS /* = nullptr */) {
|
|
||||||
NS_ENSURE_ARG_POINTER(aStatus);
|
NS_ENSURE_ARG_POINTER(aStatus);
|
||||||
aSuggestedDriverVersion.SetIsVoid(true);
|
aSuggestedDriverVersion.SetIsVoid(true);
|
||||||
*aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
|
*aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
|
||||||
|
|
@ -436,7 +470,8 @@ nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
|
||||||
return NS_OK;
|
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 (!aDriverInfo.Length()) {
|
||||||
if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
|
if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
|
||||||
// See bug 1249659
|
// See bug 1249659
|
||||||
|
|
@ -460,8 +495,8 @@ nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t* aStatus,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo,
|
return GfxInfoBase::GetFeatureStatusImpl(
|
||||||
aFailureId, &os);
|
aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,20 @@
|
||||||
+ (NSImage*)iconImageFromImageContainer:(imgIContainer*)aImage
|
+ (NSImage*)iconImageFromImageContainer:(imgIContainer*)aImage
|
||||||
withSize:(NSSize)aSize
|
withSize:(NSSize)aSize
|
||||||
presContext:(const nsPresContext*)aPresContext
|
presContext:(const nsPresContext*)aPresContext
|
||||||
computedStyle:(const mozilla::ComputedStyle*)aComputedStyle
|
computedStyle:
|
||||||
|
(const mozilla::ComputedStyle*)aComputedStyle
|
||||||
scaleFactor:(CGFloat)aScaleFactor {
|
scaleFactor:(CGFloat)aScaleFactor {
|
||||||
bool isEntirelyBlack = false;
|
bool isEntirelyBlack = false;
|
||||||
NSImage* retainedImage = nil;
|
NSImage* retainedImage = nil;
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
if (aScaleFactor != 0.0f) {
|
if (aScaleFactor != 0.0f) {
|
||||||
rv = nsCocoaUtils::CreateNSImageFromImageContainer(aImage, imgIContainer::FRAME_CURRENT,
|
rv = nsCocoaUtils::CreateNSImageFromImageContainer(
|
||||||
aPresContext, aComputedStyle, &retainedImage,
|
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle,
|
||||||
aScaleFactor, &isEntirelyBlack);
|
&retainedImage, aScaleFactor, &isEntirelyBlack);
|
||||||
} else {
|
} else {
|
||||||
rv = nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
|
rv = nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
|
||||||
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle, &retainedImage,
|
aImage, imgIContainer::FRAME_CURRENT, aPresContext, aComputedStyle,
|
||||||
&isEntirelyBlack);
|
&retainedImage, &isEntirelyBlack);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSImage* image = [retainedImage autorelease];
|
NSImage* image = [retainedImage autorelease];
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,8 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
|
||||||
withAppearance:(NSAppearance*)aAppearance
|
withAppearance:(NSAppearance*)aAppearance
|
||||||
asContextMenu:(BOOL)aIsContextMenu {
|
asContextMenu:(BOOL)aIsContextMenu {
|
||||||
MOZ_RELEASE_ASSERT(!mPendingOpening,
|
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.");
|
"for this one to open or cancel the request.");
|
||||||
|
|
||||||
NSInteger handle = ++mLastHandle;
|
NSInteger handle = ++mLastHandle;
|
||||||
|
|
@ -134,33 +135,36 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
|
||||||
asContextMenu:(BOOL)aIsContextMenu {
|
asContextMenu:(BOOL)aIsContextMenu {
|
||||||
// There are multiple ways to display an NSMenu as a context menu.
|
// 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
|
// 1. We can return the NSMenu from -[ChildView menuForEvent:] and the NSView
|
||||||
// us.
|
// will open it for us.
|
||||||
// 2. We can call +[NSMenu popUpContextMenu:withEvent:forView:] inside a mouseDown handler with a
|
// 2. We can call +[NSMenu popUpContextMenu:withEvent:forView:] inside a
|
||||||
// real mouse down event.
|
// mouseDown handler with a real mouse down event.
|
||||||
// 3. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at a later time, with a real
|
// 3. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at a later
|
||||||
// mouse event that we stored earlier.
|
// time, with a real mouse event that we stored earlier.
|
||||||
// 4. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at any time, with a synthetic
|
// 4. We can call +[NSMenu popUpContextMenu:withEvent:forView:] at any time,
|
||||||
// mouse event that we create just for that purpose.
|
// 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
|
// 5. We can call -[NSMenu popUpMenuPositioningItem:atLocation:inView:] and
|
||||||
// position, not an event.
|
// 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
|
// 1-4 look the same, 5 looks different: 5 is made for use with NSPopUpButton,
|
||||||
// item needs to be shown at a specific position. If a tall menu is opened with a position close
|
// where the selected item needs to be shown at a specific position. If a tall
|
||||||
// to the bottom edge of the screen, 5 results in a cropped menu with scroll arrows, even if the
|
// menu is opened with a position close to the bottom edge of the screen, 5
|
||||||
// entire menu would fit on the screen, due to the positioning constraint.
|
// results in a cropped menu with scroll arrows, even if the entire menu would
|
||||||
// 1-2 only work if the menu contents are known synchronously during the call to menuForEvent or
|
// 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.
|
// during the mouseDown event handler.
|
||||||
// NativeMenuMac::ShowAsContextMenu can be called at any time. It could be called during a
|
// NativeMenuMac::ShowAsContextMenu can be called at any time. It could be
|
||||||
// menuForEvent call (during a "contextmenu" event handler), or during a mouseDown handler, or at
|
// called during a menuForEvent call (during a "contextmenu" event handler),
|
||||||
// a later time.
|
// or during a mouseDown handler, or at a later time. The code below uses
|
||||||
// The code below uses option 4 as the preferred option for context menus because it's the
|
// 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
|
// simplest: It works in all scenarios and it doesn't have the drawbacks of
|
||||||
// that aren't context menus and that should be positioned as close as possible to the given
|
// option 5. For popups that aren't context menus and that should be
|
||||||
// screen position, we use option 5.
|
// positioned as close as possible to the given screen position, we use
|
||||||
|
// option 5.
|
||||||
|
|
||||||
if (aAppearance) {
|
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()) {
|
if (nsCocoaFeatures::OnBigSurOrLater()) {
|
||||||
#else
|
#else
|
||||||
if (@available(macOS 11.0, *)) {
|
if (@available(macOS 11.0, *)) {
|
||||||
|
|
@ -174,18 +178,21 @@ static BOOL sNeedToUnwindForMenuClosing = NO;
|
||||||
|
|
||||||
if (aView) {
|
if (aView) {
|
||||||
NSWindow* window = aView.window;
|
NSWindow* window = aView.window;
|
||||||
NSPoint locationInWindow = nsCocoaUtils::ConvertPointFromScreen(window, aPosition);
|
NSPoint locationInWindow =
|
||||||
|
nsCocoaUtils::ConvertPointFromScreen(window, aPosition);
|
||||||
if (aIsContextMenu) {
|
if (aIsContextMenu) {
|
||||||
// Create a synthetic event at the right location and open the menu [option 4].
|
// Create a synthetic event at the right location and open the menu
|
||||||
NSEvent* event = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
|
// [option 4].
|
||||||
location:locationInWindow
|
NSEvent* event =
|
||||||
modifierFlags:0
|
[NSEvent mouseEventWithType:NSEventTypeRightMouseDown
|
||||||
timestamp:NSProcessInfo.processInfo.systemUptime
|
location:locationInWindow
|
||||||
windowNumber:window.windowNumber
|
modifierFlags:0
|
||||||
context:nil
|
timestamp:NSProcessInfo.processInfo.systemUptime
|
||||||
eventNumber:0
|
windowNumber:window.windowNumber
|
||||||
clickCount:1
|
context:nil
|
||||||
pressure:0.0f];
|
eventNumber:0
|
||||||
|
clickCount:1
|
||||||
|
pressure:0.0f];
|
||||||
[NSMenu popUpContextMenu:aMenu withEvent:event forView:aView];
|
[NSMenu popUpContextMenu:aMenu withEvent:event forView:aView];
|
||||||
} else {
|
} else {
|
||||||
// For popups which are not context menus, we open the menu using [option
|
// 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
|
// 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
|
// prefer option 5 over option 4 so that the menu doesn't get flipped if
|
||||||
// space is tight.
|
// space is tight.
|
||||||
NSPoint locationInView = [aView convertPoint:locationInWindow fromView:nil];
|
NSPoint locationInView = [aView convertPoint:locationInWindow
|
||||||
[aMenu popUpMenuPositioningItem:nil atLocation:locationInView inView:aView];
|
fromView:nil];
|
||||||
|
[aMenu popUpMenuPositioningItem:nil
|
||||||
|
atLocation:locationInView
|
||||||
|
inView:aView];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Open the menu using popUpMenuPositioningItem:atLocation:inView: [option 5].
|
// Open the menu using popUpMenuPositioningItem:atLocation:inView: [option
|
||||||
// This is not preferred, because it positions the menu differently from how a native context
|
// 5]. This is not preferred, because it positions the menu differently from
|
||||||
// menu would be positioned; it enforces aPosition for the top left corner even if this
|
// how a native context menu would be positioned; it enforces aPosition for
|
||||||
// means that the menu will be displayed in a clipped fashion with scroll arrows.
|
// 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];
|
[aMenu popUpMenuPositioningItem:nil atLocation:aPosition inView:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,9 @@ static MediaControlKey ToMediaControlKey(int aKeyCode) {
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace widget {
|
namespace widget {
|
||||||
|
|
||||||
bool MediaHardwareKeysEventSourceMac::IsOpened() const { return mEventTap && mEventTapSource; }
|
bool MediaHardwareKeysEventSourceMac::IsOpened() const {
|
||||||
|
return mEventTap && mEventTapSource;
|
||||||
|
}
|
||||||
|
|
||||||
bool MediaHardwareKeysEventSourceMac::Open() {
|
bool MediaHardwareKeysEventSourceMac::Open() {
|
||||||
LOG("Open MediaHardwareKeysEventSourceMac");
|
LOG("Open MediaHardwareKeysEventSourceMac");
|
||||||
|
|
@ -89,22 +91,24 @@ bool MediaHardwareKeysEventSourceMac::StartEventTap() {
|
||||||
MOZ_ASSERT(!mEventTapSource);
|
MOZ_ASSERT(!mEventTapSource);
|
||||||
|
|
||||||
// Add an event tap to intercept the system defined media key events.
|
// Add an event tap to intercept the system defined media key events.
|
||||||
mEventTap =
|
mEventTap = CGEventTapCreate(
|
||||||
CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
|
kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
|
||||||
CGEventMaskBit(NX_SYSDEFINED), EventTapCallback, this);
|
CGEventMaskBit(NX_SYSDEFINED), EventTapCallback, this);
|
||||||
if (!mEventTap) {
|
if (!mEventTap) {
|
||||||
LOG("Fail to create event tap");
|
LOG("Fail to create event tap");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mEventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mEventTap, 0);
|
mEventTapSource =
|
||||||
|
CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mEventTap, 0);
|
||||||
if (!mEventTapSource) {
|
if (!mEventTapSource) {
|
||||||
LOG("Fail to create an event tap source.");
|
LOG("Fail to create an event tap source.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Add an event tap source to current loop");
|
LOG("Add an event tap source to current loop");
|
||||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventTapSource, kCFRunLoopCommonModes);
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventTapSource,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,18 +119,20 @@ void MediaHardwareKeysEventSourceMac::StopEventTap() {
|
||||||
mEventTap = nullptr;
|
mEventTap = nullptr;
|
||||||
}
|
}
|
||||||
if (mEventTapSource) {
|
if (mEventTapSource) {
|
||||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventTapSource, kCFRunLoopCommonModes);
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventTapSource,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
CFRelease(mEventTapSource);
|
CFRelease(mEventTapSource);
|
||||||
mEventTapSource = nullptr;
|
mEventTapSource = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy proxy,
|
CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(
|
||||||
CGEventType type, CGEventRef event,
|
CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) {
|
||||||
void* refcon) {
|
|
||||||
// Re-enable event tap when receiving disabled events.
|
// Re-enable event tap when receiving disabled events.
|
||||||
MediaHardwareKeysEventSourceMac* source = static_cast<MediaHardwareKeysEventSourceMac*>(refcon);
|
MediaHardwareKeysEventSourceMac* source =
|
||||||
if (type == kCGEventTapDisabledByUserInput || type == kCGEventTapDisabledByTimeout) {
|
static_cast<MediaHardwareKeysEventSourceMac*>(refcon);
|
||||||
|
if (type == kCGEventTapDisabledByUserInput ||
|
||||||
|
type == kCGEventTapDisabledByTimeout) {
|
||||||
MOZ_ASSERT(source->mEventTap);
|
MOZ_ASSERT(source->mEventTap);
|
||||||
CGEventTapEnable(source->mEventTap, true);
|
CGEventTapEnable(source->mEventTap, true);
|
||||||
return event;
|
return event;
|
||||||
|
|
@ -151,8 +157,9 @@ CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy pro
|
||||||
// - keyRepeat = (keyFlags & 0x1);
|
// - keyRepeat = (keyFlags & 0x1);
|
||||||
const NSInteger data1 = [nsEvent data1];
|
const NSInteger data1 = [nsEvent data1];
|
||||||
int keyCode = (data1 & 0xFFFF0000) >> 16;
|
int keyCode = (data1 & 0xFFFF0000) >> 16;
|
||||||
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_NEXT && keyCode != NX_KEYTYPE_PREVIOUS &&
|
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_NEXT &&
|
||||||
keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND) {
|
keyCode != NX_KEYTYPE_PREVIOUS && keyCode != NX_KEYTYPE_FAST &&
|
||||||
|
keyCode != NX_KEYTYPE_REWIND) {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,7 +180,8 @@ CGEventRef MediaHardwareKeysEventSourceMac::EventTapCallback(CGEventTapProxy pro
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG2("Get media key %s", source, ToMediaControlKeyStr(keyCode));
|
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)));
|
(*iter)->OnActionPerformed(MediaControlAction(ToMediaControlKey(keyCode)));
|
||||||
}
|
}
|
||||||
return event;
|
return event;
|
||||||
|
|
|
||||||
|
|
@ -13,39 +13,45 @@ using namespace mozilla::dom;
|
||||||
|
|
||||||
// avoid redefined macro in unified build
|
// avoid redefined macro in unified build
|
||||||
#undef LOG
|
#undef LOG
|
||||||
#define LOG(msg, ...) \
|
#define LOG(msg, ...) \
|
||||||
MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
|
MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
|
||||||
("MediaHardwareKeysEventSourceMacMediaCenter=%p, " msg, this, ##__VA_ARGS__))
|
("MediaHardwareKeysEventSourceMacMediaCenter=%p, " msg, this, \
|
||||||
|
##__VA_ARGS__))
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace widget {
|
namespace widget {
|
||||||
|
|
||||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayPauseHandler() {
|
MediaCenterEventHandler
|
||||||
|
MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayPauseHandler() {
|
||||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||||
center.playbackState = center.playbackState == MPNowPlayingPlaybackStatePlaying
|
center.playbackState =
|
||||||
? MPNowPlayingPlaybackStatePaused
|
center.playbackState == MPNowPlayingPlaybackStatePlaying
|
||||||
: MPNowPlayingPlaybackStatePlaying;
|
? MPNowPlayingPlaybackStatePaused
|
||||||
|
: MPNowPlayingPlaybackStatePlaying;
|
||||||
HandleEvent(MediaControlKey::Playpause);
|
HandleEvent(MediaControlKey::Playpause);
|
||||||
return MPRemoteCommandHandlerStatusSuccess;
|
return MPRemoteCommandHandlerStatusSuccess;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreateNextTrackHandler() {
|
MediaCenterEventHandler
|
||||||
|
MediaHardwareKeysEventSourceMacMediaCenter::CreateNextTrackHandler() {
|
||||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||||
HandleEvent(MediaControlKey::Nexttrack);
|
HandleEvent(MediaControlKey::Nexttrack);
|
||||||
return MPRemoteCommandHandlerStatusSuccess;
|
return MPRemoteCommandHandlerStatusSuccess;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePreviousTrackHandler() {
|
MediaCenterEventHandler
|
||||||
|
MediaHardwareKeysEventSourceMacMediaCenter::CreatePreviousTrackHandler() {
|
||||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||||
HandleEvent(MediaControlKey::Previoustrack);
|
HandleEvent(MediaControlKey::Previoustrack);
|
||||||
return MPRemoteCommandHandlerStatusSuccess;
|
return MPRemoteCommandHandlerStatusSuccess;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHandler() {
|
MediaCenterEventHandler
|
||||||
|
MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHandler() {
|
||||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||||
if (center.playbackState != MPNowPlayingPlaybackStatePlaying) {
|
if (center.playbackState != MPNowPlayingPlaybackStatePlaying) {
|
||||||
|
|
@ -56,7 +62,8 @@ MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHa
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseHandler() {
|
MediaCenterEventHandler
|
||||||
|
MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseHandler() {
|
||||||
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
|
||||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||||
if (center.playbackState != MPNowPlayingPlaybackStatePaused) {
|
if (center.playbackState != MPNowPlayingPlaybackStatePaused) {
|
||||||
|
|
@ -67,7 +74,8 @@ MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseH
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaHardwareKeysEventSourceMacMediaCenter::MediaHardwareKeysEventSourceMacMediaCenter() {
|
MediaHardwareKeysEventSourceMacMediaCenter::
|
||||||
|
MediaHardwareKeysEventSourceMacMediaCenter() {
|
||||||
mPlayPauseHandler = CreatePlayPauseHandler();
|
mPlayPauseHandler = CreatePlayPauseHandler();
|
||||||
mNextTrackHandler = CreateNextTrackHandler();
|
mNextTrackHandler = CreateNextTrackHandler();
|
||||||
mPreviousTrackHandler = CreatePreviousTrackHandler();
|
mPreviousTrackHandler = CreatePreviousTrackHandler();
|
||||||
|
|
@ -76,7 +84,8 @@ MediaHardwareKeysEventSourceMacMediaCenter::MediaHardwareKeysEventSourceMacMedia
|
||||||
LOG("Create MediaHardwareKeysEventSourceMacMediaCenter");
|
LOG("Create MediaHardwareKeysEventSourceMacMediaCenter");
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaHardwareKeysEventSourceMacMediaCenter::~MediaHardwareKeysEventSourceMacMediaCenter() {
|
MediaHardwareKeysEventSourceMacMediaCenter::
|
||||||
|
~MediaHardwareKeysEventSourceMacMediaCenter() {
|
||||||
LOG("Destroy MediaHardwareKeysEventSourceMacMediaCenter");
|
LOG("Destroy MediaHardwareKeysEventSourceMacMediaCenter");
|
||||||
EndListeningForEvents();
|
EndListeningForEvents();
|
||||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||||
|
|
@ -86,13 +95,15 @@ MediaHardwareKeysEventSourceMacMediaCenter::~MediaHardwareKeysEventSourceMacMedi
|
||||||
void MediaHardwareKeysEventSourceMacMediaCenter::BeginListeningForEvents() {
|
void MediaHardwareKeysEventSourceMacMediaCenter::BeginListeningForEvents() {
|
||||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||||
center.playbackState = MPNowPlayingPlaybackStatePlaying;
|
center.playbackState = MPNowPlayingPlaybackStatePlaying;
|
||||||
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
|
MPRemoteCommandCenter* commandCenter =
|
||||||
|
[MPRemoteCommandCenter sharedCommandCenter];
|
||||||
commandCenter.togglePlayPauseCommand.enabled = true;
|
commandCenter.togglePlayPauseCommand.enabled = true;
|
||||||
[commandCenter.togglePlayPauseCommand addTargetWithHandler:mPlayPauseHandler];
|
[commandCenter.togglePlayPauseCommand addTargetWithHandler:mPlayPauseHandler];
|
||||||
commandCenter.nextTrackCommand.enabled = true;
|
commandCenter.nextTrackCommand.enabled = true;
|
||||||
[commandCenter.nextTrackCommand addTargetWithHandler:mNextTrackHandler];
|
[commandCenter.nextTrackCommand addTargetWithHandler:mNextTrackHandler];
|
||||||
commandCenter.previousTrackCommand.enabled = true;
|
commandCenter.previousTrackCommand.enabled = true;
|
||||||
[commandCenter.previousTrackCommand addTargetWithHandler:mPreviousTrackHandler];
|
[commandCenter.previousTrackCommand
|
||||||
|
addTargetWithHandler:mPreviousTrackHandler];
|
||||||
commandCenter.playCommand.enabled = true;
|
commandCenter.playCommand.enabled = true;
|
||||||
[commandCenter.playCommand addTargetWithHandler:mPlayHandler];
|
[commandCenter.playCommand addTargetWithHandler:mPlayHandler];
|
||||||
commandCenter.pauseCommand.enabled = true;
|
commandCenter.pauseCommand.enabled = true;
|
||||||
|
|
@ -103,7 +114,8 @@ void MediaHardwareKeysEventSourceMacMediaCenter::EndListeningForEvents() {
|
||||||
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
|
||||||
center.playbackState = MPNowPlayingPlaybackStatePaused;
|
center.playbackState = MPNowPlayingPlaybackStatePaused;
|
||||||
center.nowPlayingInfo = nil;
|
center.nowPlayingInfo = nil;
|
||||||
MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
|
MPRemoteCommandCenter* commandCenter =
|
||||||
|
[MPRemoteCommandCenter sharedCommandCenter];
|
||||||
commandCenter.togglePlayPauseCommand.enabled = false;
|
commandCenter.togglePlayPauseCommand.enabled = false;
|
||||||
[commandCenter.togglePlayPauseCommand removeTarget:nil];
|
[commandCenter.togglePlayPauseCommand removeTarget:nil];
|
||||||
commandCenter.nextTrackCommand.enabled = false;
|
commandCenter.nextTrackCommand.enabled = false;
|
||||||
|
|
@ -131,9 +143,12 @@ void MediaHardwareKeysEventSourceMacMediaCenter::Close() {
|
||||||
MediaControlKeySource::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) {
|
for (auto iter = mListeners.begin(); iter != mListeners.end(); ++iter) {
|
||||||
(*iter)->OnActionPerformed(MediaControlAction(aEvent));
|
(*iter)->OnActionPerformed(MediaControlAction(aEvent));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,16 @@ void NativeKeyBindings::Shutdown() {
|
||||||
|
|
||||||
NativeKeyBindings::NativeKeyBindings() {}
|
NativeKeyBindings::NativeKeyBindings() {}
|
||||||
|
|
||||||
inline objc_selector* ToObjcSelectorPtr(SEL aSel) { return reinterpret_cast<objc_selector*>(aSel); }
|
inline objc_selector* ToObjcSelectorPtr(SEL aSel) {
|
||||||
#define SEL_TO_COMMAND(aSel, aCommand) \
|
return reinterpret_cast<objc_selector*>(aSel);
|
||||||
mSelectorToCommand.InsertOrUpdate(ToObjcSelectorPtr(@selector(aSel)), aCommand)
|
}
|
||||||
|
#define SEL_TO_COMMAND(aSel, aCommand) \
|
||||||
|
mSelectorToCommand.InsertOrUpdate(ToObjcSelectorPtr(@selector(aSel)), \
|
||||||
|
aCommand)
|
||||||
|
|
||||||
void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
|
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
|
// Many selectors have a one-to-one mapping to a Gecko command. Those mappings
|
||||||
// are registered in mSelectorToCommand.
|
// 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
|
// TODO: deleteTo* selectors are also supposed to add text to a kill buffer
|
||||||
SEL_TO_COMMAND(deleteToBeginningOfLine:, Command::DeleteToBeginningOfLine);
|
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(deleteToEndOfLine:, Command::DeleteToEndOfLine);
|
||||||
SEL_TO_COMMAND(deleteToEndOfParagraph:, Command::DeleteToEndOfLine);
|
SEL_TO_COMMAND(deleteToEndOfParagraph:, Command::DeleteToEndOfLine);
|
||||||
// SEL_TO_COMMAND(deleteToMark:, );
|
// SEL_TO_COMMAND(deleteToMark:, );
|
||||||
|
|
@ -119,26 +124,34 @@ void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
|
||||||
SEL_TO_COMMAND(moveForwardAndModifySelection:, Command::SelectCharNext);
|
SEL_TO_COMMAND(moveForwardAndModifySelection:, Command::SelectCharNext);
|
||||||
SEL_TO_COMMAND(moveLeft:, Command::CharPrevious);
|
SEL_TO_COMMAND(moveLeft:, Command::CharPrevious);
|
||||||
SEL_TO_COMMAND(moveLeftAndModifySelection:, Command::SelectCharPrevious);
|
SEL_TO_COMMAND(moveLeftAndModifySelection:, Command::SelectCharPrevious);
|
||||||
SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:, Command::SelectBeginLine);
|
SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
|
||||||
SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, Command::SelectEndLine);
|
Command::SelectBeginLine);
|
||||||
|
SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:,
|
||||||
|
Command::SelectEndLine);
|
||||||
SEL_TO_COMMAND(moveRight:, Command::CharNext);
|
SEL_TO_COMMAND(moveRight:, Command::CharNext);
|
||||||
SEL_TO_COMMAND(moveRightAndModifySelection:, Command::SelectCharNext);
|
SEL_TO_COMMAND(moveRightAndModifySelection:, Command::SelectCharNext);
|
||||||
SEL_TO_COMMAND(moveToBeginningOfDocument:, Command::MoveTop);
|
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(moveToBeginningOfLine:, Command::BeginLine);
|
||||||
SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:, Command::SelectBeginLine);
|
SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
|
||||||
|
Command::SelectBeginLine);
|
||||||
SEL_TO_COMMAND(moveToBeginningOfParagraph:, Command::BeginLine);
|
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(moveToEndOfDocument:, Command::MoveBottom);
|
||||||
SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, Command::SelectBottom);
|
SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, Command::SelectBottom);
|
||||||
SEL_TO_COMMAND(moveToEndOfLine:, Command::EndLine);
|
SEL_TO_COMMAND(moveToEndOfLine:, Command::EndLine);
|
||||||
SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, Command::SelectEndLine);
|
SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, Command::SelectEndLine);
|
||||||
SEL_TO_COMMAND(moveToEndOfParagraph:, Command::EndLine);
|
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(moveToLeftEndOfLine:, Command::BeginLine);
|
||||||
SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:, Command::SelectBeginLine);
|
SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:,
|
||||||
|
Command::SelectBeginLine);
|
||||||
SEL_TO_COMMAND(moveToRightEndOfLine:, Command::EndLine);
|
SEL_TO_COMMAND(moveToRightEndOfLine:, Command::EndLine);
|
||||||
SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, Command::SelectEndLine);
|
SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:,
|
||||||
|
Command::SelectEndLine);
|
||||||
if (aType == NativeKeyBindingsType::SingleLineEditor) {
|
if (aType == NativeKeyBindingsType::SingleLineEditor) {
|
||||||
SEL_TO_COMMAND(moveUp:, Command::BeginLine);
|
SEL_TO_COMMAND(moveUp:, Command::BeginLine);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -146,7 +159,8 @@ void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
|
||||||
}
|
}
|
||||||
SEL_TO_COMMAND(moveUpAndModifySelection:, Command::SelectLinePrevious);
|
SEL_TO_COMMAND(moveUpAndModifySelection:, Command::SelectLinePrevious);
|
||||||
SEL_TO_COMMAND(moveWordBackward:, Command::WordPrevious);
|
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(moveWordForward:, Command::WordNext);
|
||||||
SEL_TO_COMMAND(moveWordForwardAndModifySelection:, Command::SelectWordNext);
|
SEL_TO_COMMAND(moveWordForwardAndModifySelection:, Command::SelectWordNext);
|
||||||
SEL_TO_COMMAND(moveWordLeft:, Command::WordPrevious);
|
SEL_TO_COMMAND(moveWordLeft:, Command::WordPrevious);
|
||||||
|
|
@ -191,7 +205,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
||||||
MOZ_ASSERT(!aEvent.mFlags.mIsSynthesizedForTests);
|
MOZ_ASSERT(!aEvent.mFlags.mIsSynthesizedForTests);
|
||||||
MOZ_ASSERT(aCommands.IsEmpty());
|
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
|
// Recover the current event, which should always be the key down we are
|
||||||
// responding to.
|
// responding to.
|
||||||
|
|
@ -200,7 +215,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
||||||
|
|
||||||
if (!cocoaEvent || [cocoaEvent type] != NSEventTypeKeyDown) {
|
if (!cocoaEvent || [cocoaEvent type] != NSEventTypeKeyDown) {
|
||||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||||
("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event", this));
|
("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event",
|
||||||
|
this));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +226,8 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
||||||
NSEvent* originalEvent = cocoaEvent;
|
NSEvent* originalEvent = cocoaEvent;
|
||||||
|
|
||||||
// TODO: Use KeyNameIndex rather than legacy keyCode.
|
// 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;
|
uint32_t remappedCocoaKeyCode = 0;
|
||||||
switch (remappedGeckoKeyCode) {
|
switch (remappedGeckoKeyCode) {
|
||||||
case NS_VK_UP:
|
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");
|
MOZ_ASSERT_UNREACHABLE("Add a case for the new remapped key");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unichar ch = nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(remappedGeckoKeyCode);
|
unichar ch =
|
||||||
NSString* chars = [[[NSString alloc] initWithCharacters:&ch length:1] autorelease];
|
nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(remappedGeckoKeyCode);
|
||||||
|
NSString* chars = [[[NSString alloc] initWithCharacters:&ch
|
||||||
|
length:1] autorelease];
|
||||||
cocoaEvent = [NSEvent keyEventWithType:[originalEvent type]
|
cocoaEvent = [NSEvent keyEventWithType:[originalEvent type]
|
||||||
location:[originalEvent locationInWindow]
|
location:[originalEvent locationInWindow]
|
||||||
modifierFlags:[originalEvent modifierFlags]
|
modifierFlags:[originalEvent modifierFlags]
|
||||||
|
|
@ -272,11 +291,12 @@ void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
||||||
LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommands");
|
LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommands");
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeKeyBindings::AppendEditCommandsForSelector(objc_selector* aSelector,
|
void NativeKeyBindings::AppendEditCommandsForSelector(
|
||||||
nsTArray<CommandInt>& aCommands) const {
|
objc_selector* aSelector, nsTArray<CommandInt>& aCommands) const {
|
||||||
// Try to find a simple mapping in the hashtable
|
// Try to find a simple mapping in the hashtable
|
||||||
Command geckoCommand = Command::DoNothing;
|
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));
|
aCommands.AppendElement(static_cast<CommandInt>(geckoCommand));
|
||||||
} else if (aSelector == ToObjcSelectorPtr(@selector(selectLine:))) {
|
} else if (aSelector == ToObjcSelectorPtr(@selector(selectLine:))) {
|
||||||
// This is functional, but Cocoa's version is direction-less in that
|
// 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()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,10 +334,9 @@ void NativeKeyBindings::LogEditCommands(const nsTArray<CommandInt>& aCommands,
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
void NativeKeyBindings::GetEditCommandsForTests(
|
||||||
const WidgetKeyboardEvent& aEvent,
|
NativeKeyBindingsType aType, const WidgetKeyboardEvent& aEvent,
|
||||||
const Maybe<WritingMode>& aWritingMode,
|
const Maybe<WritingMode>& aWritingMode, nsTArray<CommandInt>& aCommands) {
|
||||||
nsTArray<CommandInt>& aCommands) {
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aEvent.IsTrusted());
|
MOZ_DIAGNOSTIC_ASSERT(aEvent.IsTrusted());
|
||||||
|
|
||||||
// The following mapping is checked on Big Sur. Some of them are defined in:
|
// 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)) {
|
if (NS_WARN_IF(!instance)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (aWritingMode.isSome() ? aEvent.GetRemappedKeyNameIndex(aWritingMode.ref())
|
switch (aWritingMode.isSome()
|
||||||
: aEvent.mKeyNameIndex) {
|
? aEvent.GetRemappedKeyNameIndex(aWritingMode.ref())
|
||||||
|
: aEvent.mKeyNameIndex) {
|
||||||
case KEY_NAME_INDEX_USE_STRING:
|
case KEY_NAME_INDEX_USE_STRING:
|
||||||
if (!aEvent.IsControl() || aEvent.IsAlt() || aEvent.IsMeta()) {
|
if (!aEvent.IsControl() || aEvent.IsAlt() || aEvent.IsMeta()) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -337,21 +358,23 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift()
|
!aEvent.IsShift()
|
||||||
? ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:))
|
? ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:))
|
||||||
: ToObjcSelectorPtr(@selector(moveToBeginningOfParagraphAndModifySelection:)),
|
: ToObjcSelectorPtr(@selector(
|
||||||
|
moveToBeginningOfParagraphAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'B':
|
case 'B':
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveBackward:))
|
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveBackward:))
|
||||||
: ToObjcSelectorPtr(@selector(moveBackwardAndModifySelection:)),
|
: ToObjcSelectorPtr(@selector(
|
||||||
|
moveBackwardAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'D':
|
case 'D':
|
||||||
if (!aEvent.IsShift()) {
|
if (!aEvent.IsShift()) {
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteForward:)),
|
instance->AppendEditCommandsForSelector(
|
||||||
aCommands);
|
ToObjcSelectorPtr(@selector(deleteForward:)), aCommands);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
|
|
@ -359,42 +382,47 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift()
|
!aEvent.IsShift()
|
||||||
? ToObjcSelectorPtr(@selector(moveToEndOfParagraph:))
|
? ToObjcSelectorPtr(@selector(moveToEndOfParagraph:))
|
||||||
: ToObjcSelectorPtr(@selector(moveToEndOfParagraphAndModifySelection:)),
|
: ToObjcSelectorPtr(
|
||||||
|
@selector(moveToEndOfParagraphAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'F':
|
case 'F':
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveForward:))
|
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveForward:))
|
||||||
: ToObjcSelectorPtr(@selector(moveForwardAndModifySelection:)),
|
: ToObjcSelectorPtr(@selector(
|
||||||
|
moveForwardAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'H':
|
case 'H':
|
||||||
if (!aEvent.IsShift()) {
|
if (!aEvent.IsShift()) {
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteBackward:)),
|
instance->AppendEditCommandsForSelector(
|
||||||
aCommands);
|
ToObjcSelectorPtr(@selector(deleteBackward:)), aCommands);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
case 'K':
|
case 'K':
|
||||||
if (!aEvent.IsShift()) {
|
if (!aEvent.IsShift()) {
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
ToObjcSelectorPtr(@selector(deleteToEndOfParagraph:)), aCommands);
|
ToObjcSelectorPtr(@selector(deleteToEndOfParagraph:)),
|
||||||
|
aCommands);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
case 'N':
|
case 'N':
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveDown:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(moveDown:))
|
||||||
|
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
case 'P':
|
case 'P':
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveUp:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(moveUp:))
|
||||||
|
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -413,21 +441,22 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
}
|
}
|
||||||
if (aEvent.IsAlt()) {
|
if (aEvent.IsAlt()) {
|
||||||
// Shift and Control are ignored.
|
// Shift and Control are ignored.
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteWordBackward:)),
|
instance->AppendEditCommandsForSelector(
|
||||||
aCommands);
|
ToObjcSelectorPtr(@selector(deleteWordBackward:)), aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (aEvent.IsControl()) {
|
if (aEvent.IsControl()) {
|
||||||
if (aEvent.IsShift()) {
|
if (aEvent.IsShift()) {
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
ToObjcSelectorPtr(@selector(deleteBackwardByDecomposingPreviousCharacter:)),
|
ToObjcSelectorPtr(
|
||||||
|
@selector(deleteBackwardByDecomposingPreviousCharacter:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Shift is ignored.
|
// Shift is ignored.
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteBackward:)),
|
instance->AppendEditCommandsForSelector(
|
||||||
aCommands);
|
ToObjcSelectorPtr(@selector(deleteBackward:)), aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_Delete:
|
case KEY_NAME_INDEX_Delete:
|
||||||
if (aEvent.IsControl() || aEvent.IsMeta()) {
|
if (aEvent.IsControl() || aEvent.IsMeta()) {
|
||||||
|
|
@ -435,13 +464,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
}
|
}
|
||||||
if (aEvent.IsAlt()) {
|
if (aEvent.IsAlt()) {
|
||||||
// Shift is ignored.
|
// Shift is ignored.
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteWordForward:)),
|
instance->AppendEditCommandsForSelector(
|
||||||
aCommands);
|
ToObjcSelectorPtr(@selector(deleteWordForward:)), aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Shift is ignored.
|
// Shift is ignored.
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteForward:)),
|
instance->AppendEditCommandsForSelector(
|
||||||
aCommands);
|
ToObjcSelectorPtr(@selector(deleteForward:)), aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_PageDown:
|
case KEY_NAME_INDEX_PageDown:
|
||||||
if (aEvent.IsControl() || aEvent.IsMeta()) {
|
if (aEvent.IsControl() || aEvent.IsMeta()) {
|
||||||
|
|
@ -449,12 +478,14 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
}
|
}
|
||||||
if (aEvent.IsAlt()) {
|
if (aEvent.IsAlt()) {
|
||||||
// Shift is ignored.
|
// Shift is ignored.
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(pageDown:)), aCommands);
|
instance->AppendEditCommandsForSelector(
|
||||||
|
ToObjcSelectorPtr(@selector(pageDown:)), aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollPageDown:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(pageDownAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(scrollPageDown:))
|
||||||
|
: ToObjcSelectorPtr(@selector(pageDownAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_PageUp:
|
case KEY_NAME_INDEX_PageUp:
|
||||||
|
|
@ -463,12 +494,14 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
}
|
}
|
||||||
if (aEvent.IsAlt()) {
|
if (aEvent.IsAlt()) {
|
||||||
// Shift is ignored.
|
// Shift is ignored.
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(pageUp:)), aCommands);
|
instance->AppendEditCommandsForSelector(
|
||||||
|
ToObjcSelectorPtr(@selector(pageUp:)), aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollPageUp:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(pageUpAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(scrollPageUp:))
|
||||||
|
: ToObjcSelectorPtr(@selector(pageUpAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_Home:
|
case KEY_NAME_INDEX_Home:
|
||||||
|
|
@ -478,7 +511,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift()
|
!aEvent.IsShift()
|
||||||
? ToObjcSelectorPtr(@selector(scrollToBeginningOfDocument:))
|
? ToObjcSelectorPtr(@selector(scrollToBeginningOfDocument:))
|
||||||
: ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)),
|
: ToObjcSelectorPtr(
|
||||||
|
@selector(moveToBeginningOfDocumentAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_End:
|
case KEY_NAME_INDEX_End:
|
||||||
|
|
@ -486,8 +520,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollToEndOfDocument:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(moveToEndOfDocumentAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(scrollToEndOfDocument:))
|
||||||
|
: ToObjcSelectorPtr(@selector
|
||||||
|
(moveToEndOfDocumentAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_ArrowLeft:
|
case KEY_NAME_INDEX_ArrowLeft:
|
||||||
|
|
@ -498,7 +534,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift()
|
!aEvent.IsShift()
|
||||||
? ToObjcSelectorPtr(@selector(moveToLeftEndOfLine:))
|
? ToObjcSelectorPtr(@selector(moveToLeftEndOfLine:))
|
||||||
: ToObjcSelectorPtr(@selector(moveToLeftEndOfLineAndModifySelection:)),
|
: ToObjcSelectorPtr(@selector
|
||||||
|
(moveToLeftEndOfLineAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -506,8 +543,9 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveLeft:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(moveLeftAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(moveLeft:))
|
||||||
|
: ToObjcSelectorPtr(@selector(moveLeftAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_ArrowRight:
|
case KEY_NAME_INDEX_ArrowRight:
|
||||||
|
|
@ -518,7 +556,8 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift()
|
!aEvent.IsShift()
|
||||||
? ToObjcSelectorPtr(@selector(moveToRightEndOfLine:))
|
? ToObjcSelectorPtr(@selector(moveToRightEndOfLine:))
|
||||||
: ToObjcSelectorPtr(@selector(moveToRightEndOfLineAndModifySelection:)),
|
: ToObjcSelectorPtr(@selector
|
||||||
|
(moveToRightEndOfLineAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -526,8 +565,9 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveRight:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(moveRightAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(moveRight:))
|
||||||
|
: ToObjcSelectorPtr(@selector(moveRightAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_ArrowUp:
|
case KEY_NAME_INDEX_ArrowUp:
|
||||||
|
|
@ -541,25 +581,30 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift()
|
!aEvent.IsShift()
|
||||||
? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
|
? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
|
||||||
: ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)),
|
: ToObjcSelectorPtr(
|
||||||
|
@selector(moveToBegginingOfDocumentAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (aEvent.IsAlt()) {
|
if (aEvent.IsAlt()) {
|
||||||
if (!aEvent.IsShift()) {
|
if (!aEvent.IsShift()) {
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(moveBackward:)),
|
|
||||||
aCommands);
|
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)), aCommands);
|
ToObjcSelectorPtr(@selector(moveBackward:)), aCommands);
|
||||||
|
instance->AppendEditCommandsForSelector(
|
||||||
|
ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)),
|
||||||
|
aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
ToObjcSelectorPtr(@selector(moveParagraphBackwardAndModifySelection:)), aCommands);
|
ToObjcSelectorPtr(@selector
|
||||||
|
(moveParagraphBackwardAndModifySelection:)),
|
||||||
|
aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveUp:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(moveUp:))
|
||||||
|
: ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
case KEY_NAME_INDEX_ArrowDown:
|
case KEY_NAME_INDEX_ArrowDown:
|
||||||
|
|
@ -573,32 +618,37 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift()
|
!aEvent.IsShift()
|
||||||
? ToObjcSelectorPtr(@selector(moveToEndOfDocument:))
|
? ToObjcSelectorPtr(@selector(moveToEndOfDocument:))
|
||||||
: ToObjcSelectorPtr(@selector(moveToEndOfDocumentAndModifySelection:)),
|
: ToObjcSelectorPtr(@selector
|
||||||
|
(moveToEndOfDocumentAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (aEvent.IsAlt()) {
|
if (aEvent.IsAlt()) {
|
||||||
if (!aEvent.IsShift()) {
|
if (!aEvent.IsShift()) {
|
||||||
instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(moveForward:)),
|
instance->AppendEditCommandsForSelector(
|
||||||
aCommands);
|
ToObjcSelectorPtr(@selector(moveForward:)), aCommands);
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
ToObjcSelectorPtr(@selector(moveToEndOfParagraph:)), aCommands);
|
ToObjcSelectorPtr(@selector(moveToEndOfParagraph:)), aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
ToObjcSelectorPtr(@selector(moveParagraphForwardAndModifySelection:)), aCommands);
|
ToObjcSelectorPtr(@selector
|
||||||
|
(moveParagraphForwardAndModifySelection:)),
|
||||||
|
aCommands);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instance->AppendEditCommandsForSelector(
|
instance->AppendEditCommandsForSelector(
|
||||||
!aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveDown:))
|
!aEvent.IsShift()
|
||||||
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
|
? ToObjcSelectorPtr(@selector(moveDown:))
|
||||||
|
: ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
|
||||||
aCommands);
|
aCommands);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommandsForTests");
|
instance->LogEditCommands(aCommands,
|
||||||
|
"NativeKeyBindings::GetEditCommandsForTests");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widget
|
} // namespace widget
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ namespace widget {
|
||||||
|
|
||||||
NativeMenuMac::NativeMenuMac(dom::Element* aElement)
|
NativeMenuMac::NativeMenuMac(dom::Element* aElement)
|
||||||
: mElement(aElement), mContainerStatusBarItem(nil) {
|
: 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);
|
mMenuGroupOwner = new nsMenuGroupOwnerX(aElement, nullptr);
|
||||||
mMenu = MakeRefPtr<nsMenuX>(nullptr, mMenuGroupOwner, aElement);
|
mMenu = MakeRefPtr<nsMenuX>(nullptr, mMenuGroupOwner, aElement);
|
||||||
mMenu->SetObserver(this);
|
mMenu->SetObserver(this);
|
||||||
|
|
@ -78,9 +79,11 @@ bool NativeMenuMac::ActivateNativeMenuItemAt(const nsAString& aIndexString) {
|
||||||
nsMenuUtilsX::CheckNativeMenuConsistency(menu);
|
nsMenuUtilsX::CheckNativeMenuConsistency(menu);
|
||||||
|
|
||||||
NSString* locationString =
|
NSString* locationString =
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading())
|
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
aIndexString.BeginReading())
|
||||||
length:aIndexString.Length()];
|
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
|
// We can't perform an action on an item with a submenu, that will raise
|
||||||
// an obj-c exception.
|
// an obj-c exception.
|
||||||
|
|
@ -106,9 +109,11 @@ void NativeMenuMac::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||||
|
|
||||||
NSString* locationString =
|
NSString* locationString =
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading())
|
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
aIndexString.BeginReading())
|
||||||
length:aIndexString.Length()];
|
length:aIndexString.Length()];
|
||||||
NSArray<NSString*>* indexes = [locationString componentsSeparatedByString:@"|"];
|
NSArray<NSString*>* indexes =
|
||||||
|
[locationString componentsSeparatedByString:@"|"];
|
||||||
RefPtr<nsMenuX> currentMenu = mMenu.get();
|
RefPtr<nsMenuX> currentMenu = mMenu.get();
|
||||||
|
|
||||||
// now find the correct submenu
|
// now find the correct submenu
|
||||||
|
|
@ -124,7 +129,9 @@ void NativeMenuMac::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
|
||||||
}
|
}
|
||||||
RefPtr<nsIContent> content = targetMenu->match(
|
RefPtr<nsIContent> content = targetMenu->match(
|
||||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
[](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)) {
|
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
|
||||||
visible++;
|
visible++;
|
||||||
if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) {
|
if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) {
|
||||||
|
|
@ -175,8 +182,8 @@ void NativeMenuMac::OnMenuWillOpen(dom::Element* aPopupElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case
|
// Our caller isn't keeping us alive, so make sure we stay alive throughout
|
||||||
// one of the observer notifications destroys us.
|
// this function in case one of the observer notifications destroys us.
|
||||||
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
||||||
|
|
||||||
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
||||||
|
|
@ -185,8 +192,8 @@ void NativeMenuMac::OnMenuWillOpen(dom::Element* aPopupElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeMenuMac::OnMenuDidOpen(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
|
// Our caller isn't keeping us alive, so make sure we stay alive throughout
|
||||||
// one of the observer notifications destroys us.
|
// this function in case one of the observer notifications destroys us.
|
||||||
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
||||||
|
|
||||||
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
||||||
|
|
@ -200,8 +207,8 @@ void NativeMenuMac::OnMenuDidOpen(dom::Element* aPopupElement) {
|
||||||
|
|
||||||
void NativeMenuMac::OnMenuWillActivateItem(dom::Element* aPopupElement,
|
void NativeMenuMac::OnMenuWillActivateItem(dom::Element* aPopupElement,
|
||||||
dom::Element* aMenuItemElement) {
|
dom::Element* aMenuItemElement) {
|
||||||
// Our caller isn't keeping us alive, so make sure we stay alive throughout this function in case
|
// Our caller isn't keeping us alive, so make sure we stay alive throughout
|
||||||
// one of the observer notifications destroys us.
|
// this function in case one of the observer notifications destroys us.
|
||||||
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
||||||
|
|
||||||
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
||||||
|
|
@ -210,8 +217,8 @@ void NativeMenuMac::OnMenuWillActivateItem(dom::Element* aPopupElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeMenuMac::OnMenuClosed(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
|
// Our caller isn't keeping us alive, so make sure we stay alive throughout
|
||||||
// one of the observer notifications destroys us.
|
// this function in case one of the observer notifications destroys us.
|
||||||
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
RefPtr<NativeMenuMac> kungFuDeathGrip(this);
|
||||||
|
|
||||||
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
for (NativeMenu::Observer* observer : mObservers.Clone()) {
|
||||||
|
|
@ -236,7 +243,8 @@ static NSAppearance* NativeAppearanceForContent(nsIContent* aContent) {
|
||||||
return NSAppearanceForColorScheme(LookAndFeel::ColorSchemeForFrame(f));
|
return NSAppearanceForColorScheme(LookAndFeel::ColorSchemeForFrame(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame, const CSSIntPoint& aPosition,
|
void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame,
|
||||||
|
const CSSIntPoint& aPosition,
|
||||||
bool aIsContextMenu) {
|
bool aIsContextMenu) {
|
||||||
nsPresContext* pc = aClickedFrame->PresContext();
|
nsPresContext* pc = aClickedFrame->PresContext();
|
||||||
auto cssToDesktopScale =
|
auto cssToDesktopScale =
|
||||||
|
|
@ -250,24 +258,29 @@ void NativeMenuMac::ShowAsContextMenu(nsIFrame* aClickedFrame, const CSSIntPoint
|
||||||
NSAppearance* appearance = NativeAppearanceForContent(mMenu->Content());
|
NSAppearance* appearance = NativeAppearanceForContent(mMenu->Content());
|
||||||
NSPoint locationOnScreen = nsCocoaUtils::GeckoPointToCocoaPoint(desktopPoint);
|
NSPoint locationOnScreen = nsCocoaUtils::GeckoPointToCocoaPoint(desktopPoint);
|
||||||
|
|
||||||
// Let the MOZMenuOpeningCoordinator do the actual opening, so that this ShowAsContextMenu call
|
// Let the MOZMenuOpeningCoordinator do the actual opening, so that this
|
||||||
// does not spawn a nested event loop, which would be surprising to our callers.
|
// ShowAsContextMenu call does not spawn a nested event loop, which would be
|
||||||
mOpeningHandle = [MOZMenuOpeningCoordinator.sharedInstance asynchronouslyOpenMenu:menu
|
// surprising to our callers.
|
||||||
atScreenPosition:locationOnScreen
|
mOpeningHandle = [MOZMenuOpeningCoordinator.sharedInstance
|
||||||
forView:view
|
asynchronouslyOpenMenu:menu
|
||||||
withAppearance:appearance
|
atScreenPosition:locationOnScreen
|
||||||
asContextMenu:aIsContextMenu];
|
forView:view
|
||||||
|
withAppearance:appearance
|
||||||
|
asContextMenu:aIsContextMenu];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NativeMenuMac::Close() {
|
bool NativeMenuMac::Close() {
|
||||||
if (mOpeningHandle) {
|
if (mOpeningHandle) {
|
||||||
// In case the menu was trying to open, but this Close() call interrupted it, cancel opening.
|
// In case the menu was trying to open, but this Close() call interrupted
|
||||||
[MOZMenuOpeningCoordinator.sharedInstance cancelAsynchronousOpening:mOpeningHandle];
|
// it, cancel opening.
|
||||||
|
[MOZMenuOpeningCoordinator.sharedInstance
|
||||||
|
cancelAsynchronousOpening:mOpeningHandle];
|
||||||
}
|
}
|
||||||
return mMenu->Close();
|
return mMenu->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(dom::Element* aElement) {
|
RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(
|
||||||
|
dom::Element* aElement) {
|
||||||
nsTArray<RefPtr<dom::Element>> submenuChain;
|
nsTArray<RefPtr<dom::Element>> submenuChain;
|
||||||
RefPtr<dom::Element> currentElement = aElement->GetParentElement();
|
RefPtr<dom::Element> currentElement = aElement->GetParentElement();
|
||||||
while (currentElement && currentElement != mElement) {
|
while (currentElement && currentElement != mElement) {
|
||||||
|
|
@ -281,7 +294,8 @@ RefPtr<nsMenuX> NativeMenuMac::GetOpenMenuContainingElement(dom::Element* aEleme
|
||||||
return nullptr;
|
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();
|
submenuChain.Reverse();
|
||||||
RefPtr<nsMenuX> menu = mMenu;
|
RefPtr<nsMenuX> menu = mMenu;
|
||||||
for (const auto& submenu : submenuChain) {
|
for (const auto& submenu : submenuChain) {
|
||||||
|
|
@ -321,7 +335,8 @@ static NSEventModifierFlags ConvertModifierFlags(Modifiers aModifiers) {
|
||||||
return flags;
|
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) {
|
ErrorResult& aRv) {
|
||||||
RefPtr<nsMenuX> menu = GetOpenMenuContainingElement(aItemElement);
|
RefPtr<nsMenuX> menu = GetOpenMenuContainingElement(aItemElement);
|
||||||
if (!menu) {
|
if (!menu) {
|
||||||
|
|
@ -343,27 +358,29 @@ void NativeMenuMac::ActivateItem(dom::Element* aItemElement, Modifiers aModifier
|
||||||
NSMenuItem* nativeItem = [item->NativeNSMenuItem() retain];
|
NSMenuItem* nativeItem = [item->NativeNSMenuItem() retain];
|
||||||
|
|
||||||
// First, initiate the closing of the NSMenu.
|
// First, initiate the closing of the NSMenu.
|
||||||
// This synchronously calls the menu delegate's menuDidClose handler. So menuDidClose is
|
// This synchronously calls the menu delegate's menuDidClose handler. So
|
||||||
// what runs first; this matches the order of events for user-initiated menu item activation.
|
// menuDidClose is what runs first; this matches the order of events for
|
||||||
// This call doesn't immediately hide the menu; the menu only hides once the stack unwinds
|
// user-initiated menu item activation. This call doesn't immediately hide the
|
||||||
// from NSMenu's nested "tracking" event loop.
|
// menu; the menu only hides once the stack unwinds from NSMenu's nested
|
||||||
|
// "tracking" event loop.
|
||||||
[mMenu->NativeNSMenu() cancelTrackingWithoutAnimation];
|
[mMenu->NativeNSMenu() cancelTrackingWithoutAnimation];
|
||||||
|
|
||||||
// Next, call OnWillActivateItem. This also matches the order of calls that happen when a user
|
// Next, call OnWillActivateItem. This also matches the order of calls that
|
||||||
// activates a menu item in the real world: -[MenuDelegate menu:willActivateItem:] runs after
|
// happen when a user activates a menu item in the real world: -[MenuDelegate
|
||||||
// menuDidClose.
|
// menu:willActivateItem:] runs after menuDidClose.
|
||||||
menu->OnWillActivateItem(nativeItem);
|
menu->OnWillActivateItem(nativeItem);
|
||||||
|
|
||||||
// Finally, call ActivateItemAfterClosing. This also mimics the order in the real world:
|
// Finally, call ActivateItemAfterClosing. This also mimics the order in the
|
||||||
// menuItemHit is called after menu:willActivateItem:.
|
// real world: menuItemHit is called after menu:willActivateItem:.
|
||||||
menu->ActivateItemAfterClosing(std::move(item), ConvertModifierFlags(aModifiers), aButton);
|
menu->ActivateItemAfterClosing(std::move(item),
|
||||||
|
ConvertModifierFlags(aModifiers), aButton);
|
||||||
|
|
||||||
// Tell our native event loop that it should not process any more work before
|
// 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
|
// 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
|
// as fast as possible. This was needed to fix spurious failures in tests,
|
||||||
// a call to cancelTrackingWithoutAnimation was ignored if more native events were
|
// where a call to cancelTrackingWithoutAnimation was ignored if more native
|
||||||
// processed before the event loop was exited. As a result, the menu stayed open
|
// events were processed before the event loop was exited. As a result, the
|
||||||
// forever and the test never finished.
|
// menu stayed open forever and the test never finished.
|
||||||
MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES;
|
MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES;
|
||||||
|
|
||||||
[nativeItem release];
|
[nativeItem release];
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,19 @@
|
||||||
|
|
||||||
namespace mozilla::widget {
|
namespace mozilla::widget {
|
||||||
|
|
||||||
void NativeMenuSupport::CreateNativeMenuBar(nsIWidget* aParent, dom::Element* aMenuBarElement) {
|
void NativeMenuSupport::CreateNativeMenuBar(nsIWidget* aParent,
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Attempting to create native menu bar on wrong thread!");
|
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.
|
// Create the menubar and give it to the parent window. The parent takes
|
||||||
static_cast<nsCocoaWindow*>(aParent)->SetMenuBar(MakeRefPtr<nsMenuBarX>(aMenuBarElement));
|
// 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);
|
return MakeAndAddRef<NativeMenuMac>(aPopup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,8 @@ using namespace mozilla;
|
||||||
- (void)_removeDisplayedNotification:(id<FakeNSUserNotification>)notification;
|
- (void)_removeDisplayedNotification:(id<FakeNSUserNotification>)notification;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface mozNotificationCenterDelegate : NSObject <NSUserNotificationCenterDelegate> {
|
@interface mozNotificationCenterDelegate
|
||||||
|
: NSObject <NSUserNotificationCenterDelegate> {
|
||||||
OSXNotificationCenter* mOSXNC;
|
OSXNotificationCenter* mOSXNC;
|
||||||
}
|
}
|
||||||
- (id)initWithOSXNC:(OSXNotificationCenter*)osxnc;
|
- (id)initWithOSXNC:(OSXNotificationCenter*)osxnc;
|
||||||
|
|
@ -78,11 +79,12 @@ using namespace mozilla;
|
||||||
didActivateNotification:(id<FakeNSUserNotification>)notification {
|
didActivateNotification:(id<FakeNSUserNotification>)notification {
|
||||||
unsigned long long additionalActionIndex = ULLONG_MAX;
|
unsigned long long additionalActionIndex = ULLONG_MAX;
|
||||||
if ([notification respondsToSelector:@selector(_alternateActionIndex)]) {
|
if ([notification respondsToSelector:@selector(_alternateActionIndex)]) {
|
||||||
NSNumber* alternateActionIndex = [(NSObject*)notification valueForKey:@"_alternateActionIndex"];
|
NSNumber* alternateActionIndex =
|
||||||
|
[(NSObject*)notification valueForKey:@"_alternateActionIndex"];
|
||||||
additionalActionIndex = [alternateActionIndex unsignedLongLongValue];
|
additionalActionIndex = [alternateActionIndex unsignedLongLongValue];
|
||||||
}
|
}
|
||||||
mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"], notification.activationType,
|
mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"],
|
||||||
additionalActionIndex);
|
notification.activationType, additionalActionIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
- (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
|
- (void)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
||||||
didDismissAlert:(id<FakeNSUserNotification>)notification {
|
didDismissAlert:(id<FakeNSUserNotification>)notification {
|
||||||
NSString* name = [[notification userInfo] valueForKey:@"name"];
|
NSString* name = [[notification userInfo] valueForKey:@"name"];
|
||||||
|
|
@ -122,7 +125,8 @@ class OSXNotificationInfo final : public nsISupports {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
OSXNotificationInfo(NSString* name, nsIObserver* observer, const nsAString& alertCookie);
|
OSXNotificationInfo(NSString* name, nsIObserver* observer,
|
||||||
|
const nsAString& alertCookie);
|
||||||
|
|
||||||
NSString* mName;
|
NSString* mName;
|
||||||
nsCOMPtr<nsIObserver> mObserver;
|
nsCOMPtr<nsIObserver> mObserver;
|
||||||
|
|
@ -183,50 +187,56 @@ OSXNotificationCenter::~OSXNotificationCenter() {
|
||||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsIAlertsIconData, nsIAlertsDoNotDisturb,
|
NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsIAlertsIconData,
|
||||||
nsIAlertNotificationImageListener)
|
nsIAlertsDoNotDisturb, nsIAlertNotificationImageListener)
|
||||||
|
|
||||||
nsresult OSXNotificationCenter::Init() {
|
nsresult OSXNotificationCenter::Init() {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
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_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXNotificationCenter::ShowAlertNotification(
|
OSXNotificationCenter::ShowAlertNotification(
|
||||||
const nsAString& aImageUrl, const nsAString& aAlertTitle, const nsAString& aAlertText,
|
const nsAString& aImageUrl, const nsAString& aAlertTitle,
|
||||||
bool aAlertTextClickable, const nsAString& aAlertCookie, nsIObserver* aAlertListener,
|
const nsAString& aAlertText, bool aAlertTextClickable,
|
||||||
|
const nsAString& aAlertCookie, nsIObserver* aAlertListener,
|
||||||
const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang,
|
const nsAString& aAlertName, const nsAString& aBidi, const nsAString& aLang,
|
||||||
const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
|
const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
|
||||||
bool aRequireInteraction) {
|
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);
|
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
|
||||||
// vibrate is unused for now
|
// vibrate is unused for now
|
||||||
nsTArray<uint32_t> vibrate;
|
nsTArray<uint32_t> vibrate;
|
||||||
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
|
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle, aAlertText,
|
||||||
aAlertCookie, aBidi, aLang, aData, aPrincipal, aInPrivateBrowsing,
|
aAlertTextClickable, aAlertCookie, aBidi, aLang,
|
||||||
|
aData, aPrincipal, aInPrivateBrowsing,
|
||||||
aRequireInteraction, false, vibrate);
|
aRequireInteraction, false, vibrate);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
return ShowAlert(alert, aAlertListener);
|
return ShowAlert(alert, aAlertListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXNotificationCenter::ShowPersistentNotification(const nsAString& aPersistentData,
|
OSXNotificationCenter::ShowPersistentNotification(
|
||||||
nsIAlertNotification* aAlert,
|
const nsAString& aPersistentData, nsIAlertNotification* aAlert,
|
||||||
nsIObserver* aAlertListener) {
|
nsIObserver* aAlertListener) {
|
||||||
return ShowAlert(aAlert, aAlertListener);
|
return ShowAlert(aAlert, aAlertListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert, nsIObserver* aAlertListener) {
|
OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert,
|
||||||
|
nsIObserver* aAlertListener) {
|
||||||
return ShowAlertWithIconData(aAlert, aAlertListener, 0, nullptr);
|
return ShowAlertWithIconData(aAlert, aAlertListener, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||||
nsIObserver* aAlertListener, uint32_t aIconSize,
|
nsIObserver* aAlertListener,
|
||||||
|
uint32_t aIconSize,
|
||||||
const uint8_t* aIconData) {
|
const uint8_t* aIconData) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
|
|
@ -248,13 +258,16 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||||
rv = aAlert->GetSource(hostPort);
|
rv = aAlert->GetSource(hostPort);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
nsCOMPtr<nsIStringBundle> bundle;
|
nsCOMPtr<nsIStringBundle> bundle;
|
||||||
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
nsCOMPtr<nsIStringBundleService> sbs =
|
||||||
sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle));
|
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||||
|
sbs->CreateBundle("chrome://alerts/locale/alert.properties",
|
||||||
|
getter_AddRefs(bundle));
|
||||||
|
|
||||||
if (!hostPort.IsEmpty() && bundle) {
|
if (!hostPort.IsEmpty() && bundle) {
|
||||||
AutoTArray<nsString, 1> formatStrings = {hostPort};
|
AutoTArray<nsString, 1> formatStrings = {hostPort};
|
||||||
nsAutoString notificationSource;
|
nsAutoString notificationSource;
|
||||||
bundle->FormatStringFromName("source.label", formatStrings, notificationSource);
|
bundle->FormatStringFromName("source.label", formatStrings,
|
||||||
|
notificationSource);
|
||||||
notification.subtitle = nsCocoaUtils::ToNSString(notificationSource);
|
notification.subtitle = nsCocoaUtils::ToNSString(notificationSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,17 +281,19 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||||
notification.soundName = isSilent ? nil : NSUserNotificationDefaultSoundName;
|
notification.soundName = isSilent ? nil : NSUserNotificationDefaultSoundName;
|
||||||
notification.hasActionButton = NO;
|
notification.hasActionButton = NO;
|
||||||
|
|
||||||
// If this is not an application/extension alert, show additional actions dealing with
|
// If this is not an application/extension alert, show additional actions
|
||||||
// permissions.
|
// dealing with permissions.
|
||||||
bool isActionable;
|
bool isActionable;
|
||||||
if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) && isActionable) {
|
if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) &&
|
||||||
nsAutoString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle;
|
isActionable) {
|
||||||
|
nsAutoString closeButtonTitle, actionButtonTitle, disableButtonTitle,
|
||||||
|
settingsButtonTitle;
|
||||||
bundle->GetStringFromName("closeButton.title", closeButtonTitle);
|
bundle->GetStringFromName("closeButton.title", closeButtonTitle);
|
||||||
bundle->GetStringFromName("actionButton.label", actionButtonTitle);
|
bundle->GetStringFromName("actionButton.label", actionButtonTitle);
|
||||||
if (!hostPort.IsEmpty()) {
|
if (!hostPort.IsEmpty()) {
|
||||||
AutoTArray<nsString, 1> formatStrings = {hostPort};
|
AutoTArray<nsString, 1> formatStrings = {hostPort};
|
||||||
bundle->FormatStringFromName("webActions.disableForOrigin.label", formatStrings,
|
bundle->FormatStringFromName("webActions.disableForOrigin.label",
|
||||||
disableButtonTitle);
|
formatStrings, disableButtonTitle);
|
||||||
}
|
}
|
||||||
bundle->GetStringFromName("webActions.settings.label", settingsButtonTitle);
|
bundle->GetStringFromName("webActions.settings.label", settingsButtonTitle);
|
||||||
|
|
||||||
|
|
@ -288,15 +303,20 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||||
// Notification Center preferences, and doesn't support the alternate
|
// Notification Center preferences, and doesn't support the alternate
|
||||||
// action menu.
|
// action menu.
|
||||||
if ([notification respondsToSelector:@selector(set_showsButtons:)] &&
|
if ([notification respondsToSelector:@selector(set_showsButtons:)] &&
|
||||||
[notification respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] &&
|
[notification
|
||||||
[notification respondsToSelector:@selector(set_alternateActionButtonTitles:)]) {
|
respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] &&
|
||||||
|
[notification
|
||||||
|
respondsToSelector:@selector(set_alternateActionButtonTitles:)]) {
|
||||||
notification.hasActionButton = YES;
|
notification.hasActionButton = YES;
|
||||||
notification.actionButtonTitle = nsCocoaUtils::ToNSString(actionButtonTitle);
|
notification.actionButtonTitle =
|
||||||
|
nsCocoaUtils::ToNSString(actionButtonTitle);
|
||||||
|
|
||||||
[(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"];
|
[(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"];
|
||||||
[(NSObject*)notification setValue:@(YES) forKey:@"_alwaysShowAlternateActionMenu"];
|
[(NSObject*)notification setValue:@(YES)
|
||||||
|
forKey:@"_alwaysShowAlternateActionMenu"];
|
||||||
[(NSObject*)notification setValue:@[
|
[(NSObject*)notification setValue:@[
|
||||||
nsCocoaUtils::ToNSString(disableButtonTitle), nsCocoaUtils::ToNSString(settingsButtonTitle)
|
nsCocoaUtils::ToNSString(disableButtonTitle),
|
||||||
|
nsCocoaUtils::ToNSString(settingsButtonTitle)
|
||||||
]
|
]
|
||||||
forKey:@"_alternateActionButtonTitles"];
|
forKey:@"_alternateActionButtonTitles"];
|
||||||
}
|
}
|
||||||
|
|
@ -315,19 +335,22 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||||
if (!alertName) {
|
if (!alertName) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
notification.userInfo =
|
notification.userInfo = [NSDictionary
|
||||||
[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil]
|
dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil]
|
||||||
forKeys:[NSArray arrayWithObjects:@"name", nil]];
|
forKeys:[NSArray arrayWithObjects:@"name", nil]];
|
||||||
|
|
||||||
nsAutoString cookie;
|
nsAutoString cookie;
|
||||||
rv = aAlert->GetCookie(cookie);
|
rv = aAlert->GetCookie(cookie);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
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.
|
// Show the favicon if supported on this version of OS X.
|
||||||
if (aIconSize > 0 && [notification respondsToSelector:@selector(set_identityImage:)] &&
|
if (aIconSize > 0 &&
|
||||||
[notification respondsToSelector:@selector(set_identityImageHasBorder:)]) {
|
[notification respondsToSelector:@selector(set_identityImage:)] &&
|
||||||
|
[notification
|
||||||
|
respondsToSelector:@selector(set_identityImageHasBorder:)]) {
|
||||||
NSData* iconData = [NSData dataWithBytes:aIconData length:aIconSize];
|
NSData* iconData = [NSData dataWithBytes:aIconData length:aIconSize];
|
||||||
NSImage* icon = [[[NSImage alloc] initWithData:iconData] autorelease];
|
NSImage* icon = [[[NSImage alloc] initWithData:iconData] autorelease];
|
||||||
|
|
||||||
|
|
@ -339,8 +362,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||||
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
|
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Show the notification without waiting for an image if there is no icon URL or
|
// Show the notification without waiting for an image if there is no icon URL
|
||||||
// notification icons are not supported on this version of OS X.
|
// or notification icons are not supported on this version of OS X.
|
||||||
if (![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
|
if (![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
|
||||||
CloseAlertCocoaString(alertName);
|
CloseAlertCocoaString(alertName);
|
||||||
mActiveAlerts.AppendElement(osxni);
|
mActiveAlerts.AppendElement(osxni);
|
||||||
|
|
@ -353,7 +376,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||||
mPendingAlerts.AppendElement(osxni);
|
mPendingAlerts.AppendElement(osxni);
|
||||||
osxni->mPendingNotification = notification;
|
osxni->mPendingNotification = notification;
|
||||||
// Wait six seconds for the image to load.
|
// 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))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
ShowPendingNotification(osxni);
|
ShowPendingNotification(osxni);
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +389,8 @@ OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXNotificationCenter::CloseAlert(const nsAString& aAlertName, bool aContextClosed) {
|
OSXNotificationCenter::CloseAlert(const nsAString& aAlertName,
|
||||||
|
bool aContextClosed) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NSString* alertName = nsCocoaUtils::ToNSString(aAlertName);
|
NSString* alertName = nsCocoaUtils::ToNSString(aAlertName);
|
||||||
|
|
@ -396,7 +421,8 @@ void OSXNotificationCenter::CloseAlertCocoaString(NSString* aAlertName) {
|
||||||
OSXNotificationInfo* osxni = mActiveAlerts[i];
|
OSXNotificationInfo* osxni = mActiveAlerts[i];
|
||||||
if ([aAlertName isEqualToString:osxni->mName]) {
|
if ([aAlertName isEqualToString:osxni->mName]) {
|
||||||
if (osxni->mObserver) {
|
if (osxni->mObserver) {
|
||||||
osxni->mObserver->Observe(nullptr, "alertfinished", osxni->mCookie.get());
|
osxni->mObserver->Observe(nullptr, "alertfinished",
|
||||||
|
osxni->mCookie.get());
|
||||||
}
|
}
|
||||||
if (osxni->mIconRequest) {
|
if (osxni->mIconRequest) {
|
||||||
osxni->mIconRequest->Cancel(NS_BINDING_ABORTED);
|
osxni->mIconRequest->Cancel(NS_BINDING_ABORTED);
|
||||||
|
|
@ -410,9 +436,9 @@ void OSXNotificationCenter::CloseAlertCocoaString(NSString* aAlertName) {
|
||||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OSXNotificationCenter::OnActivate(NSString* aAlertName,
|
void OSXNotificationCenter::OnActivate(
|
||||||
NSUserNotificationActivationType aActivationType,
|
NSString* aAlertName, NSUserNotificationActivationType aActivationType,
|
||||||
unsigned long long aAdditionalActionIndex) {
|
unsigned long long aAdditionalActionIndex) {
|
||||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
if (!aAlertName) {
|
if (!aAlertName) {
|
||||||
|
|
@ -428,18 +454,22 @@ void OSXNotificationCenter::OnActivate(NSString* aAlertName,
|
||||||
case NSUserNotificationActivationTypeActionButtonClicked:
|
case NSUserNotificationActivationTypeActionButtonClicked:
|
||||||
switch (aAdditionalActionIndex) {
|
switch (aAdditionalActionIndex) {
|
||||||
case OSXNotificationActionDisable:
|
case OSXNotificationActionDisable:
|
||||||
osxni->mObserver->Observe(nullptr, "alertdisablecallback", osxni->mCookie.get());
|
osxni->mObserver->Observe(nullptr, "alertdisablecallback",
|
||||||
|
osxni->mCookie.get());
|
||||||
break;
|
break;
|
||||||
case OSXNotificationActionSettings:
|
case OSXNotificationActionSettings:
|
||||||
osxni->mObserver->Observe(nullptr, "alertsettingscallback", osxni->mCookie.get());
|
osxni->mObserver->Observe(nullptr, "alertsettingscallback",
|
||||||
|
osxni->mCookie.get());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NS_WARNING("Unknown NSUserNotification additional action clicked");
|
NS_WARNING(
|
||||||
|
"Unknown NSUserNotification additional action clicked");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
osxni->mObserver->Observe(nullptr, "alertclickcallback", osxni->mCookie.get());
|
osxni->mObserver->Observe(nullptr, "alertclickcallback",
|
||||||
|
osxni->mCookie.get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -450,7 +480,8 @@ void OSXNotificationCenter::OnActivate(NSString* aAlertName,
|
||||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OSXNotificationCenter::ShowPendingNotification(OSXNotificationInfo* osxni) {
|
void OSXNotificationCenter::ShowPendingNotification(
|
||||||
|
OSXNotificationInfo* osxni) {
|
||||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
if (osxni->mIconRequest) {
|
if (osxni->mIconRequest) {
|
||||||
|
|
@ -496,7 +527,8 @@ OSXNotificationCenter::OnImageMissing(nsISupports* aUserData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aRequest) {
|
OSXNotificationCenter::OnImageReady(nsISupports* aUserData,
|
||||||
|
imgIRequest* aRequest) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsCOMPtr<imgIContainer> image;
|
nsCOMPtr<imgIContainer> image;
|
||||||
|
|
@ -511,9 +543,10 @@ OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aReques
|
||||||
}
|
}
|
||||||
|
|
||||||
NSImage* cocoaImage = nil;
|
NSImage* cocoaImage = nil;
|
||||||
// TODO: Pass pres context / ComputedStyle here to support context paint properties
|
// TODO: Pass pres context / ComputedStyle here to support context paint
|
||||||
nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(image, imgIContainer::FRAME_FIRST,
|
// properties
|
||||||
nullptr, nullptr, &cocoaImage);
|
nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
|
||||||
|
image, imgIContainer::FRAME_FIRST, nullptr, nullptr, &cocoaImage);
|
||||||
(osxni->mPendingNotification).contentImage = cocoaImage;
|
(osxni->mPendingNotification).contentImage = cocoaImage;
|
||||||
[cocoaImage release];
|
[cocoaImage release];
|
||||||
ShowPendingNotification(osxni);
|
ShowPendingNotification(osxni);
|
||||||
|
|
@ -525,7 +558,9 @@ OSXNotificationCenter::OnImageReady(nsISupports* aUserData, imgIRequest* aReques
|
||||||
|
|
||||||
// nsIAlertsDoNotDisturb
|
// nsIAlertsDoNotDisturb
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXNotificationCenter::GetManualDoNotDisturb(bool* aRetVal) { return NS_ERROR_NOT_IMPLEMENTED; }
|
OSXNotificationCenter::GetManualDoNotDisturb(bool* aRetVal) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
OSXNotificationCenter::SetManualDoNotDisturb(bool aDoNotDisturb) {
|
OSXNotificationCenter::SetManualDoNotDisturb(bool aDoNotDisturb) {
|
||||||
|
|
|
||||||
|
|
@ -79,19 +79,20 @@ ScreenHelperCocoa::~ScreenHelperCocoa() {
|
||||||
static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
|
static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
DesktopToLayoutDeviceScale contentsScaleFactor(nsCocoaUtils::GetBackingScaleFactor(aScreen));
|
DesktopToLayoutDeviceScale contentsScaleFactor(
|
||||||
|
nsCocoaUtils::GetBackingScaleFactor(aScreen));
|
||||||
CSSToLayoutDeviceScale defaultCssScaleFactor(contentsScaleFactor.scale);
|
CSSToLayoutDeviceScale defaultCssScaleFactor(contentsScaleFactor.scale);
|
||||||
NSRect frame = [aScreen frame];
|
NSRect frame = [aScreen frame];
|
||||||
LayoutDeviceIntRect rect =
|
LayoutDeviceIntRect rect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(
|
||||||
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale);
|
frame, contentsScaleFactor.scale);
|
||||||
frame = [aScreen visibleFrame];
|
frame = [aScreen visibleFrame];
|
||||||
LayoutDeviceIntRect availRect =
|
LayoutDeviceIntRect availRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(
|
||||||
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, contentsScaleFactor.scale);
|
frame, contentsScaleFactor.scale);
|
||||||
|
|
||||||
// aScreen may be capable of displaying multiple pixel depths, for example by
|
// 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
|
// transitioning to an HDR-capable depth when required by a window displayed
|
||||||
// the screen. We want to note the maximum capabilities of the screen, so we use
|
// on the screen. We want to note the maximum capabilities of the screen, so
|
||||||
// the largest depth it offers.
|
// we use the largest depth it offers.
|
||||||
uint32_t pixelDepth = 0;
|
uint32_t pixelDepth = 0;
|
||||||
const NSWindowDepth* depths = [aScreen supportedWindowDepths];
|
const NSWindowDepth* depths = [aScreen supportedWindowDepths];
|
||||||
for (size_t d = 0; NSWindowDepth depth = depths[d]; d++) {
|
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);
|
dpi = rect.height / (heightMM / MM_PER_INCH_FLOAT);
|
||||||
}
|
}
|
||||||
MOZ_LOG(sScreenLog, LogLevel::Debug,
|
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,
|
("New screen [%d %d %d %d (%d %d %d %d) %d %f %f %f]", rect.x, rect.y,
|
||||||
rect.height, availRect.x, availRect.y, availRect.width, availRect.height, pixelDepth,
|
rect.width, rect.height, availRect.x, availRect.y, availRect.width,
|
||||||
contentsScaleFactor.scale, defaultCssScaleFactor.scale, dpi));
|
availRect.height, pixelDepth, contentsScaleFactor.scale,
|
||||||
|
defaultCssScaleFactor.scale, dpi));
|
||||||
|
|
||||||
// Getting the refresh rate is a little hard on OS X. We could use
|
// Getting the refresh rate is a little hard on OS X. We could use
|
||||||
// CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little
|
// CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little
|
||||||
// involved. Ideally we could query it from vsync. For now, we leave it out.
|
// involved. Ideally we could query it from vsync. For now, we leave it out.
|
||||||
RefPtr<Screen> screen =
|
RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth, 0,
|
||||||
new Screen(rect, availRect, pixelDepth, pixelDepth, 0, contentsScaleFactor,
|
contentsScaleFactor, defaultCssScaleFactor,
|
||||||
defaultCssScaleFactor, dpi, Screen::IsPseudoDisplay::No);
|
dpi, Screen::IsPseudoDisplay::No);
|
||||||
return screen.forget();
|
return screen.forget();
|
||||||
|
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nullptr);
|
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->GetRect(&rect.x, &rect.y, &rect.width, &rect.height);
|
||||||
aScreen->GetContentsScaleFactor(&scale);
|
aScreen->GetContentsScaleFactor(&scale);
|
||||||
NSRect frame = [screen frame];
|
NSRect frame = [screen frame];
|
||||||
LayoutDeviceIntRect frameRect = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, scale);
|
LayoutDeviceIntRect frameRect =
|
||||||
|
nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, scale);
|
||||||
if (rect == frameRect) {
|
if (rect == frameRect) {
|
||||||
return screen;
|
return screen;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -18,7 +18,8 @@
|
||||||
namespace mozilla::widget {
|
namespace mozilla::widget {
|
||||||
|
|
||||||
auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
|
auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
|
||||||
const nsTArray<nsCString>& aLanguages) -> RefPtr<NativePromise> {
|
const nsTArray<nsCString>& aLanguages)
|
||||||
|
-> RefPtr<NativePromise> {
|
||||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK
|
||||||
|
|
||||||
// TODO - Is this the most efficient path? Maybe we can write a new
|
// 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;
|
CGImageRef imageRef = NULL;
|
||||||
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(&aSurface, &imageRef);
|
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(&aSurface, &imageRef);
|
||||||
if (NS_FAILED(rv) || !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__);
|
auto promise = MakeRefPtr<NativePromise::Private>(__func__);
|
||||||
|
|
@ -48,47 +50,63 @@ auto TextRecognition::DoFindText(gfx::DataSourceSurface& aSurface,
|
||||||
dom::TextRecognitionResult result;
|
dom::TextRecognitionResult result;
|
||||||
dom::TextRecognitionResult* pResult = &result;
|
dom::TextRecognitionResult* pResult = &result;
|
||||||
|
|
||||||
// Define the request to use, which also handles the result. It will be run below
|
// Define the request to use, which also handles the result. It will
|
||||||
// directly in this thread. After creating this request.
|
// be run below directly in this thread. After creating this
|
||||||
VNRecognizeTextRequest* textRecognitionRequest = [[VNRecognizeTextRequest alloc]
|
// request.
|
||||||
initWithCompletionHandler:^(VNRequest* _Nonnull request, NSError* _Nullable error) {
|
VNRecognizeTextRequest* textRecognitionRequest =
|
||||||
NSArray<VNRecognizedTextObservation*>* observations = request.results;
|
[[VNRecognizeTextRequest alloc] initWithCompletionHandler:^(
|
||||||
|
VNRequest* _Nonnull request,
|
||||||
|
NSError* _Nullable error) {
|
||||||
|
NSArray<VNRecognizedTextObservation*>* observations =
|
||||||
|
request.results;
|
||||||
|
|
||||||
[observations
|
[observations enumerateObjectsUsingBlock:^(
|
||||||
enumerateObjectsUsingBlock:^(VNRecognizedTextObservation* _Nonnull obj,
|
VNRecognizedTextObservation* _Nonnull obj,
|
||||||
NSUInteger idx, BOOL* _Nonnull stop) {
|
NSUInteger idx, BOOL* _Nonnull stop) {
|
||||||
// Requests the n top candidates for a recognized text string.
|
// Requests the n top candidates for a recognized text
|
||||||
VNRecognizedText* recognizedText = [obj topCandidates:1].firstObject;
|
// string.
|
||||||
|
VNRecognizedText* recognizedText =
|
||||||
|
[obj topCandidates:1].firstObject;
|
||||||
|
|
||||||
// https://developer.apple.com/documentation/vision/vnrecognizedtext?language=objc
|
// https://developer.apple.com/documentation/vision/vnrecognizedtext?language=objc
|
||||||
auto& quad = *pResult->quads().AppendElement();
|
auto& quad = *pResult->quads().AppendElement();
|
||||||
CopyCocoaStringToXPCOMString(recognizedText.string, quad.string());
|
CopyCocoaStringToXPCOMString(recognizedText.string,
|
||||||
quad.confidence() = recognizedText.confidence;
|
quad.string());
|
||||||
|
quad.confidence() = recognizedText.confidence;
|
||||||
|
|
||||||
auto ToImagePoint = [](CGPoint aPoint) -> ImagePoint {
|
auto ToImagePoint = [](CGPoint aPoint) -> ImagePoint {
|
||||||
return {static_cast<float>(aPoint.x), static_cast<float>(aPoint.y)};
|
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() =
|
||||||
*quad.points().AppendElement() = ToImagePoint(obj.topRight);
|
ToImagePoint(obj.bottomLeft);
|
||||||
*quad.points().AppendElement() = ToImagePoint(obj.bottomRight);
|
*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.recognitionLanguages = recognitionLanguages;
|
||||||
textRecognitionRequest.usesLanguageCorrection = true;
|
textRecognitionRequest.usesLanguageCorrection = true;
|
||||||
|
|
||||||
// Send out the request. This blocks execution of this thread with an expensive
|
// Send out the request. This blocks execution of this thread with
|
||||||
// CPU call.
|
// an expensive CPU call.
|
||||||
NSError* error = nil;
|
NSError* error = nil;
|
||||||
VNImageRequestHandler* requestHandler =
|
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) {
|
if (error != nil) {
|
||||||
promise->Reject(
|
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__);
|
__func__);
|
||||||
} else {
|
} else {
|
||||||
promise->Resolve(std::move(result), __func__);
|
promise->Resolve(std::move(result), __func__);
|
||||||
|
|
|
||||||
|
|
@ -16,27 +16,29 @@ using namespace mozilla;
|
||||||
@interface MOZVibrantView : NSVisualEffectView {
|
@interface MOZVibrantView : NSVisualEffectView {
|
||||||
VibrancyType mType;
|
VibrancyType mType;
|
||||||
}
|
}
|
||||||
- (instancetype)initWithFrame:(NSRect)aRect vibrancyType:(VibrancyType)aVibrancyType;
|
- (instancetype)initWithFrame:(NSRect)aRect
|
||||||
|
vibrancyType:(VibrancyType)aVibrancyType;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface MOZVibrantLeafView : MOZVibrantView
|
@interface MOZVibrantLeafView : MOZVibrantView
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static NSVisualEffectState VisualEffectStateForVibrancyType(VibrancyType aType) {
|
static NSVisualEffectState VisualEffectStateForVibrancyType(
|
||||||
|
VibrancyType aType) {
|
||||||
switch (aType) {
|
switch (aType) {
|
||||||
case VibrancyType::TOOLTIP:
|
case VibrancyType::TOOLTIP:
|
||||||
case VibrancyType::MENU:
|
case VibrancyType::MENU:
|
||||||
case VibrancyType::HIGHLIGHTED_MENUITEM:
|
case VibrancyType::HIGHLIGHTED_MENUITEM:
|
||||||
// Tooltip and menu windows are never "key", so we need to tell the vibrancy effect to look
|
// Tooltip and menu windows are never "key", so we need to tell the
|
||||||
// active regardless of window state.
|
// vibrancy effect to look active regardless of window state.
|
||||||
return NSVisualEffectStateActive;
|
return NSVisualEffectStateActive;
|
||||||
default:
|
default:
|
||||||
return NSVisualEffectStateFollowsWindowActiveState;
|
return NSVisualEffectStateFollowsWindowActiveState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(VibrancyType aType,
|
static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(
|
||||||
BOOL* aOutIsEmphasized) {
|
VibrancyType aType, BOOL* aOutIsEmphasized) {
|
||||||
switch (aType) {
|
switch (aType) {
|
||||||
case VibrancyType::TOOLTIP:
|
case VibrancyType::TOOLTIP:
|
||||||
return (NSVisualEffectMaterial)NSVisualEffectMaterialToolTip;
|
return (NSVisualEffectMaterial)NSVisualEffectMaterialToolTip;
|
||||||
|
|
@ -90,8 +92,8 @@ static NSVisualEffectMaterial VisualEffectMaterialForVibrancyType(VibrancyType a
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
bool VibrancyManager::UpdateVibrantRegion(VibrancyType aType,
|
bool VibrancyManager::UpdateVibrantRegion(
|
||||||
const LayoutDeviceIntRegion& aRegion) {
|
VibrancyType aType, const LayoutDeviceIntRegion& aRegion) {
|
||||||
if (aRegion.IsEmpty()) {
|
if (aRegion.IsEmpty()) {
|
||||||
return mVibrantRegions.Remove(uint32_t(aType));
|
return mVibrantRegions.Remove(uint32_t(aType));
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +111,10 @@ LayoutDeviceIntRegion VibrancyManager::GetUnionOfVibrantRegions() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType, BOOL aIsContainer) {
|
/* static */ NSView* VibrancyManager::CreateEffectView(VibrancyType aType,
|
||||||
return aIsContainer ? [[MOZVibrantView alloc] initWithFrame:NSZeroRect vibrancyType:aType]
|
BOOL aIsContainer) {
|
||||||
: [[MOZVibrantLeafView alloc] initWithFrame:NSZeroRect vibrancyType:aType];
|
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,
|
bool ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion,
|
||||||
const nsChildView& aCoordinateConverter, NSView* aContainerView,
|
const nsChildView& aCoordinateConverter,
|
||||||
|
NSView* aContainerView,
|
||||||
NSView* (^aViewCreationCallback)()) {
|
NSView* (^aViewCreationCallback)()) {
|
||||||
if (mRegion == aRegion) {
|
if (mRegion == aRegion) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -33,7 +34,8 @@ bool ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion,
|
||||||
// The mViews array is now empty.
|
// The mViews array is now empty.
|
||||||
|
|
||||||
size_t i = 0;
|
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()) {
|
if (!iter.Done()) {
|
||||||
NSView* view = nil;
|
NSView* view = nil;
|
||||||
NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(iter.Get());
|
NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(iter.Get());
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,8 @@
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::widget;
|
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");
|
static mozilla::LazyLogModule gMacWakeLockLog("MacWakeLock");
|
||||||
|
|
||||||
// A wake lock listener that disables screen saver when requested by
|
// A wake lock listener that disables screen saver when requested by
|
||||||
|
|
@ -74,24 +75,30 @@ class MacWakeLockListener final : public nsIDOMMozWakeLockListener {
|
||||||
IOPMAssertionID mAssertionNoDisplaySleepID = kIOPMNullAssertionID;
|
IOPMAssertionID mAssertionNoDisplaySleepID = kIOPMNullAssertionID;
|
||||||
IOPMAssertionID mAssertionNoIdleSleepID = 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") &&
|
if (!aTopic.EqualsASCII("screen") && !aTopic.EqualsASCII("audio-playing") &&
|
||||||
!aTopic.EqualsASCII("video-playing")) {
|
!aTopic.EqualsASCII("video-playing")) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we should still hold the lock for background audio.
|
// 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");
|
WAKE_LOCK_LOG("keep audio playing even in background");
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldKeepDisplayOn = aTopic.EqualsASCII("screen") || aTopic.EqualsASCII("video-playing");
|
bool shouldKeepDisplayOn =
|
||||||
CFStringRef assertionType =
|
aTopic.EqualsASCII("screen") || aTopic.EqualsASCII("video-playing");
|
||||||
shouldKeepDisplayOn ? kIOPMAssertionTypeNoDisplaySleep : kIOPMAssertionTypeNoIdleSleep;
|
CFStringRef assertionType = shouldKeepDisplayOn
|
||||||
IOPMAssertionID& assertionId =
|
? kIOPMAssertionTypeNoDisplaySleep
|
||||||
shouldKeepDisplayOn ? mAssertionNoDisplaySleepID : mAssertionNoIdleSleepID;
|
: kIOPMAssertionTypeNoIdleSleep;
|
||||||
WAKE_LOCK_LOG("topic=%s, state=%s, shouldKeepDisplayOn=%d", NS_ConvertUTF16toUTF8(aTopic).get(),
|
IOPMAssertionID& assertionId = shouldKeepDisplayOn
|
||||||
|
? mAssertionNoDisplaySleepID
|
||||||
|
: mAssertionNoIdleSleepID;
|
||||||
|
WAKE_LOCK_LOG("topic=%s, state=%s, shouldKeepDisplayOn=%d",
|
||||||
|
NS_ConvertUTF16toUTF8(aTopic).get(),
|
||||||
NS_ConvertUTF16toUTF8(aState).get(), shouldKeepDisplayOn);
|
NS_ConvertUTF16toUTF8(aState).get(), shouldKeepDisplayOn);
|
||||||
|
|
||||||
// Note the wake lock code ensures that we're not sent duplicate
|
// Note the wake lock code ensures that we're not sent duplicate
|
||||||
|
|
@ -103,9 +110,10 @@ class MacWakeLockListener final : public nsIDOMMozWakeLockListener {
|
||||||
}
|
}
|
||||||
// Prevent screen saver.
|
// Prevent screen saver.
|
||||||
CFStringRef cf_topic = ::CFStringCreateWithCharacters(
|
CFStringRef cf_topic = ::CFStringCreateWithCharacters(
|
||||||
kCFAllocatorDefault, reinterpret_cast<const UniChar*>(aTopic.Data()), aTopic.Length());
|
kCFAllocatorDefault, reinterpret_cast<const UniChar*>(aTopic.Data()),
|
||||||
IOReturn success = ::IOPMAssertionCreateWithName(assertionType, kIOPMAssertionLevelOn,
|
aTopic.Length());
|
||||||
cf_topic, &assertionId);
|
IOReturn success = ::IOPMAssertionCreateWithName(
|
||||||
|
assertionType, kIOPMAssertionLevelOn, cf_topic, &assertionId);
|
||||||
CFRelease(cf_topic);
|
CFRelease(cf_topic);
|
||||||
if (success != kIOReturnSuccess) {
|
if (success != kIOReturnSuccess) {
|
||||||
WAKE_LOCK_LOG("failed to disable screensaver");
|
WAKE_LOCK_LOG("failed to disable screensaver");
|
||||||
|
|
@ -133,19 +141,21 @@ static bool gAppShellMethodsSwizzled = false;
|
||||||
|
|
||||||
void OnUncaughtException(NSException* aException) {
|
void OnUncaughtException(NSException* aException) {
|
||||||
nsObjCExceptionLog(aException);
|
nsObjCExceptionLog(aException);
|
||||||
MOZ_CRASH("Uncaught Objective C exception from NSSetUncaughtExceptionHandler");
|
MOZ_CRASH(
|
||||||
|
"Uncaught Objective C exception from NSSetUncaughtExceptionHandler");
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation GeckoNSApplication
|
@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 {
|
+ (void)load {
|
||||||
NSSetUncaughtExceptionHandler(OnUncaughtException);
|
NSSetUncaughtExceptionHandler(OnUncaughtException);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is called from NSDefaultTopLevelErrorHandler, which is invoked when an Objective C
|
// This method is called from NSDefaultTopLevelErrorHandler, which is invoked
|
||||||
// exception propagates up into the native event loop. It is possible that it is also called in
|
// when an Objective C exception propagates up into the native event loop. It is
|
||||||
// other cases.
|
// possible that it is also called in other cases.
|
||||||
- (void)reportException:(NSException*)aException {
|
- (void)reportException:(NSException*)aException {
|
||||||
if (ShouldIgnoreObjCException(aException)) {
|
if (ShouldIgnoreObjCException(aException)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -154,14 +164,16 @@ void OnUncaughtException(NSException* aException) {
|
||||||
nsObjCExceptionLog(aException);
|
nsObjCExceptionLog(aException);
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
#ifdef NIGHTLY_BUILD
|
||||||
MOZ_CRASH("Uncaught Objective C exception from -[GeckoNSApplication reportException:]");
|
MOZ_CRASH("Uncaught Objective C exception from -[GeckoNSApplication "
|
||||||
|
"reportException:]");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendEvent:(NSEvent*)anEvent {
|
- (void)sendEvent:(NSEvent*)anEvent {
|
||||||
mozilla::BackgroundHangMonitor().NotifyActivity();
|
mozilla::BackgroundHangMonitor().NotifyActivity();
|
||||||
|
|
||||||
if ([anEvent type] == NSEventTypeApplicationDefined && [anEvent subtype] == kEventSubtypeTrace) {
|
if ([anEvent type] == NSEventTypeApplicationDefined &&
|
||||||
|
[anEvent subtype] == kEventSubtypeTrace) {
|
||||||
mozilla::SignalTracerThread();
|
mozilla::SignalTracerThread();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -208,7 +220,8 @@ void OnUncaughtException(NSException* aException) {
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsAppShell::ResumeNative(void) {
|
nsAppShell::ResumeNative(void) {
|
||||||
nsresult retval = nsBaseAppShell::ResumeNative();
|
nsresult retval = nsBaseAppShell::ResumeNative();
|
||||||
if (NS_SUCCEEDED(retval) && (mSuspendNativeCount == 0) && mSkippedNativeCallback) {
|
if (NS_SUCCEEDED(retval) && (mSuspendNativeCount == 0) &&
|
||||||
|
mSkippedNativeCallback) {
|
||||||
mSkippedNativeCallback = false;
|
mSkippedNativeCallback = false;
|
||||||
ScheduleNativeEventCallback();
|
ScheduleNativeEventCallback();
|
||||||
}
|
}
|
||||||
|
|
@ -243,11 +256,13 @@ nsAppShell::~nsAppShell() {
|
||||||
|
|
||||||
if (mCFRunLoop) {
|
if (mCFRunLoop) {
|
||||||
if (mCFRunLoopSource) {
|
if (mCFRunLoopSource) {
|
||||||
::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
|
::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
::CFRelease(mCFRunLoopSource);
|
::CFRelease(mCFRunLoopSource);
|
||||||
}
|
}
|
||||||
if (mCFRunLoopObserver) {
|
if (mCFRunLoopObserver) {
|
||||||
::CFRunLoopRemoveObserver(mCFRunLoop, mCFRunLoopObserver, kCFRunLoopCommonModes);
|
::CFRunLoopRemoveObserver(mCFRunLoop, mCFRunLoopObserver,
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
::CFRelease(mCFRunLoopObserver);
|
::CFRelease(mCFRunLoopObserver);
|
||||||
}
|
}
|
||||||
::CFRelease(mCFRunLoop);
|
::CFRelease(mCFRunLoop);
|
||||||
|
|
@ -274,7 +289,8 @@ static void AddScreenWakeLockListener() {
|
||||||
sWakeLockListener = new MacWakeLockListener();
|
sWakeLockListener = new MacWakeLockListener();
|
||||||
sPowerManagerService->AddWakeLockListener(sWakeLockListener);
|
sPowerManagerService->AddWakeLockListener(sWakeLockListener);
|
||||||
} else {
|
} 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 RunLoopObserverCallback(CFRunLoopObserverRef aObserver,
|
||||||
void* aInfo) {
|
CFRunLoopActivity aActivity, void* aInfo) {
|
||||||
static_cast<nsAppShell*>(aInfo)->OnRunLoopActivityChanged(aActivity);
|
static_cast<nsAppShell*>(aInfo)->OnRunLoopActivityChanged(aActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,30 +314,34 @@ void nsAppShell::OnRunLoopActivityChanged(CFRunLoopActivity aActivity) {
|
||||||
mozilla::BackgroundHangMonitor().NotifyWait();
|
mozilla::BackgroundHangMonitor().NotifyWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the event loop is in its waiting state, we would like the profiler to know that the thread
|
// When the event loop is in its waiting state, we would like the profiler to
|
||||||
// is idle. The usual way to notify the profiler of idleness would be to place a profiler label
|
// know that the thread is idle. The usual way to notify the profiler of
|
||||||
// frame with the IDLE category on the stack, for the duration of the function that does the
|
// idleness would be to place a profiler label frame with the IDLE category on
|
||||||
// waiting. However, since macOS uses an event loop model where "the event loop calls you", we do
|
// the stack, for the duration of the function that does the waiting. However,
|
||||||
// not control the function that does the waiting; the waiting happens inside CFRunLoop code.
|
// since macOS uses an event loop model where "the event loop calls you", we
|
||||||
// Instead, the run loop notifies us when it enters and exits the waiting state, by calling this
|
// do not control the function that does the waiting; the waiting happens
|
||||||
// function.
|
// inside CFRunLoop code. Instead, the run loop notifies us when it enters and
|
||||||
// So we do not have a function under our control that stays on the stack for the duration of the
|
// exits the waiting state, by calling this function. So we do not have a
|
||||||
// wait. So, rather than putting an AutoProfilerLabel on the stack, we will manually push and pop
|
// function under our control that stays on the stack for the duration of the
|
||||||
// the label frame here.
|
// wait. So, rather than putting an AutoProfilerLabel on the stack, we will
|
||||||
// The location in the stack where this label frame is inserted is somewhat arbitrary. In
|
// manually push and pop the label frame here. The location in the stack where
|
||||||
// practice, the label frame will be at the very tip of the stack, looking like it's "inside" the
|
// 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.
|
// mach_msg_trap wait function.
|
||||||
if (aActivity == kCFRunLoopBeforeWaiting) {
|
if (aActivity == kCFRunLoopBeforeWaiting) {
|
||||||
using ThreadRegistration = mozilla::profiler::ThreadRegistration;
|
using ThreadRegistration = mozilla::profiler::ThreadRegistration;
|
||||||
ThreadRegistration::WithOnThreadRef([&](ThreadRegistration::OnThreadRef aOnThreadRef) {
|
ThreadRegistration::WithOnThreadRef(
|
||||||
ProfilingStack& profilingStack =
|
[&](ThreadRegistration::OnThreadRef aOnThreadRef) {
|
||||||
aOnThreadRef.UnlockedConstReaderAndAtomicRWRef().ProfilingStackRef();
|
ProfilingStack& profilingStack =
|
||||||
mProfilingStackWhileWaiting = &profilingStack;
|
aOnThreadRef.UnlockedConstReaderAndAtomicRWRef()
|
||||||
uint8_t variableOnStack = 0;
|
.ProfilingStackRef();
|
||||||
profilingStack.pushLabelFrame("Native event loop idle", nullptr, &variableOnStack,
|
mProfilingStackWhileWaiting = &profilingStack;
|
||||||
JS::ProfilingCategoryPair::IDLE, 0);
|
uint8_t variableOnStack = 0;
|
||||||
profiler_thread_sleep();
|
profilingStack.pushLabelFrame("Native event loop idle", nullptr,
|
||||||
});
|
&variableOnStack,
|
||||||
|
JS::ProfilingCategoryPair::IDLE, 0);
|
||||||
|
profiler_thread_sleep();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
if (mProfilingStackWhileWaiting) {
|
if (mProfilingStackWhileWaiting) {
|
||||||
mProfilingStackWhileWaiting->pop();
|
mProfilingStackWhileWaiting->pop();
|
||||||
|
|
@ -356,8 +376,9 @@ nsresult nsAppShell::Init() {
|
||||||
mAutoreleasePools = ::CFArrayCreateMutable(nullptr, 0, nullptr);
|
mAutoreleasePools = ::CFArrayCreateMutable(nullptr, 0, nullptr);
|
||||||
NS_ENSURE_STATE(mAutoreleasePools);
|
NS_ENSURE_STATE(mAutoreleasePools);
|
||||||
|
|
||||||
bool isNSApplicationProcessType = (XRE_GetProcessType() != GeckoProcessType_RDD) &&
|
bool isNSApplicationProcessType =
|
||||||
(XRE_GetProcessType() != GeckoProcessType_Socket);
|
(XRE_GetProcessType() != GeckoProcessType_RDD) &&
|
||||||
|
(XRE_GetProcessType() != GeckoProcessType_Socket);
|
||||||
|
|
||||||
if (isNSApplicationProcessType) {
|
if (isNSApplicationProcessType) {
|
||||||
// This call initializes NSApplication unless:
|
// This call initializes NSApplication unless:
|
||||||
|
|
@ -391,14 +412,15 @@ nsresult nsAppShell::Init() {
|
||||||
|
|
||||||
::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
|
::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
|
||||||
|
|
||||||
// Add a CFRunLoopObserver so that the profiler can be notified when we enter and exit the waiting
|
// Add a CFRunLoopObserver so that the profiler can be notified when we enter
|
||||||
// state.
|
// and exit the waiting state.
|
||||||
CFRunLoopObserverContext observerContext;
|
CFRunLoopObserverContext observerContext;
|
||||||
PodZero(&observerContext);
|
PodZero(&observerContext);
|
||||||
observerContext.info = this;
|
observerContext.info = this;
|
||||||
|
|
||||||
mCFRunLoopObserver = ::CFRunLoopObserverCreate(
|
mCFRunLoopObserver = ::CFRunLoopObserverCreate(
|
||||||
kCFAllocatorDefault, kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting | kCFRunLoopExit, true,
|
kCFAllocatorDefault,
|
||||||
|
kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting | kCFRunLoopExit, true,
|
||||||
0, RunLoopObserverCallback, &observerContext);
|
0, RunLoopObserverCallback, &observerContext);
|
||||||
NS_ENSURE_STATE(mCFRunLoopObserver);
|
NS_ENSURE_STATE(mCFRunLoopObserver);
|
||||||
|
|
||||||
|
|
@ -491,9 +513,10 @@ void nsAppShell::ProcessGeckoEvents(void* aInfo) {
|
||||||
// DummyEvent inserted by nsBaseAppShell::OnProcessNextEvent. This second
|
// DummyEvent inserted by nsBaseAppShell::OnProcessNextEvent. This second
|
||||||
// event will cause the second call to AcquireFirstMatchingEventInQueue in
|
// event will cause the second call to AcquireFirstMatchingEventInQueue in
|
||||||
// nsAppShell::ProcessNextNativeEvent to return true. Which makes
|
// nsAppShell::ProcessNextNativeEvent to return true. Which makes
|
||||||
// nsBaseAppShell::OnProcessNextEvent call nsAppShell::ProcessNextNativeEvent
|
// nsBaseAppShell::OnProcessNextEvent call
|
||||||
// again during which it will loop until it sleeps because ProcessGeckoEvents()
|
// nsAppShell::ProcessNextNativeEvent again during which it will loop until
|
||||||
// won't be called for the DummyEvent.
|
// 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
|
// This is not a good approach and we should fix things up so that only
|
||||||
// one postEvent is needed.
|
// one postEvent is needed.
|
||||||
|
|
@ -551,8 +574,8 @@ void nsAppShell::ProcessGeckoEvents(void* aInfo) {
|
||||||
if (self->mTerminated) {
|
if (self->mTerminated) {
|
||||||
int32_t releaseCount = 0;
|
int32_t releaseCount = 0;
|
||||||
if (self->mNativeEventScheduledDepth > self->mNativeEventCallbackDepth) {
|
if (self->mNativeEventScheduledDepth > self->mNativeEventCallbackDepth) {
|
||||||
releaseCount =
|
releaseCount = PR_ATOMIC_SET(&self->mNativeEventScheduledDepth,
|
||||||
PR_ATOMIC_SET(&self->mNativeEventScheduledDepth, self->mNativeEventCallbackDepth);
|
self->mNativeEventCallbackDepth);
|
||||||
}
|
}
|
||||||
while (releaseCount-- > self->mNativeEventCallbackDepth) self->Release();
|
while (releaseCount-- > self->mNativeEventCallbackDepth) self->Release();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -651,10 +674,10 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
||||||
|
|
||||||
if (mTerminated) return false;
|
if (mTerminated) return false;
|
||||||
|
|
||||||
// Do not call -[NSApplication nextEventMatchingMask:...] when we're trying to close a native
|
// Do not call -[NSApplication nextEventMatchingMask:...] when we're trying to
|
||||||
// menu. Doing so could confuse the NSMenu's closing mechanism. Instead, we try to unwind the
|
// close a native menu. Doing so could confuse the NSMenu's closing mechanism.
|
||||||
// stack as quickly as possible and return to the parent event loop. At that point, native events
|
// Instead, we try to unwind the stack as quickly as possible and return to
|
||||||
// will be processed.
|
// the parent event loop. At that point, native events will be processed.
|
||||||
if (MOZMenuOpeningCoordinator.needToUnwindForMenuClosing) {
|
if (MOZMenuOpeningCoordinator.needToUnwindForMenuClosing) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -700,12 +723,13 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// In at least 10.15, AcquireFirstMatchingEventInQueue will move 1
|
// In at least 10.15, AcquireFirstMatchingEventInQueue will move 1
|
||||||
// CGEvent from the CGEvent queue into the Carbon event queue. Unfortunately,
|
// CGEvent from the CGEvent queue into the Carbon event queue.
|
||||||
// once an event has been moved to the Carbon event queue it's no longer a
|
// Unfortunately, once an event has been moved to the Carbon event queue
|
||||||
// candidate for coalescing. This means that even if we don't remove the
|
// it's no longer a candidate for coalescing. This means that even if we
|
||||||
// event from the queue, just calling AcquireFirstMatchingEventInQueue can
|
// don't remove the event from the queue, just calling
|
||||||
// cause behaviour change. Prior to bug 1690687 landing, the event that we got
|
// AcquireFirstMatchingEventInQueue can cause behaviour change. Prior to
|
||||||
// from AcquireFirstMatchingEventInQueue was often our own ApplicationDefined
|
// 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. 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
|
// 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
|
// 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
|
// AcquireFirstMatchingEventInQueue() doesn't spin the (native) event
|
||||||
// loop, though it does queue up any newly available events from the
|
// loop, though it does queue up any newly available events from the
|
||||||
// window server.
|
// window server.
|
||||||
EventRef currentEvent =
|
EventRef currentEvent = AcquireFirstMatchingEventInQueue(
|
||||||
AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL, kEventQueueOptionsNone);
|
currentEventQueue, 0, NULL, kEventQueueOptionsNone);
|
||||||
if (!currentEvent) {
|
if (!currentEvent) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -729,7 +753,8 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
||||||
UInt32 eventClass = GetEventClass(currentEvent);
|
UInt32 eventClass = GetEventClass(currentEvent);
|
||||||
bool osCocoaEvent =
|
bool osCocoaEvent =
|
||||||
((eventClass == 'appl') || (eventClass == kEventClassAppleEvent) ||
|
((eventClass == 'appl') || (eventClass == kEventClassAppleEvent) ||
|
||||||
((eventClass == 'cgs ') && (eventKind != NSEventTypeApplicationDefined)));
|
((eventClass == 'cgs ') &&
|
||||||
|
(eventKind != NSEventTypeApplicationDefined)));
|
||||||
// If attrs is kEventAttributeUserEvent or kEventAttributeMonitored
|
// If attrs is kEventAttributeUserEvent or kEventAttributeMonitored
|
||||||
// (i.e. a user input event), we shouldn't process it here while
|
// (i.e. a user input event), we shouldn't process it here while
|
||||||
// aMayWait is false. Likewise if currentEvent will eventually be
|
// aMayWait is false. Likewise if currentEvent will eventually be
|
||||||
|
|
@ -761,8 +786,9 @@ bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
|
||||||
} while (mRunningEventLoop);
|
} while (mRunningEventLoop);
|
||||||
|
|
||||||
if (eventProcessed) {
|
if (eventProcessed) {
|
||||||
moreEvents = (AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
|
moreEvents =
|
||||||
kEventQueueOptionsNone) != NULL);
|
(AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
|
||||||
|
kEventQueueOptionsNone) != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
mRunningEventLoop = wasRunningEventLoop;
|
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
|
// (Ventura) than on other versions of macOS. So we only use this hack on
|
||||||
// macOS 13 and up.
|
// macOS 13 and up.
|
||||||
static void PinSidecarCoreTextCStringSections() {
|
static void PinSidecarCoreTextCStringSections() {
|
||||||
if (!dlopen("/System/Library/PrivateFrameworks/SidecarCore.framework/SidecarCore", RTLD_LAZY)) {
|
if (!dlopen(
|
||||||
|
"/System/Library/PrivateFrameworks/SidecarCore.framework/SidecarCore",
|
||||||
|
RTLD_LAZY)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -798,7 +826,8 @@ static void PinSidecarCoreTextCStringSections() {
|
||||||
// normally runs automatically on the first Cmd-key combination.
|
// normally runs automatically on the first Cmd-key combination.
|
||||||
Class displayManagerClass = NSClassFromString(@"SidecarDisplayManager");
|
Class displayManagerClass = NSClassFromString(@"SidecarDisplayManager");
|
||||||
if ([displayManagerClass respondsToSelector:@selector(sharedManager)]) {
|
if ([displayManagerClass respondsToSelector:@selector(sharedManager)]) {
|
||||||
id sharedManager = [displayManagerClass performSelector:@selector(sharedManager)];
|
id sharedManager =
|
||||||
|
[displayManagerClass performSelector:@selector(sharedManager)];
|
||||||
if ([sharedManager respondsToSelector:@selector(devices)]) {
|
if ([sharedManager respondsToSelector:@selector(devices)]) {
|
||||||
[sharedManager performSelector:@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:]
|
// [NSApp stop:], so we have to assume that one extra call to [NSApp stop:]
|
||||||
// will do the job.)
|
// will do the job.)
|
||||||
BOOL cocoaModal = [NSApp _isRunningModal];
|
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];
|
if (cocoaModal) [NSApp stop:nullptr];
|
||||||
[NSApp stop:nullptr];
|
[NSApp stop:nullptr];
|
||||||
|
|
||||||
|
|
@ -911,7 +941,8 @@ NS_IMETHODIMP
|
||||||
nsAppShell::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) {
|
nsAppShell::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
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];
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
::CFArrayAppendValue(mAutoreleasePools, pool);
|
::CFArrayAppendValue(mAutoreleasePools, pool);
|
||||||
|
|
@ -929,15 +960,17 @@ nsAppShell::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait) {
|
||||||
//
|
//
|
||||||
// public
|
// public
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsAppShell::AfterProcessNextEvent(nsIThreadInternal* aThread, bool aEventWasProcessed) {
|
nsAppShell::AfterProcessNextEvent(nsIThreadInternal* aThread,
|
||||||
|
bool aEventWasProcessed) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
CFIndex count = ::CFArrayGetCount(mAutoreleasePools);
|
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 =
|
const NSAutoreleasePool* pool = static_cast<const NSAutoreleasePool*>(
|
||||||
static_cast<const NSAutoreleasePool*>(::CFArrayGetValueAtIndex(mAutoreleasePools, count - 1));
|
::CFArrayGetValueAtIndex(mAutoreleasePools, count - 1));
|
||||||
::CFArrayRemoveValueAtIndex(mAutoreleasePools, count - 1);
|
::CFArrayRemoveValueAtIndex(mAutoreleasePools, count - 1);
|
||||||
[pool release];
|
[pool release];
|
||||||
|
|
||||||
|
|
@ -952,11 +985,11 @@ void nsAppShell::InitMemoryPressureObserver() {
|
||||||
// values. Hence this may need to be augmented with polling of the memory
|
// values. Hence this may need to be augmented with polling of the memory
|
||||||
// pressure sysctls for lower latency reactions to OS memory pressure. This
|
// pressure sysctls for lower latency reactions to OS memory pressure. This
|
||||||
// was also observed when using DISPATCH_QUEUE_PRIORITY_HIGH.
|
// was also observed when using DISPATCH_QUEUE_PRIORITY_HIGH.
|
||||||
mMemoryPressureSource =
|
mMemoryPressureSource = dispatch_source_create(
|
||||||
dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
|
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
|
||||||
DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN |
|
DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN |
|
||||||
DISPATCH_MEMORYPRESSURE_CRITICAL,
|
DISPATCH_MEMORYPRESSURE_CRITICAL,
|
||||||
dispatch_get_main_queue());
|
dispatch_get_main_queue());
|
||||||
|
|
||||||
dispatch_source_set_event_handler(mMemoryPressureSource, ^{
|
dispatch_source_set_event_handler(mMemoryPressureSource, ^{
|
||||||
dispatch_source_memorypressure_flags_t pressureLevel =
|
dispatch_source_memorypressure_flags_t pressureLevel =
|
||||||
|
|
@ -971,7 +1004,8 @@ void nsAppShell::InitMemoryPressureObserver() {
|
||||||
nsAvailableMemoryWatcherBase::GetSingleton());
|
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
|
// The memory pressure dispatch source is created (above) with
|
||||||
// dispatch_get_main_queue() which always fires on the main thread.
|
// dispatch_get_main_queue() which always fires on the main thread.
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
@ -1008,18 +1042,21 @@ void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t
|
||||||
if ((self = [self init])) {
|
if ((self = [self init])) {
|
||||||
mAppShell = aAppShell;
|
mAppShell = aAppShell;
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter]
|
||||||
selector:@selector(applicationWillTerminate:)
|
addObserver:self
|
||||||
name:NSApplicationWillTerminateNotification
|
selector:@selector(applicationWillTerminate:)
|
||||||
object:NSApp];
|
name:NSApplicationWillTerminateNotification
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
object:NSApp];
|
||||||
selector:@selector(applicationDidBecomeActive:)
|
[[NSNotificationCenter defaultCenter]
|
||||||
name:NSApplicationDidBecomeActiveNotification
|
addObserver:self
|
||||||
object:NSApp];
|
selector:@selector(applicationDidBecomeActive:)
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
name:NSApplicationDidBecomeActiveNotification
|
||||||
selector:@selector(timezoneChanged:)
|
object:NSApp];
|
||||||
name:NSSystemTimeZoneDidChangeNotification
|
[[NSNotificationCenter defaultCenter]
|
||||||
object:nil];
|
addObserver:self
|
||||||
|
selector:@selector(timezoneChanged:)
|
||||||
|
name:NSSystemTimeZoneDidChangeNotification
|
||||||
|
object:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|
@ -1061,12 +1098,14 @@ void nsAppShell::OnMemoryPressureChanged(dispatch_source_memorypressure_flags_t
|
||||||
NSEvent* currentEvent = [NSApp currentEvent];
|
NSEvent* currentEvent = [NSApp currentEvent];
|
||||||
if (currentEvent) {
|
if (currentEvent) {
|
||||||
TextInputHandler::sLastModifierState =
|
TextInputHandler::sLastModifierState =
|
||||||
[currentEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
[currentEvent modifierFlags] &
|
||||||
|
NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
||||||
if (observerService) {
|
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;
|
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
|
// in XRE_Main(), which in particular means that ScopedXPCOMStartup's destructor
|
||||||
// and NS_ShutdownXPCOM() never get called.
|
// and NS_ShutdownXPCOM() never get called.
|
||||||
- (void)nsAppShell_NSApplication_terminate:(id)sender {
|
- (void)nsAppShell_NSApplication_terminate:(id)sender {
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification
|
[[NSNotificationCenter defaultCenter]
|
||||||
object:NSApp];
|
postNotificationName:NSApplicationWillTerminateNotification
|
||||||
|
object:NSApp];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -32,9 +32,10 @@ mozilla::StaticRefPtr<nsITransferable> nsClipboard::sSelectionCache;
|
||||||
int32_t nsClipboard::sSelectionCacheChangeCount = 0;
|
int32_t nsClipboard::sSelectionCacheChangeCount = 0;
|
||||||
|
|
||||||
nsClipboard::nsClipboard()
|
nsClipboard::nsClipboard()
|
||||||
: nsBaseClipboard(mozilla::dom::ClipboardCapabilities(false /* supportsSelectionClipboard */,
|
: nsBaseClipboard(mozilla::dom::ClipboardCapabilities(
|
||||||
true /* supportsFindClipboard */,
|
false /* supportsSelectionClipboard */,
|
||||||
true /* supportsSelectionCache */)) {}
|
true /* supportsFindClipboard */,
|
||||||
|
true /* supportsSelectionCache */)) {}
|
||||||
|
|
||||||
nsClipboard::~nsClipboard() { ClearSelectionCache(); }
|
nsClipboard::~nsClipboard() { ClearSelectionCache(); }
|
||||||
|
|
||||||
|
|
@ -45,15 +46,16 @@ namespace {
|
||||||
// We separate this into its own function because after an @try, all local
|
// 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
|
// variables within that function get marked as volatile, and our C++ type
|
||||||
// system doesn't like volatile things.
|
// system doesn't like volatile things.
|
||||||
static NSData* GetDataFromPasteboard(NSPasteboard* aPasteboard, NSString* aType) {
|
static NSData* GetDataFromPasteboard(NSPasteboard* aPasteboard,
|
||||||
|
NSString* aType) {
|
||||||
NSData* data = nil;
|
NSData* data = nil;
|
||||||
@try {
|
@try {
|
||||||
data = [aPasteboard dataForType:aType];
|
data = [aPasteboard dataForType:aType];
|
||||||
} @catch (NSException* e) {
|
} @catch (NSException* e) {
|
||||||
NS_WARNING(
|
NS_WARNING(nsPrintfCString("Exception raised while getting data from the "
|
||||||
nsPrintfCString("Exception raised while getting data from the pasteboard: \"%s - %s\"",
|
"pasteboard: \"%s - %s\"",
|
||||||
[[e name] UTF8String], [[e reason] UTF8String])
|
[[e name] UTF8String], [[e reason] UTF8String])
|
||||||
.get());
|
.get());
|
||||||
mozilla::Unused << e;
|
mozilla::Unused << e;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
|
@ -80,7 +82,8 @@ void nsClipboard::SetSelectionCache(nsITransferable* aTransferable) {
|
||||||
void nsClipboard::ClearSelectionCache() { SetSelectionCache(nullptr); }
|
void nsClipboard::ClearSelectionCache() { SetSelectionCache(nullptr); }
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboardOwner* aOwner,
|
nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable,
|
||||||
|
nsIClipboardOwner* aOwner,
|
||||||
int32_t aWhichClipboard) {
|
int32_t aWhichClipboard) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
|
|
@ -92,7 +95,8 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(aTransferable);
|
NSDictionary* pasteboardOutputDict =
|
||||||
|
PasteboardDictFromTransferable(aTransferable);
|
||||||
if (!pasteboardOutputDict) return NS_ERROR_FAILURE;
|
if (!pasteboardOutputDict) return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
unsigned int outputCount = [pasteboardOutputDict count];
|
unsigned int outputCount = [pasteboardOutputDict count];
|
||||||
|
|
@ -100,8 +104,10 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
|
||||||
NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
|
NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
|
||||||
MOZ_ASSERT(cocoaPasteboard);
|
MOZ_ASSERT(cocoaPasteboard);
|
||||||
if (aWhichClipboard == kFindClipboard) {
|
if (aWhichClipboard == kFindClipboard) {
|
||||||
NSString* stringType = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
NSString* stringType =
|
||||||
[cocoaPasteboard declareTypes:[NSArray arrayWithObject:stringType] owner:nil];
|
[UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
||||||
|
[cocoaPasteboard declareTypes:[NSArray arrayWithObject:stringType]
|
||||||
|
owner:nil];
|
||||||
} else {
|
} else {
|
||||||
// Write everything else out to the general pasteboard.
|
// Write everything else out to the general pasteboard.
|
||||||
MOZ_ASSERT(aWhichClipboard == kGlobalClipboard);
|
MOZ_ASSERT(aWhichClipboard == kGlobalClipboard);
|
||||||
|
|
@ -112,32 +118,48 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
|
||||||
NSString* currentKey = [outputKeys objectAtIndex:i];
|
NSString* currentKey = [outputKeys objectAtIndex:i];
|
||||||
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
||||||
if (aWhichClipboard == kFindClipboard) {
|
if (aWhichClipboard == kFindClipboard) {
|
||||||
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeString]]) {
|
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:
|
||||||
|
NSPasteboardTypeString]]) {
|
||||||
[cocoaPasteboard setString:currentValue forType:currentKey];
|
[cocoaPasteboard setString:currentValue forType:currentKey];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeString]] ||
|
if ([currentKey isEqualToString:[UTIHelper stringFromPboardType:
|
||||||
[currentKey isEqualToString:[UTIHelper stringFromPboardType:kPublicUrlPboardType]] ||
|
NSPasteboardTypeString]] ||
|
||||||
[currentKey isEqualToString:[UTIHelper stringFromPboardType:kPublicUrlNamePboardType]]) {
|
[currentKey
|
||||||
|
isEqualToString:[UTIHelper
|
||||||
|
stringFromPboardType:kPublicUrlPboardType]] ||
|
||||||
|
[currentKey
|
||||||
|
isEqualToString:
|
||||||
|
[UTIHelper stringFromPboardType:kPublicUrlNamePboardType]]) {
|
||||||
[cocoaPasteboard setString:currentValue forType:currentKey];
|
[cocoaPasteboard setString:currentValue forType:currentKey];
|
||||||
} else if ([currentKey
|
} else if ([currentKey
|
||||||
isEqualToString:[UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType]]) {
|
isEqualToString:
|
||||||
[cocoaPasteboard setPropertyList:[pasteboardOutputDict valueForKey:currentKey]
|
[UTIHelper
|
||||||
forType:currentKey];
|
stringFromPboardType:kUrlsWithTitlesPboardType]]) {
|
||||||
|
[cocoaPasteboard
|
||||||
|
setPropertyList:[pasteboardOutputDict valueForKey:currentKey]
|
||||||
|
forType:currentKey];
|
||||||
} else if ([currentKey
|
} else if ([currentKey
|
||||||
isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeHTML]]) {
|
isEqualToString:[UTIHelper stringFromPboardType:
|
||||||
[cocoaPasteboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
|
NSPasteboardTypeHTML]]) {
|
||||||
forType:currentKey];
|
[cocoaPasteboard
|
||||||
|
setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
|
||||||
|
forType:currentKey];
|
||||||
} else if ([currentKey
|
} else if ([currentKey
|
||||||
isEqualToString:[UTIHelper stringFromPboardType:kMozFileUrlsPboardType]]) {
|
isEqualToString:[UTIHelper stringFromPboardType:
|
||||||
|
kMozFileUrlsPboardType]]) {
|
||||||
[cocoaPasteboard writeObjects:currentValue];
|
[cocoaPasteboard writeObjects:currentValue];
|
||||||
} else if ([currentKey
|
} else if ([currentKey
|
||||||
isEqualToString:[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]]) {
|
isEqualToString:
|
||||||
|
[UTIHelper
|
||||||
|
stringFromPboardType:(NSString*)kUTTypeFileURL]]) {
|
||||||
[cocoaPasteboard setString:currentValue forType:currentKey];
|
[cocoaPasteboard setString:currentValue forType:currentKey];
|
||||||
} else if ([currentKey
|
} else if ([currentKey
|
||||||
isEqualToString:[UTIHelper stringFromPboardType:kPasteboardConcealedType]]) {
|
isEqualToString:
|
||||||
// It's fine to set the data to null for this field - this field is an addition
|
[UTIHelper
|
||||||
// to a value's other type and works like a flag.
|
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];
|
[cocoaPasteboard setData:NULL forType:currentKey];
|
||||||
} else {
|
} else {
|
||||||
[cocoaPasteboard setData:currentValue forType:currentKey];
|
[cocoaPasteboard setData:currentValue forType:currentKey];
|
||||||
|
|
@ -150,12 +172,12 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, nsIClipboard
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
nsresult nsClipboard::TransferableFromPasteboard(
|
||||||
NSPasteboard* cocoaPasteboard) {
|
nsITransferable* aTransferable, NSPasteboard* cocoaPasteboard) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
// get flavor list that includes all acceptable flavors (including ones obtained through
|
// get flavor list that includes all acceptable flavors (including ones
|
||||||
// conversion)
|
// obtained through conversion)
|
||||||
nsTArray<nsCString> flavors;
|
nsTArray<nsCString> flavors;
|
||||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||||
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
||||||
|
|
@ -173,8 +195,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* stringData;
|
NSData* stringData;
|
||||||
bool isRTF =
|
bool isRTF = [pboardType
|
||||||
[pboardType isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]];
|
isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]];
|
||||||
if (isRTF) {
|
if (isRTF) {
|
||||||
stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
|
stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -187,23 +209,25 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||||
}
|
}
|
||||||
[stringData getBytes:clipboardDataPtr length:dataLength];
|
[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;
|
int32_t signedDataLength = dataLength;
|
||||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(isRTF, &clipboardDataPtr,
|
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
|
||||||
&signedDataLength);
|
isRTF, &clipboardDataPtr, &signedDataLength);
|
||||||
dataLength = signedDataLength;
|
dataLength = signedDataLength;
|
||||||
|
|
||||||
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
||||||
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
|
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
|
||||||
if ((dataLength > 2) &&
|
if ((dataLength > 2) && ((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
|
||||||
((clipboardDataPtrNoBOM[0] == 0xFEFF) || (clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
(clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
||||||
dataLength -= sizeof(char16_t);
|
dataLength -= sizeof(char16_t);
|
||||||
clipboardDataPtrNoBOM += 1;
|
clipboardDataPtrNoBOM += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
|
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||||
getter_AddRefs(genericDataWrapper));
|
flavorStr, clipboardDataPtrNoBOM, dataLength,
|
||||||
|
getter_AddRefs(genericDataWrapper));
|
||||||
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
|
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
|
||||||
free(clipboardDataPtr);
|
free(clipboardDataPtr);
|
||||||
break;
|
break;
|
||||||
|
|
@ -220,11 +244,14 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable, flavorStr, item);
|
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable,
|
||||||
|
flavorStr, item);
|
||||||
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||||
NSString* type = [cocoaPasteboard
|
NSString* type = [cocoaPasteboard
|
||||||
availableTypeFromArray:
|
availableTypeFromArray:
|
||||||
[NSArray arrayWithObject:[UTIHelper stringFromPboardType:kMozCustomTypesPboardType]]];
|
[NSArray
|
||||||
|
arrayWithObject:[UTIHelper stringFromPboardType:
|
||||||
|
kMozCustomTypesPboardType]]];
|
||||||
if (!type) {
|
if (!type) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -242,19 +269,26 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||||
[pasteboardData getBytes:clipboardDataPtr length:dataLength];
|
[pasteboardData getBytes:clipboardDataPtr length:dataLength];
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
|
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||||
getter_AddRefs(genericDataWrapper));
|
flavorStr, clipboardDataPtr, dataLength,
|
||||||
|
getter_AddRefs(genericDataWrapper));
|
||||||
|
|
||||||
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
|
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
|
||||||
free(clipboardDataPtr);
|
free(clipboardDataPtr);
|
||||||
} else if (flavorStr.EqualsLiteral(kJPEGImageMime) || flavorStr.EqualsLiteral(kJPGImageMime) ||
|
} else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||||
flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) {
|
flavorStr.EqualsLiteral(kJPGImageMime) ||
|
||||||
|
flavorStr.EqualsLiteral(kPNGImageMime) ||
|
||||||
|
flavorStr.EqualsLiteral(kGIFImageMime)) {
|
||||||
// Figure out if there's data on the pasteboard we can grab (sanity check)
|
// Figure out if there's data on the pasteboard we can grab (sanity check)
|
||||||
NSString* type = [cocoaPasteboard
|
NSString* type = [cocoaPasteboard
|
||||||
availableTypeFromArray:
|
availableTypeFromArray:
|
||||||
[NSArray arrayWithObjects:[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL],
|
[NSArray
|
||||||
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
arrayWithObjects:
|
||||||
[UTIHelper stringFromPboardType:NSPasteboardTypePNG], nil]];
|
[UTIHelper
|
||||||
|
stringFromPboardType:(NSString*)kUTTypeFileURL],
|
||||||
|
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
||||||
|
[UTIHelper stringFromPboardType:NSPasteboardTypePNG],
|
||||||
|
nil]];
|
||||||
if (!type) continue;
|
if (!type) continue;
|
||||||
|
|
||||||
// Read data off the clipboard
|
// Read data off the clipboard
|
||||||
|
|
@ -263,7 +297,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||||
|
|
||||||
// Figure out what type we're converting to
|
// Figure out what type we're converting to
|
||||||
CFStringRef outputType = NULL;
|
CFStringRef outputType = NULL;
|
||||||
if (flavorStr.EqualsLiteral(kJPEGImageMime) || flavorStr.EqualsLiteral(kJPGImageMime))
|
if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||||
|
flavorStr.EqualsLiteral(kJPGImageMime))
|
||||||
outputType = CFSTR("public.jpeg");
|
outputType = CFSTR("public.jpeg");
|
||||||
else if (flavorStr.EqualsLiteral(kPNGImageMime))
|
else if (flavorStr.EqualsLiteral(kPNGImageMime))
|
||||||
outputType = CFSTR("public.png");
|
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
|
// Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
|
||||||
// and safely in most cases (like ObjC). A notable exception is CFRelease.
|
// and safely in most cases (like ObjC). A notable exception is CFRelease.
|
||||||
NSDictionary* options = [NSDictionary
|
NSDictionary* options = [NSDictionary
|
||||||
dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue, kCGImageSourceShouldAllowFloat,
|
dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue,
|
||||||
type, kCGImageSourceTypeIdentifierHint, nil];
|
kCGImageSourceShouldAllowFloat, type,
|
||||||
|
kCGImageSourceTypeIdentifierHint, nil];
|
||||||
CGImageSourceRef source = nullptr;
|
CGImageSourceRef source = nullptr;
|
||||||
if (type == [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]) {
|
if (type == [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]) {
|
||||||
NSString* urlStr = [cocoaPasteboard stringForType:type];
|
NSString* urlStr = [cocoaPasteboard stringForType:type];
|
||||||
NSURL* url = [NSURL URLWithString:urlStr];
|
NSURL* url = [NSURL URLWithString:urlStr];
|
||||||
source = CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options);
|
source =
|
||||||
|
CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options);
|
||||||
} else {
|
} else {
|
||||||
source = CGImageSourceCreateWithData((CFDataRef)pasteboardData, (CFDictionaryRef)options);
|
source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
|
||||||
|
(CFDictionaryRef)options);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableData* encodedData = [NSMutableData data];
|
NSMutableData* encodedData = [NSMutableData data];
|
||||||
CGImageDestinationRef dest =
|
CGImageDestinationRef dest = CGImageDestinationCreateWithData(
|
||||||
CGImageDestinationCreateWithData((CFMutableDataRef)encodedData, outputType, 1, NULL);
|
(CFMutableDataRef)encodedData, outputType, 1, NULL);
|
||||||
CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
|
CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
|
||||||
bool successfullyConverted = CGImageDestinationFinalize(dest);
|
bool successfullyConverted = CGImageDestinationFinalize(dest);
|
||||||
|
|
||||||
|
|
@ -297,7 +335,8 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||||
// Put the converted data in a form Gecko can understand
|
// Put the converted data in a form Gecko can understand
|
||||||
nsCOMPtr<nsIInputStream> byteStream;
|
nsCOMPtr<nsIInputStream> byteStream;
|
||||||
NS_NewByteInputStream(getter_AddRefs(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);
|
NS_ASSIGNMENT_COPY);
|
||||||
|
|
||||||
aTransferable->SetTransferData(flavorStr.get(), byteStream);
|
aTransferable->SetTransferData(flavorStr.get(), byteStream);
|
||||||
|
|
@ -321,19 +360,21 @@ nsresult nsClipboard::TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) {
|
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
|
||||||
|
int32_t aWhichClipboard) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
|
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||||
|
|
||||||
if (kSelectionCache == aWhichClipboard) {
|
if (kSelectionCache == aWhichClipboard) {
|
||||||
if (!sSelectionCache) {
|
if (!sSelectionCache) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get flavor list that includes all acceptable flavors (including ones obtained through
|
// get flavor list that includes all acceptable flavors (including ones
|
||||||
// conversion)
|
// obtained through conversion)
|
||||||
nsTArray<nsCString> flavors;
|
nsTArray<nsCString> flavors;
|
||||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
@ -342,7 +383,8 @@ nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhi
|
||||||
|
|
||||||
for (const auto& flavor : flavors) {
|
for (const auto& flavor : flavors) {
|
||||||
nsCOMPtr<nsISupports> dataSupports;
|
nsCOMPtr<nsISupports> dataSupports;
|
||||||
rv = sSelectionCache->GetTransferData(flavor.get(), getter_AddRefs(dataSupports));
|
rv = sSelectionCache->GetTransferData(flavor.get(),
|
||||||
|
getter_AddRefs(dataSupports));
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
CLIPBOARD_LOG("%s: getting %s from cache.", __FUNCTION__, flavor.get());
|
CLIPBOARD_LOG("%s: getting %s from cache.", __FUNCTION__, flavor.get());
|
||||||
aTransferable->SetTransferData(flavor.get(), dataSupports);
|
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
|
// 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) {
|
const nsTArray<nsCString>& aFlavorList, int32_t aWhichClipboard) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
|
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||||
|
|
||||||
if (kSelectionCache == aWhichClipboard) {
|
if (kSelectionCache == aWhichClipboard) {
|
||||||
nsTArray<nsCString> transferableFlavors;
|
nsTArray<nsCString> transferableFlavors;
|
||||||
if (sSelectionCache &&
|
if (sSelectionCache &&
|
||||||
NS_SUCCEEDED(sSelectionCache->FlavorsTransferableCanImport(transferableFlavors))) {
|
NS_SUCCEEDED(sSelectionCache->FlavorsTransferableCanImport(
|
||||||
|
transferableFlavors))) {
|
||||||
if (CLIPBOARD_LOG_ENABLED()) {
|
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) {
|
for (const auto& transferableFlavor : transferableFlavors) {
|
||||||
CLIPBOARD_LOG(" MIME %s", transferableFlavor.get());
|
CLIPBOARD_LOG(" MIME %s", transferableFlavor.get());
|
||||||
}
|
}
|
||||||
|
|
@ -417,8 +463,8 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
|
||||||
for (auto& mimeType : aFlavorList) {
|
for (auto& mimeType : aFlavorList) {
|
||||||
NSString* pboardType = nil;
|
NSString* pboardType = nil;
|
||||||
if (nsClipboard::IsStringType(mimeType, &pboardType)) {
|
if (nsClipboard::IsStringType(mimeType, &pboardType)) {
|
||||||
NSString* availableType =
|
NSString* availableType = [cocoaPasteboard
|
||||||
[cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
|
availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
|
||||||
if (availableType && [availableType isEqualToString:pboardType]) {
|
if (availableType && [availableType isEqualToString:pboardType]) {
|
||||||
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -426,17 +472,24 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
|
||||||
} else if (mimeType.EqualsLiteral(kCustomTypesMime)) {
|
} else if (mimeType.EqualsLiteral(kCustomTypesMime)) {
|
||||||
NSString* availableType = [cocoaPasteboard
|
NSString* availableType = [cocoaPasteboard
|
||||||
availableTypeFromArray:
|
availableTypeFromArray:
|
||||||
[NSArray arrayWithObject:[UTIHelper stringFromPboardType:kMozCustomTypesPboardType]]];
|
[NSArray
|
||||||
|
arrayWithObject:[UTIHelper stringFromPboardType:
|
||||||
|
kMozCustomTypesPboardType]]];
|
||||||
if (availableType) {
|
if (availableType) {
|
||||||
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (mimeType.EqualsLiteral(kJPEGImageMime) || mimeType.EqualsLiteral(kJPGImageMime) ||
|
} else if (mimeType.EqualsLiteral(kJPEGImageMime) ||
|
||||||
mimeType.EqualsLiteral(kPNGImageMime) || mimeType.EqualsLiteral(kGIFImageMime)) {
|
mimeType.EqualsLiteral(kJPGImageMime) ||
|
||||||
|
mimeType.EqualsLiteral(kPNGImageMime) ||
|
||||||
|
mimeType.EqualsLiteral(kGIFImageMime)) {
|
||||||
NSString* availableType = [cocoaPasteboard
|
NSString* availableType = [cocoaPasteboard
|
||||||
availableTypeFromArray:
|
availableTypeFromArray:
|
||||||
[NSArray arrayWithObjects:[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
[NSArray
|
||||||
[UTIHelper stringFromPboardType:NSPasteboardTypePNG], nil]];
|
arrayWithObjects:
|
||||||
|
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
||||||
|
[UTIHelper stringFromPboardType:NSPasteboardTypePNG],
|
||||||
|
nil]];
|
||||||
if (availableType) {
|
if (availableType) {
|
||||||
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -449,9 +502,11 @@ mozilla::Result<bool, nsresult> nsClipboard::HasNativeClipboardDataMatchingFlavo
|
||||||
if (NSPasteboardItem* item = [items objectAtIndex:0]) {
|
if (NSPasteboardItem* item = [items objectAtIndex:0]) {
|
||||||
if (NSString *availableType = [item
|
if (NSString *availableType = [item
|
||||||
availableTypeFromArray:
|
availableTypeFromArray:
|
||||||
[NSArray arrayWithObjects:[UTIHelper
|
[NSArray
|
||||||
stringFromPboardType:(NSString*)kUTTypeFileURL],
|
arrayWithObjects:[UTIHelper
|
||||||
nil]]) {
|
stringFromPboardType:
|
||||||
|
(NSString*)kUTTypeFileURL],
|
||||||
|
nil]]) {
|
||||||
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
CLIPBOARD_LOG(" has %s\n", mimeType.get());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -481,10 +536,10 @@ mozilla::Maybe<uint32_t> nsClipboard::FindIndexOfImageFlavor(
|
||||||
return mozilla::Nothing();
|
return mozilla::Nothing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function converts anything that other applications might understand into the system format
|
// This function converts anything that other applications might understand into
|
||||||
// and puts it into a dictionary which it returns.
|
// the system format and puts it into a dictionary which it returns. static
|
||||||
// static
|
NSDictionary* nsClipboard::PasteboardDictFromTransferable(
|
||||||
NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable) {
|
nsITransferable* aTransferable) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
if (!aTransferable) {
|
if (!aTransferable) {
|
||||||
|
|
@ -499,29 +554,33 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mozilla::Maybe<uint32_t> imageFlavorIndex = nsClipboard::FindIndexOfImageFlavor(flavors);
|
const mozilla::Maybe<uint32_t> imageFlavorIndex =
|
||||||
|
nsClipboard::FindIndexOfImageFlavor(flavors);
|
||||||
|
|
||||||
if (imageFlavorIndex) {
|
if (imageFlavorIndex) {
|
||||||
// When right-clicking and "Copy Image" is clicked on macOS, some apps expect the
|
// When right-clicking and "Copy Image" is clicked on macOS, some apps
|
||||||
// first flavor to be the image flavor. See bug 1689992. For other apps, the
|
// expect the first flavor to be the image flavor. See bug 1689992. For
|
||||||
// order shouldn't matter.
|
// other apps, the order shouldn't matter.
|
||||||
std::swap(*flavors.begin(), flavors[*imageFlavorIndex]);
|
std::swap(*flavors.begin(), flavors[*imageFlavorIndex]);
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||||
nsCString& flavorStr = flavors[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;
|
NSString* pboardType = nil;
|
||||||
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
||||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericDataWrapper));
|
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||||
|
getter_AddRefs(genericDataWrapper));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoString data;
|
nsAutoString data;
|
||||||
if (nsCOMPtr<nsISupportsString> text = do_QueryInterface(genericDataWrapper)) {
|
if (nsCOMPtr<nsISupportsString> text =
|
||||||
|
do_QueryInterface(genericDataWrapper)) {
|
||||||
text->GetData(data);
|
text->GetData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -540,26 +599,32 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aTransferable->GetIsPrivateData()) {
|
if (aTransferable->GetIsPrivateData()) {
|
||||||
// In the case of password strings, we want to include the key for concealed type.
|
// In the case of password strings, we want to include the key for
|
||||||
// These will be flagged as private data.
|
// concealed type. These will be flagged as private data.
|
||||||
[pasteboardOutputDict setObject:nativeString
|
[pasteboardOutputDict
|
||||||
forKey:[UTIHelper stringFromPboardType:kPasteboardConcealedType]];
|
setObject:nativeString
|
||||||
|
forKey:[UTIHelper
|
||||||
|
stringFromPboardType:kPasteboardConcealedType]];
|
||||||
}
|
}
|
||||||
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericDataWrapper));
|
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||||
|
getter_AddRefs(genericDataWrapper));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoCString data;
|
nsAutoCString data;
|
||||||
if (nsCOMPtr<nsISupportsCString> text = do_QueryInterface(genericDataWrapper)) {
|
if (nsCOMPtr<nsISupportsCString> text =
|
||||||
|
do_QueryInterface(genericDataWrapper)) {
|
||||||
text->GetData(data);
|
text->GetData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.IsEmpty()) {
|
if (!data.IsEmpty()) {
|
||||||
NSData* nativeData = [NSData dataWithBytes:data.get() length:data.Length()];
|
NSData* nativeData = [NSData dataWithBytes:data.get()
|
||||||
NSString* customType = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
|
length:data.Length()];
|
||||||
|
NSString* customType =
|
||||||
|
[UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
|
||||||
if (!nativeData) {
|
if (!nativeData) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -567,7 +632,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
}
|
}
|
||||||
} else if (nsClipboard::IsImageType(flavorStr)) {
|
} else if (nsClipboard::IsImageType(flavorStr)) {
|
||||||
nsCOMPtr<nsISupports> transferSupports;
|
nsCOMPtr<nsISupports> transferSupports;
|
||||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(transferSupports));
|
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||||
|
getter_AddRefs(transferSupports));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -578,9 +644,9 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<SourceSurface> surface =
|
RefPtr<SourceSurface> surface = image->GetFrame(
|
||||||
image->GetFrame(imgIContainer::FRAME_CURRENT,
|
imgIContainer::FRAME_CURRENT,
|
||||||
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
|
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -592,8 +658,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
|
|
||||||
// Convert the CGImageRef to TIFF data.
|
// Convert the CGImageRef to TIFF data.
|
||||||
CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||||
CGImageDestinationRef destRef =
|
CGImageDestinationRef destRef = CGImageDestinationCreateWithData(
|
||||||
CGImageDestinationCreateWithData(tiffData, CFSTR("public.tiff"), 1, NULL);
|
tiffData, CFSTR("public.tiff"), 1, NULL);
|
||||||
CGImageDestinationAddImage(destRef, imageRef, NULL);
|
CGImageDestinationAddImage(destRef, imageRef, NULL);
|
||||||
bool successfullyConverted = CGImageDestinationFinalize(destRef);
|
bool successfullyConverted = CGImageDestinationFinalize(destRef);
|
||||||
|
|
||||||
|
|
@ -609,12 +675,14 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* tiffType = [UTIHelper stringFromPboardType:NSPasteboardTypeTIFF];
|
NSString* tiffType =
|
||||||
|
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF];
|
||||||
[pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:tiffType];
|
[pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:tiffType];
|
||||||
CFRelease(tiffData);
|
CFRelease(tiffData);
|
||||||
} else if (flavorStr.EqualsLiteral(kFileMime)) {
|
} else if (flavorStr.EqualsLiteral(kFileMime)) {
|
||||||
nsCOMPtr<nsISupports> genericFile;
|
nsCOMPtr<nsISupports> genericFile;
|
||||||
rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(genericFile));
|
rv = aTransferable->GetTransferData(flavorStr.get(),
|
||||||
|
getter_AddRefs(genericFile));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -635,18 +703,22 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
if (!url || ![url absoluteString]) {
|
if (!url || ![url absoluteString]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NSString* fileUTType = [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL];
|
NSString* fileUTType =
|
||||||
|
[UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL];
|
||||||
[pasteboardOutputDict setObject:[url absoluteString] forKey:fileUTType];
|
[pasteboardOutputDict setObject:[url absoluteString] forKey:fileUTType];
|
||||||
} else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
|
} else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
|
||||||
NSString* urlPromise =
|
NSString* urlPromise = [UTIHelper
|
||||||
[UTIHelper stringFromPboardType:(NSString*)kPasteboardTypeFileURLPromise];
|
stringFromPboardType:(NSString*)kPasteboardTypeFileURLPromise];
|
||||||
NSString* urlPromiseContent =
|
NSString* urlPromiseContent = [UTIHelper
|
||||||
[UTIHelper stringFromPboardType:(NSString*)kPasteboardTypeFilePromiseContent];
|
stringFromPboardType:(NSString*)kPasteboardTypeFilePromiseContent];
|
||||||
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:urlPromise];
|
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""]
|
||||||
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:urlPromiseContent];
|
forKey:urlPromise];
|
||||||
|
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""]
|
||||||
|
forKey:urlPromiseContent];
|
||||||
} else if (flavorStr.EqualsLiteral(kURLMime)) {
|
} else if (flavorStr.EqualsLiteral(kURLMime)) {
|
||||||
nsCOMPtr<nsISupports> genericURL;
|
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));
|
nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL));
|
||||||
|
|
||||||
nsAutoString url;
|
nsAutoString url;
|
||||||
|
|
@ -662,10 +734,12 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
|
|
||||||
nsAutoString urlTitle;
|
nsAutoString urlTitle;
|
||||||
urlObject->GetData(urlTitle);
|
urlObject->GetData(urlTitle);
|
||||||
urlTitle.Mid(urlTitle, newlinePos + 1, urlTitle.Length() - (newlinePos + 1));
|
urlTitle.Mid(urlTitle, newlinePos + 1,
|
||||||
|
urlTitle.Length() - (newlinePos + 1));
|
||||||
|
|
||||||
nativeTitle =
|
nativeTitle =
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(urlTitle.get())
|
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
urlTitle.get())
|
||||||
length:urlTitle.Length()];
|
length:urlTitle.Length()];
|
||||||
}
|
}
|
||||||
// The Finder doesn't like getting random binary data aka
|
// The Finder doesn't like getting random binary data aka
|
||||||
|
|
@ -673,24 +747,29 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
// ASCII.
|
// ASCII.
|
||||||
nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length());
|
nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length());
|
||||||
nsAutoCString escData;
|
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* nativeURL = [NSString stringWithUTF8String:escData.get()];
|
||||||
NSString* publicUrl = [UTIHelper stringFromPboardType:kPublicUrlPboardType];
|
NSString* publicUrl =
|
||||||
|
[UTIHelper stringFromPboardType:kPublicUrlPboardType];
|
||||||
if (!nativeURL) {
|
if (!nativeURL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
[pasteboardOutputDict setObject:nativeURL forKey:publicUrl];
|
[pasteboardOutputDict setObject:nativeURL forKey:publicUrl];
|
||||||
if (nativeTitle) {
|
if (nativeTitle) {
|
||||||
NSArray* urlsAndTitles = @[ @[ nativeURL ], @[ nativeTitle ] ];
|
NSArray* urlsAndTitles = @[ @[ nativeURL ], @[ nativeTitle ] ];
|
||||||
NSString* urlName = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
|
NSString* urlName =
|
||||||
NSString* urlsWithTitles = [UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType];
|
[UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
|
||||||
|
NSString* urlsWithTitles =
|
||||||
|
[UTIHelper stringFromPboardType:kUrlsWithTitlesPboardType];
|
||||||
[pasteboardOutputDict setObject:nativeTitle forKey:urlName];
|
[pasteboardOutputDict setObject:nativeTitle forKey:urlName];
|
||||||
[pasteboardOutputDict setObject:urlsAndTitles forKey:urlsWithTitles];
|
[pasteboardOutputDict setObject:urlsAndTitles forKey:urlsWithTitles];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If it wasn't a type that we recognize as exportable we don't put it on the system
|
// If it wasn't a type that we recognize as exportable we don't put it on
|
||||||
// clipboard. We'll just access it from our cached transferable when we need it.
|
// the system clipboard. We'll just access it from our cached transferable
|
||||||
|
// when we need it.
|
||||||
}
|
}
|
||||||
|
|
||||||
return pasteboardOutputDict;
|
return pasteboardOutputDict;
|
||||||
|
|
@ -698,7 +777,8 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTran
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
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)) {
|
if (aMIMEType.EqualsLiteral(kTextMime)) {
|
||||||
*aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
*aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -715,29 +795,33 @@ bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPboardTyp
|
||||||
|
|
||||||
// static
|
// static
|
||||||
bool nsClipboard::IsImageType(const nsACString& aMIMEType) {
|
bool nsClipboard::IsImageType(const nsACString& aMIMEType) {
|
||||||
return aMIMEType.EqualsLiteral(kPNGImageMime) || aMIMEType.EqualsLiteral(kJPEGImageMime) ||
|
return aMIMEType.EqualsLiteral(kPNGImageMime) ||
|
||||||
aMIMEType.EqualsLiteral(kJPGImageMime) || aMIMEType.EqualsLiteral(kGIFImageMime) ||
|
aMIMEType.EqualsLiteral(kJPEGImageMime) ||
|
||||||
|
aMIMEType.EqualsLiteral(kJPGImageMime) ||
|
||||||
|
aMIMEType.EqualsLiteral(kGIFImageMime) ||
|
||||||
aMIMEType.EqualsLiteral(kNativeImageMime);
|
aMIMEType.EqualsLiteral(kNativeImageMime);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString) {
|
NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString) {
|
||||||
NSString* wrapped = [NSString
|
NSString* wrapped =
|
||||||
stringWithFormat:@"<html>"
|
[NSString stringWithFormat:@"<html>"
|
||||||
"<head>"
|
"<head>"
|
||||||
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">"
|
"<meta http-equiv=\"content-type\" "
|
||||||
"</head>"
|
"content=\"text/html; charset=utf-8\">"
|
||||||
"<body>"
|
"</head>"
|
||||||
"%@"
|
"<body>"
|
||||||
"</body>"
|
"%@"
|
||||||
"</html>",
|
"</body>"
|
||||||
aString];
|
"</html>",
|
||||||
|
aString];
|
||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) {
|
nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
|
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||||
|
|
||||||
if (kSelectionCache == aWhichClipboard) {
|
if (kSelectionCache == aWhichClipboard) {
|
||||||
ClearSelectionCache();
|
ClearSelectionCache();
|
||||||
|
|
@ -753,11 +837,12 @@ nsresult nsClipboard::EmptyNativeClipboardData(int32_t aWhichClipboard) {
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::Result<int32_t, nsresult> nsClipboard::GetNativeClipboardSequenceNumber(
|
mozilla::Result<int32_t, nsresult>
|
||||||
int32_t aWhichClipboard) {
|
nsClipboard::GetNativeClipboardSequenceNumber(int32_t aWhichClipboard) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
MOZ_DIAGNOSTIC_ASSERT(
|
||||||
|
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||||
|
|
||||||
if (kSelectionCache == aWhichClipboard) {
|
if (kSelectionCache == aWhichClipboard) {
|
||||||
return sSelectionCacheChangeCount;
|
return sSelectionCacheChangeCount;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@
|
||||||
/*static*/ int32_t nsCocoaFeatures::mOSVersion = 0;
|
/*static*/ int32_t nsCocoaFeatures::mOSVersion = 0;
|
||||||
|
|
||||||
// This should not be called with unchecked aMajor, which should be >= 10.
|
// 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);
|
MOZ_ASSERT(aMajor >= 10);
|
||||||
return (aMajor << 16) + (aMinor << 8) + aBugFix;
|
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) {
|
void nsCocoaFeatures::GetSystemVersion(int& major, int& minor, int& bugfix) {
|
||||||
major = minor = bugfix = 0;
|
major = minor = bugfix = 0;
|
||||||
|
|
||||||
NSString* versionString = [[NSDictionary
|
NSString* versionString =
|
||||||
dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]
|
[[NSDictionary dictionaryWithContentsOfFile:
|
||||||
objectForKey:@"ProductVersion"];
|
@"/System/Library/CoreServices/SystemVersion.plist"]
|
||||||
|
objectForKey:@"ProductVersion"];
|
||||||
if (!versionString) {
|
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.");
|
"version.");
|
||||||
return;
|
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;
|
int32_t macOSVersion;
|
||||||
if (aMajor < 10) {
|
if (aMajor < 10) {
|
||||||
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() {
|
/* 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 */
|
/* 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);
|
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) {
|
int32_t aBugFix) {
|
||||||
return macOSVersion() >= GetVersion(aMajor, aMinor, aBugFix);
|
return macOSVersion() >= GetVersion(aMajor, aMinor, aBugFix);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -96,25 +96,30 @@ nsColorPicker::~nsColorPicker() {
|
||||||
// TODO(bug 1805397): Implement default colors
|
// TODO(bug 1805397): Implement default colors
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
|
nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
|
||||||
const nsAString& aInitialColor, const nsTArray<nsString>& aDefaultColors) {
|
const nsAString& aInitialColor,
|
||||||
MOZ_ASSERT(NS_IsMainThread(), "Color pickers can only be opened from main thread currently");
|
const nsTArray<nsString>& aDefaultColors) {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread(),
|
||||||
|
"Color pickers can only be opened from main thread currently");
|
||||||
mTitle = aTitle;
|
mTitle = aTitle;
|
||||||
mColor = aInitialColor;
|
mColor = aInitialColor;
|
||||||
mColorPanelWrapper = [[NSColorPanelWrapper alloc] initWithPicker:this];
|
mColorPanelWrapper = [[NSColorPanelWrapper alloc] initWithPicker:this];
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ NSColor* nsColorPicker::GetNSColorFromHexString(const nsAString& aColor) {
|
/* static */ NSColor* nsColorPicker::GetNSColorFromHexString(
|
||||||
|
const nsAString& aColor) {
|
||||||
NSString* str = nsCocoaUtils::ToNSString(aColor);
|
NSString* str = nsCocoaUtils::ToNSString(aColor);
|
||||||
|
|
||||||
double red = HexStrToInt([str substringWithRange:NSMakeRange(1, 2)]) / 255.0;
|
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;
|
double blue = HexStrToInt([str substringWithRange:NSMakeRange(5, 2)]) / 255.0;
|
||||||
|
|
||||||
return [NSColor colorWithDeviceRed:red green:green blue:blue alpha:1.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;
|
CGFloat redFloat, greenFloat, blueFloat;
|
||||||
|
|
||||||
NSColor* color = aColor;
|
NSColor* color = aColor;
|
||||||
|
|
@ -126,7 +131,8 @@ nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCocoaUtils::GetStringForNSString(
|
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)],
|
(int)(blueFloat * 255)],
|
||||||
aResult);
|
aResult);
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +142,8 @@ nsColorPicker::Open(nsIColorPickerShownCallback* aCallback) {
|
||||||
MOZ_ASSERT(aCallback);
|
MOZ_ASSERT(aCallback);
|
||||||
mCallback = aCallback;
|
mCallback = aCallback;
|
||||||
|
|
||||||
[mColorPanelWrapper open:GetNSColorFromHexString(mColor) title:nsCocoaUtils::ToNSString(mTitle)];
|
[mColorPanelWrapper open:GetNSColorFromHexString(mColor)
|
||||||
|
title:nsCocoaUtils::ToNSString(mTitle)];
|
||||||
|
|
||||||
NS_ADDREF_THIS();
|
NS_ADDREF_THIS();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
/*! @method getCursor:
|
/*! @method getCursor:
|
||||||
@abstract Get a reference to the native Mac representation of a cursor.
|
@abstract Get a reference to the native Mac representation of a cursor.
|
||||||
@discussion Gets a reference to the Mac native implementation 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,
|
If the cursor has been requested before, it is retreived from
|
||||||
otherwise it is created and cached.
|
the cursor cache, otherwise it is created and cached.
|
||||||
@param aCursor the cursor to get
|
@param aCursor the cursor to get
|
||||||
@result the Mac native implementation of the cursor
|
@result the Mac native implementation of the cursor
|
||||||
*/
|
*/
|
||||||
|
|
@ -29,8 +29,9 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
|
|
||||||
/*! @method setMacCursor:
|
/*! @method setMacCursor:
|
||||||
@abstract Set the current Mac native cursor
|
@abstract Set the current Mac native cursor
|
||||||
@discussion Sets the current cursor - this routine is what actually causes the cursor to change.
|
@discussion Sets the current cursor - this routine is what actually causes the
|
||||||
The argument is retained and the old cursor is released.
|
cursor to change. The argument is retained and the old cursor is
|
||||||
|
released.
|
||||||
@param aMacCursor the cursor to set
|
@param aMacCursor the cursor to set
|
||||||
@result NS_OK
|
@result NS_OK
|
||||||
*/
|
*/
|
||||||
|
|
@ -38,7 +39,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
|
|
||||||
/*! @method createCursor:
|
/*! @method createCursor:
|
||||||
@abstract Create a Mac native representation of a cursor.
|
@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
|
@param aCursor the cursor to create
|
||||||
@result the Mac native implementation of the cursor
|
@result the Mac native implementation of the cursor
|
||||||
*/
|
*/
|
||||||
|
|
@ -76,92 +78,128 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
|
||||||
case eCursor_wait:
|
case eCursor_wait:
|
||||||
case eCursor_spinning: {
|
case eCursor_spinning: {
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor]
|
||||||
|
type:aCursor];
|
||||||
}
|
}
|
||||||
case eCursor_select:
|
case eCursor_select:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor];
|
||||||
case eCursor_hyperlink:
|
case eCursor_hyperlink:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor]
|
||||||
|
type:aCursor];
|
||||||
case eCursor_crosshair:
|
case eCursor_crosshair:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor]
|
||||||
|
type:aCursor];
|
||||||
case eCursor_move:
|
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:
|
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: {
|
case eCursor_copy: {
|
||||||
SEL cursorSelector = @selector(dragCopyCursor);
|
SEL cursorSelector = @selector(dragCopyCursor);
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
return [nsMacCursor
|
||||||
? [NSCursor performSelector:cursorSelector]
|
cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||||
: [NSCursor arrowCursor]
|
? [NSCursor performSelector:cursorSelector]
|
||||||
type:aCursor];
|
: [NSCursor arrowCursor]
|
||||||
|
type:aCursor];
|
||||||
}
|
}
|
||||||
case eCursor_alias: {
|
case eCursor_alias: {
|
||||||
SEL cursorSelector = @selector(dragLinkCursor);
|
SEL cursorSelector = @selector(dragLinkCursor);
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
return [nsMacCursor
|
||||||
? [NSCursor performSelector:cursorSelector]
|
cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||||
: [NSCursor arrowCursor]
|
? [NSCursor performSelector:cursorSelector]
|
||||||
type:aCursor];
|
: [NSCursor arrowCursor]
|
||||||
|
type:aCursor];
|
||||||
}
|
}
|
||||||
case eCursor_context_menu: {
|
case eCursor_context_menu: {
|
||||||
SEL cursorSelector = @selector(contextualMenuCursor);
|
SEL cursorSelector = @selector(contextualMenuCursor);
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
return [nsMacCursor
|
||||||
? [NSCursor performSelector:cursorSelector]
|
cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||||
: [NSCursor arrowCursor]
|
? [NSCursor performSelector:cursorSelector]
|
||||||
type:aCursor];
|
: [NSCursor arrowCursor]
|
||||||
|
type:aCursor];
|
||||||
}
|
}
|
||||||
case eCursor_cell:
|
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:
|
case eCursor_grab:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor]
|
||||||
|
type:aCursor];
|
||||||
case eCursor_grabbing:
|
case eCursor_grabbing:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor]
|
||||||
|
type:aCursor];
|
||||||
case eCursor_zoom_in:
|
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:
|
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:
|
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:
|
case eCursor_all_scroll:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor]
|
||||||
|
type:aCursor];
|
||||||
case eCursor_not_allowed:
|
case eCursor_not_allowed:
|
||||||
case eCursor_no_drop: {
|
case eCursor_no_drop: {
|
||||||
SEL cursorSelector = @selector(operationNotAllowedCursor);
|
SEL cursorSelector = @selector(operationNotAllowedCursor);
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
return [nsMacCursor
|
||||||
? [NSCursor performSelector:cursorSelector]
|
cursorWithCursor:[NSCursor respondsToSelector:cursorSelector]
|
||||||
: [NSCursor arrowCursor]
|
? [NSCursor performSelector:cursorSelector]
|
||||||
type:aCursor];
|
: [NSCursor arrowCursor]
|
||||||
|
type:aCursor];
|
||||||
}
|
}
|
||||||
// Resize Cursors:
|
// Resize Cursors:
|
||||||
// North
|
// North
|
||||||
case eCursor_n_resize:
|
case eCursor_n_resize:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor]
|
||||||
|
type:aCursor];
|
||||||
// North East
|
// North East
|
||||||
case eCursor_ne_resize:
|
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
|
// East
|
||||||
case eCursor_e_resize:
|
case eCursor_e_resize:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor]
|
||||||
|
type:aCursor];
|
||||||
// South East
|
// South East
|
||||||
case eCursor_se_resize:
|
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
|
// South
|
||||||
case eCursor_s_resize:
|
case eCursor_s_resize:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor]
|
||||||
|
type:aCursor];
|
||||||
// South West
|
// South West
|
||||||
case eCursor_sw_resize:
|
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
|
// West
|
||||||
case eCursor_w_resize:
|
case eCursor_w_resize:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor]
|
||||||
|
type:aCursor];
|
||||||
// North West
|
// North West
|
||||||
case eCursor_nw_resize:
|
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
|
// North & South
|
||||||
case eCursor_ns_resize:
|
case eCursor_ns_resize:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor]
|
||||||
|
type:aCursor];
|
||||||
// East & West
|
// East & West
|
||||||
case eCursor_ew_resize:
|
case eCursor_ew_resize:
|
||||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor] type:aCursor];
|
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor]
|
||||||
|
type:aCursor];
|
||||||
// North East & South West
|
// North East & South West
|
||||||
case eCursor_nesw_resize:
|
case eCursor_nesw_resize:
|
||||||
return [nsMacCursor cursorWithImageNamed:@"sizeNESW"
|
return [nsMacCursor cursorWithImageNamed:@"sizeNESW"
|
||||||
|
|
@ -241,8 +279,10 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
widgetScaleFactor:(CGFloat)scaleFactor {
|
widgetScaleFactor:(CGFloat)scaleFactor {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
// As the user moves the mouse, this gets called repeatedly with the same aCursorImage
|
// As the user moves the mouse, this gets called repeatedly with the same
|
||||||
if (sCurrentCursor == aCursor && sCurrentCursorScaleFactor == scaleFactor && mCurrentMacCursor) {
|
// aCursorImage
|
||||||
|
if (sCurrentCursor == aCursor && sCurrentCursorScaleFactor == scaleFactor &&
|
||||||
|
mCurrentMacCursor) {
|
||||||
// Native dragging can unset our cursor apparently (see bug 1739352).
|
// Native dragging can unset our cursor apparently (see bug 1739352).
|
||||||
if (MOZ_UNLIKELY(![mCurrentMacCursor isSet])) {
|
if (MOZ_UNLIKELY(![mCurrentMacCursor isSet])) {
|
||||||
[mCurrentMacCursor set];
|
[mCurrentMacCursor set];
|
||||||
|
|
@ -265,7 +305,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
|
|
||||||
NSImage* cursorImage;
|
NSImage* cursorImage;
|
||||||
nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(
|
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) {
|
if (NS_FAILED(rv) || !cursorImage) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -277,11 +318,14 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the hotspot is nonsensical, make it 0,0
|
// if the hotspot is nonsensical, make it 0,0
|
||||||
uint32_t hotspotX = aCursor.mHotspotX > (uint32_t(size.width) - 1) ? 0 : aCursor.mHotspotX;
|
uint32_t hotspotX =
|
||||||
uint32_t hotspotY = aCursor.mHotspotY > (uint32_t(size.height) - 1) ? 0 : aCursor.mHotspotY;
|
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);
|
NSPoint hotSpot = ::NSMakePoint(hotspotX, hotspotY);
|
||||||
[self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc] initWithImage:cursorImage
|
[self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc]
|
||||||
hotSpot:hotSpot]
|
initWithImage:cursorImage
|
||||||
|
hotSpot:hotSpot]
|
||||||
type:kCustomCursor]];
|
type:kCustomCursor]];
|
||||||
[cursorImage release];
|
[cursorImage release];
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -292,7 +336,8 @@ static constexpr nsCursor kCustomCursor = eCursorCount;
|
||||||
- (nsMacCursor*)getCursor:(enum nsCursor)aCursor {
|
- (nsMacCursor*)getCursor:(enum nsCursor)aCursor {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsMacCursor* result = [mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
|
nsMacCursor* result =
|
||||||
|
[mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = [nsCursorManager createCursor:aCursor];
|
result = [nsCursorManager createCursor:aCursor];
|
||||||
[mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]];
|
[mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]];
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,8 @@ nsDeviceContextSpecX::~nsDeviceContextSpecX() {
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(nsDeviceContextSpecX, nsIDeviceContextSpec)
|
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;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
RefPtr<nsPrintSettingsX> settings(do_QueryObject(aPS));
|
RefPtr<nsPrintSettingsX> settings(do_QueryObject(aPS));
|
||||||
|
|
@ -81,7 +82,8 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIPrintSettings* aPS, bool aIsPrintPre
|
||||||
if (!printInfo) {
|
if (!printInfo) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
if (aPS->GetOutputDestination() == nsIPrintSettings::kOutputDestinationStream) {
|
if (aPS->GetOutputDestination() ==
|
||||||
|
nsIPrintSettings::kOutputDestinationStream) {
|
||||||
aPS->GetOutputStream(getter_AddRefs(mOutputStream));
|
aPS->GetOutputStream(getter_AddRefs(mOutputStream));
|
||||||
if (!mOutputStream) {
|
if (!mOutputStream) {
|
||||||
return NS_ERROR_FAILURE;
|
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
|
// TODO: Currently we do not support using SkPDF for kPMDestinationFax or
|
||||||
// kPMDestinationProcessPDF ("Add PDF to iBooks, etc.), and we only support
|
// kPMDestinationProcessPDF ("Add PDF to iBooks, etc.), and we only support
|
||||||
// it for kPMDestinationFile if the destination file is a PDF.
|
// it for kPMDestinationFile if the destination file is a PDF.
|
||||||
// XXX Could PMWorkflowSubmitPDFWithSettings/PMPrinterPrintWithProvider help?
|
// XXX Could PMWorkflowSubmitPDFWithSettings/PMPrinterPrintWithProvider
|
||||||
|
// help?
|
||||||
OSStatus status = noErr;
|
OSStatus status = noErr;
|
||||||
PMDestinationType destination;
|
PMDestinationType destination;
|
||||||
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination);
|
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings,
|
||||||
|
&destination);
|
||||||
if (status == noErr) {
|
if (status == noErr) {
|
||||||
if (destination == kPMDestinationPrinter || destination == kPMDestinationPreview) {
|
if (destination == kPMDestinationPrinter ||
|
||||||
|
destination == kPMDestinationPreview) {
|
||||||
mPrintViaSkPDF = true;
|
mPrintViaSkPDF = true;
|
||||||
} else if (destination == kPMDestinationFile) {
|
} else if (destination == kPMDestinationFile) {
|
||||||
AutoCFRelease<CFURLRef> destURL(nullptr);
|
AutoCFRelease<CFURLRef> destURL(nullptr);
|
||||||
status =
|
status = ::PMSessionCopyDestinationLocation(
|
||||||
::PMSessionCopyDestinationLocation(mPrintSession, mPMPrintSettings, destURL.receive());
|
mPrintSession, mPMPrintSettings, destURL.receive());
|
||||||
if (status == noErr) {
|
if (status == noErr) {
|
||||||
AutoCFRelease<CFStringRef> destPathRef =
|
AutoCFRelease<CFStringRef> destPathRef =
|
||||||
CFURLCopyFileSystemPath(destURL, kCFURLPOSIXPathStyle);
|
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
|
// 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
|
// this is for completeness in case we add that (we probably need to in
|
||||||
// order to support adding links into saved PDFs, for example).
|
// 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 {
|
} else {
|
||||||
PMDestinationType destination;
|
PMDestinationType destination;
|
||||||
OSStatus status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination);
|
OSStatus status = ::PMSessionGetDestinationType(
|
||||||
if (status == noErr &&
|
mPrintSession, mPMPrintSettings, &destination);
|
||||||
(destination == kPMDestinationFile || destination == kPMDestinationPreview ||
|
if (status == noErr && (destination == kPMDestinationFile ||
|
||||||
destination == kPMDestinationProcessPDF)) {
|
destination == kPMDestinationPreview ||
|
||||||
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE, u"pdf_file"_ns, 1);
|
destination == kPMDestinationProcessPDF)) {
|
||||||
|
Telemetry::ScalarAdd(Telemetry::ScalarID::PRINTING_TARGET_TYPE,
|
||||||
|
u"pdf_file"_ns, 1);
|
||||||
} else {
|
} 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_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle,
|
NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(
|
||||||
const nsAString& aPrintToFileName,
|
const nsAString& aTitle, const nsAString& aPrintToFileName,
|
||||||
int32_t aStartPage, int32_t aEndPage) {
|
int32_t aStartPage, int32_t aEndPage) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -168,7 +177,8 @@ NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle,
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<PrintEndDocumentPromise> nsDeviceContextSpecX::EndDocument() {
|
RefPtr<PrintEndDocumentPromise> nsDeviceContextSpecX::EndDocument() {
|
||||||
return nsIDeviceContextSpec::EndDocumentPromiseFromResult(DoEndDocument(), __func__);
|
return nsIDeviceContextSpec::EndDocumentPromiseFromResult(DoEndDocument(),
|
||||||
|
__func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsDeviceContextSpecX::DoEndDocument() {
|
nsresult nsDeviceContextSpecX::DoEndDocument() {
|
||||||
|
|
@ -183,14 +193,15 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
AutoCFRelease<CFURLRef> pdfURL(nullptr);
|
AutoCFRelease<CFURLRef> pdfURL(nullptr);
|
||||||
// Note that the caller is responsible to release pdfURL according to nsILocalFileMac.idl,
|
// Note that the caller is responsible to release pdfURL according to
|
||||||
// even though we didn't follow the Core Foundation naming conventions here (the method
|
// nsILocalFileMac.idl, even though we didn't follow the Core Foundation
|
||||||
// should've been called CopyCFURL).
|
// naming conventions here (the method should've been called CopyCFURL).
|
||||||
nsresult rv = tmpPDFFile->GetCFURL(pdfURL.receive());
|
nsresult rv = tmpPDFFile->GetCFURL(pdfURL.receive());
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
PMDestinationType destination;
|
PMDestinationType destination;
|
||||||
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings, &destination);
|
status = ::PMSessionGetDestinationType(mPrintSession, mPMPrintSettings,
|
||||||
|
&destination);
|
||||||
|
|
||||||
switch (destination) {
|
switch (destination) {
|
||||||
case kPMDestinationPrinter: {
|
case kPMDestinationPrinter: {
|
||||||
|
|
@ -200,13 +211,14 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
CFStringRef mimeType = CFSTR("application/pdf");
|
CFStringRef mimeType = CFSTR("application/pdf");
|
||||||
status = ::PMPrinterPrintWithFile(currentPrinter, mPMPrintSettings, mPageFormat, mimeType,
|
status = ::PMPrinterPrintWithFile(currentPrinter, mPMPrintSettings,
|
||||||
pdfURL);
|
mPageFormat, mimeType, pdfURL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kPMDestinationPreview: {
|
case kPMDestinationPreview: {
|
||||||
// XXXjwatt Or should we use CocoaFileUtils::RevealFileInFinder(pdfURL);
|
// 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);
|
NSString* path = (NSString*)CFStringRef(pdfPath);
|
||||||
NSWorkspace* ws = [NSWorkspace sharedWorkspace];
|
NSWorkspace* ws = [NSWorkspace sharedWorkspace];
|
||||||
[ws openFile:path];
|
[ws openFile:path];
|
||||||
|
|
@ -214,8 +226,8 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
||||||
}
|
}
|
||||||
case kPMDestinationFile: {
|
case kPMDestinationFile: {
|
||||||
AutoCFRelease<CFURLRef> destURL(nullptr);
|
AutoCFRelease<CFURLRef> destURL(nullptr);
|
||||||
status =
|
status = ::PMSessionCopyDestinationLocation(
|
||||||
::PMSessionCopyDestinationLocation(mPrintSession, mPMPrintSettings, destURL.receive());
|
mPrintSession, mPMPrintSettings, destURL.receive());
|
||||||
if (status == noErr) {
|
if (status == noErr) {
|
||||||
AutoCFRelease<CFStringRef> sourcePathRef =
|
AutoCFRelease<CFStringRef> sourcePathRef =
|
||||||
CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
|
CFURLCopyFileSystemPath(pdfURL, kCFURLPOSIXPathStyle);
|
||||||
|
|
@ -234,12 +246,14 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
||||||
if ([fileManager fileExistsAtPath:sourcePath]) {
|
if ([fileManager fileExistsAtPath:sourcePath]) {
|
||||||
NSURL* src = static_cast<NSURL*>(CFURLRef(pdfURL));
|
NSURL* src = static_cast<NSURL*>(CFURLRef(pdfURL));
|
||||||
NSURL* dest = static_cast<NSURL*>(CFURLRef(destURL));
|
NSURL* dest = static_cast<NSURL*>(CFURLRef(destURL));
|
||||||
bool ok = [fileManager replaceItemAtURL:dest
|
bool ok = [fileManager
|
||||||
withItemAtURL:src
|
replaceItemAtURL:dest
|
||||||
backupItemName:nil
|
withItemAtURL:src
|
||||||
options:NSFileManagerItemReplacementUsingNewMetadataOnly
|
backupItemName:nil
|
||||||
resultingItemURL:nil
|
options:
|
||||||
error:nil];
|
NSFileManagerItemReplacementUsingNewMetadataOnly
|
||||||
|
resultingItemURL:nil
|
||||||
|
error:nil];
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -261,8 +275,8 @@ nsresult nsDeviceContextSpecX::DoEndDocument() {
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft, double* aBottom,
|
void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft,
|
||||||
double* aRight) {
|
double* aBottom, double* aRight) {
|
||||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
PMRect paperRect;
|
PMRect paperRect;
|
||||||
|
|
@ -286,7 +300,8 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
|
||||||
#ifdef MOZ_ENABLE_SKIA_PDF
|
#ifdef MOZ_ENABLE_SKIA_PDF
|
||||||
if (mPrintViaSkPDF) {
|
if (mPrintViaSkPDF) {
|
||||||
// TODO: Add support for stream printing via SkPDF if we enable that again.
|
// 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);
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
nsAutoCString tempPath("tmp-printing.pdf");
|
nsAutoCString tempPath("tmp-printing.pdf");
|
||||||
mTempFile->AppendNative(tempPath);
|
mTempFile->AppendNative(tempPath);
|
||||||
|
|
@ -298,6 +313,6 @@ already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return PrintTargetCG::CreateOrNull(mOutputStream, mPrintSession, mPageFormat, mPMPrintSettings,
|
return PrintTargetCG::CreateOrNull(mOutputStream, mPrintSession, mPageFormat,
|
||||||
size);
|
mPMPrintSettings, size);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,24 +49,29 @@ nsDragService::nsDragService()
|
||||||
|
|
||||||
nsDragService::~nsDragService() {}
|
nsDragService::~nsDragService() {}
|
||||||
|
|
||||||
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSIntRegion>& aRegion,
|
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode,
|
||||||
|
const Maybe<CSSIntRegion>& aRegion,
|
||||||
NSPoint* aDragPoint) {
|
NSPoint* aDragPoint) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
|
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
|
||||||
|
|
||||||
LayoutDeviceIntRect dragRect(0, 0, 20, 20);
|
LayoutDeviceIntRect dragRect(0, 0, 20, 20);
|
||||||
NSImage* image = ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect);
|
NSImage* image =
|
||||||
|
ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect);
|
||||||
if (!image) {
|
if (!image) {
|
||||||
// if no image was returned, just draw a rectangle
|
// if no image was returned, just draw a rectangle
|
||||||
NSSize size;
|
NSSize size;
|
||||||
size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
|
size.width =
|
||||||
size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
|
nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
|
||||||
|
size.height =
|
||||||
|
nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
|
||||||
image = [NSImage imageWithSize:size
|
image = [NSImage imageWithSize:size
|
||||||
flipped:YES
|
flipped:YES
|
||||||
drawingHandler:^BOOL(NSRect dstRect) {
|
drawingHandler:^BOOL(NSRect dstRect) {
|
||||||
[[NSColor grayColor] set];
|
[[NSColor grayColor] set];
|
||||||
NSBezierPath* path = [NSBezierPath bezierPathWithRect:dstRect];
|
NSBezierPath* path =
|
||||||
|
[NSBezierPath bezierPathWithRect:dstRect];
|
||||||
[path setLineWidth:2.0];
|
[path setLineWidth:2.0];
|
||||||
[path stroke];
|
[path stroke];
|
||||||
return YES;
|
return YES;
|
||||||
|
|
@ -85,8 +90,10 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSIntRegion>& aRegion,
|
NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode,
|
||||||
CSSIntPoint aPoint, LayoutDeviceIntRect* aDragRect) {
|
const Maybe<CSSIntRegion>& aRegion,
|
||||||
|
CSSIntPoint aPoint,
|
||||||
|
LayoutDeviceIntRect* aDragRect) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
|
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
|
||||||
|
|
@ -97,8 +104,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
||||||
if (pc && (!aDragRect->width || !aDragRect->height)) {
|
if (pc && (!aDragRect->width || !aDragRect->height)) {
|
||||||
// just use some suitable defaults
|
// just use some suitable defaults
|
||||||
int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor);
|
int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor);
|
||||||
aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x), pc->CSSPixelsToDevPixels(aPoint.y), size,
|
aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x),
|
||||||
size);
|
pc->CSSPixelsToDevPixels(aPoint.y), size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(rv) || !surface) return nil;
|
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 width = aDragRect->width;
|
||||||
uint32_t height = aDragRect->height;
|
uint32_t height = aDragRect->height;
|
||||||
|
|
||||||
RefPtr<DataSourceSurface> dataSurface =
|
RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(
|
||||||
Factory::CreateDataSourceSurface(IntSize(width, height), SurfaceFormat::B8G8R8A8);
|
IntSize(width, height), SurfaceFormat::B8G8R8A8);
|
||||||
DataSourceSurface::MappedSurface map;
|
DataSourceSurface::MappedSurface map;
|
||||||
if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
|
if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
|
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) {
|
if (!dt) {
|
||||||
dataSurface->Unmap();
|
dataSurface->Unmap();
|
||||||
return nil;
|
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));
|
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
|
||||||
|
|
||||||
NSBitmapImageRep* imageRep =
|
NSBitmapImageRep* imageRep =
|
||||||
|
|
@ -140,7 +149,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
||||||
uint8_t* src = map.mData + i * map.mStride;
|
uint8_t* src = map.mData + i * map.mStride;
|
||||||
for (uint32_t j = 0; j < width; ++j) {
|
for (uint32_t j = 0; j < width; ++j) {
|
||||||
// Reduce transparency overall by multipying by a factor. Remember, Alpha
|
// 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
|
#ifdef IS_BIG_ENDIAN
|
||||||
dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
|
dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
|
||||||
dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
|
dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
|
||||||
|
|
@ -158,8 +168,8 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
||||||
}
|
}
|
||||||
dataSurface->Unmap();
|
dataSurface->Unmap();
|
||||||
|
|
||||||
NSImage* image =
|
NSImage* image = [[NSImage alloc]
|
||||||
[[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor, height / scaleFactor)];
|
initWithSize:NSMakeSize(width / scaleFactor, height / scaleFactor)];
|
||||||
[image addRepresentation:imageRep];
|
[image addRepresentation:imageRep];
|
||||||
[imageRep release];
|
[imageRep release];
|
||||||
|
|
||||||
|
|
@ -168,9 +178,9 @@ NSImage* nsDragService::ConstructDragImage(nsINode* aDOMNode, const Maybe<CSSInt
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
nsresult nsDragService::InvokeDragSessionImpl(
|
||||||
const Maybe<CSSIntRegion>& aRegion,
|
nsIArray* aTransferableArray, const Maybe<CSSIntRegion>& aRegion,
|
||||||
uint32_t aActionType) {
|
uint32_t aActionType) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
#ifdef NIGHTLY_BUILD
|
||||||
|
|
@ -178,10 +188,11 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!gLastDragView) {
|
if (!gLastDragView) {
|
||||||
// gLastDragView is non-null between -[ChildView mouseDown:] and -[ChildView mouseUp:].
|
// gLastDragView is non-null between -[ChildView mouseDown:] and -[ChildView
|
||||||
// If we get here with gLastDragView being null, that means that the mouse button has already
|
// mouseUp:]. If we get here with gLastDragView being null, that means that
|
||||||
// been released. In that case we need to abort the drag because the OS won't know where to drop
|
// the mouse button has already been released. In that case we need to abort
|
||||||
// whatever's being dragged, and we might end up with a stuck drag & drop session.
|
// 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;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,7 +216,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
||||||
gDraggedTransferables->GetLength(&count);
|
gDraggedTransferables->GetLength(&count);
|
||||||
|
|
||||||
for (uint32_t j = 0; j < count; j++) {
|
for (uint32_t j = 0; j < count; j++) {
|
||||||
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(aTransferableArray, j);
|
nsCOMPtr<nsITransferable> currentTransferable =
|
||||||
|
do_QueryElementAt(aTransferableArray, j);
|
||||||
if (!currentTransferable) {
|
if (!currentTransferable) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -234,7 +246,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
||||||
localDragRect.origin.x = draggingPoint.x;
|
localDragRect.origin.x = draggingPoint.x;
|
||||||
localDragRect.origin.y = draggingPoint.y - localDragRect.size.height;
|
localDragRect.origin.y = draggingPoint.y - localDragRect.size.height;
|
||||||
|
|
||||||
NSDraggingItem* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
|
NSDraggingItem* dragItem =
|
||||||
|
[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
|
||||||
[pbItem release];
|
[pbItem release];
|
||||||
[dragItem setDraggingFrame:localDragRect contents:image];
|
[dragItem setDraggingFrame:localDragRect contents:image];
|
||||||
|
|
||||||
|
|
@ -242,7 +255,8 @@ nsresult nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
||||||
nsBaseDragService::OpenDragPopup();
|
nsBaseDragService::OpenDragPopup();
|
||||||
|
|
||||||
NSDraggingSession* draggingSession = [mNativeDragView
|
NSDraggingSession* draggingSession = [mNativeDragView
|
||||||
beginDraggingSessionWithItems:[NSArray arrayWithObject:[dragItem autorelease]]
|
beginDraggingSessionWithItems:[NSArray
|
||||||
|
arrayWithObject:[dragItem autorelease]]
|
||||||
event:mNativeDragEvent
|
event:mNativeDragEvent
|
||||||
source:mNativeDragView];
|
source:mNativeDragView];
|
||||||
draggingSession.animatesToStartingPositionsOnCancelOrFail =
|
draggingSession.animatesToStartingPositionsOnCancelOrFail =
|
||||||
|
|
@ -261,24 +275,26 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get flavor list that includes all acceptable flavors (including ones obtained through
|
// get flavor list that includes all acceptable flavors (including ones
|
||||||
// conversion)
|
// obtained through conversion)
|
||||||
nsTArray<nsCString> flavors;
|
nsTArray<nsCString> flavors;
|
||||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this drag originated within Mozilla we should just use the cached data from
|
// if this drag originated within Mozilla we should just use the cached data
|
||||||
// when the drag started if possible
|
// from when the drag started if possible
|
||||||
if (mDataItems) {
|
if (mDataItems) {
|
||||||
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, aItemIndex);
|
nsCOMPtr<nsITransferable> currentTransferable =
|
||||||
|
do_QueryElementAt(mDataItems, aItemIndex);
|
||||||
if (currentTransferable) {
|
if (currentTransferable) {
|
||||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||||
nsCString& flavorStr = flavors[i];
|
nsCString& flavorStr = flavors[i];
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> dataSupports;
|
nsCOMPtr<nsISupports> dataSupports;
|
||||||
rv = currentTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(dataSupports));
|
rv = currentTransferable->GetTransferData(flavorStr.get(),
|
||||||
|
getter_AddRefs(dataSupports));
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
aTransferable->SetTransferData(flavorStr.get(), dataSupports);
|
aTransferable->SetTransferData(flavorStr.get(), dataSupports);
|
||||||
return NS_OK; // maybe try to fill in more types? Is there a point?
|
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
|
// now check the actual clipboard for data
|
||||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||||
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable, flavors[i], item);
|
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable,
|
||||||
|
flavors[i], item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -327,7 +344,8 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
|
||||||
uint32_t dataItemsCount;
|
uint32_t dataItemsCount;
|
||||||
mDataItems->GetLength(&dataItemsCount);
|
mDataItems->GetLength(&dataItemsCount);
|
||||||
for (unsigned int i = 0; i < dataItemsCount; i++) {
|
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;
|
if (!currentTransferable) continue;
|
||||||
|
|
||||||
nsTArray<nsCString> flavors;
|
nsTArray<nsCString> flavors;
|
||||||
|
|
@ -352,7 +370,8 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
|
||||||
type = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
type = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
||||||
} else if (dataFlavor.EqualsLiteral(kHTMLMime)) {
|
} else if (dataFlavor.EqualsLiteral(kHTMLMime)) {
|
||||||
type = [UTIHelper stringFromPboardType:NSPasteboardTypeHTML];
|
type = [UTIHelper stringFromPboardType:NSPasteboardTypeHTML];
|
||||||
} else if (dataFlavor.EqualsLiteral(kURLMime) || dataFlavor.EqualsLiteral(kURLDataMime)) {
|
} else if (dataFlavor.EqualsLiteral(kURLMime) ||
|
||||||
|
dataFlavor.EqualsLiteral(kURLDataMime)) {
|
||||||
type = [UTIHelper stringFromPboardType:kPublicUrlPboardType];
|
type = [UTIHelper stringFromPboardType:kPublicUrlPboardType];
|
||||||
} else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) {
|
} else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) {
|
||||||
type = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
|
type = [UTIHelper stringFromPboardType:kPublicUrlNamePboardType];
|
||||||
|
|
@ -362,9 +381,10 @@ nsDragService::IsDataFlavorSupported(const char* aDataFlavor, bool* _retval) {
|
||||||
type = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
|
type = [UTIHelper stringFromPboardType:kMozCustomTypesPboardType];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* availableType =
|
NSString* availableType = [globalDragPboard
|
||||||
[globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
|
availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
|
||||||
if (availableType && nsCocoaUtils::IsValidPasteboardType(availableType, allowFileURL)) {
|
if (availableType &&
|
||||||
|
nsCocoaUtils::IsValidPasteboardType(availableType, allowFileURL)) {
|
||||||
*_retval = true;
|
*_retval = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -396,19 +416,22 @@ nsDragService::GetNumDropItems(uint32_t* aNumItems) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
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);
|
nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY);
|
||||||
mDragImageChanged = true;
|
mDragImageChanged = true;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoint) {
|
void nsDragService::DragMovedWithView(NSDraggingSession* aSession,
|
||||||
|
NSPoint aPoint) {
|
||||||
aPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y);
|
aPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y);
|
||||||
|
|
||||||
// XXX It feels like we should be using the backing scale factor at aPoint
|
// 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.
|
// rather than the initial drag view, but I've seen no ill effects of this.
|
||||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
|
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
|
// If the image has changed, call enumerateDraggingItemsWithOptions to get
|
||||||
// the item being dragged and update its image.
|
// the item being dragged and update its image.
|
||||||
|
|
@ -422,32 +445,39 @@ void nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoin
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pc) {
|
if (pc) {
|
||||||
void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) =
|
void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) = ^(
|
||||||
^(NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
|
NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
|
||||||
// We never add more than one item right now, but check just in case.
|
// We never add more than one item right now, but check just in case.
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsPoint pt =
|
nsPoint pt = LayoutDevicePixel::ToAppUnits(
|
||||||
LayoutDevicePixel::ToAppUnits(devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
|
devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
|
||||||
CSSIntPoint screenPoint = CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
|
CSSIntPoint screenPoint =
|
||||||
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
|
CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
|
||||||
|
nsPresContext::AppUnitsToIntCSSPixels(pt.y));
|
||||||
|
|
||||||
// Create a new image; if one isn't returned don't change the current one.
|
// Create a new image; if one isn't returned don't change the current
|
||||||
LayoutDeviceIntRect newRect;
|
// one.
|
||||||
NSImage* image = ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
|
LayoutDeviceIntRect newRect;
|
||||||
if (image) {
|
NSImage* image =
|
||||||
NSRect draggingRect = nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
|
ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
|
||||||
[draggingItem setDraggingFrame:draggingRect contents:image];
|
if (image) {
|
||||||
}
|
NSRect draggingRect =
|
||||||
};
|
nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
|
||||||
|
[draggingItem setDraggingFrame:draggingRect contents:image];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
[aSession enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
|
[aSession
|
||||||
forView:nil
|
enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
|
||||||
classes:[NSArray arrayWithObject:[NSPasteboardItem class]]
|
forView:nil
|
||||||
searchOptions:@{}
|
classes:[NSArray
|
||||||
usingBlock:changeImageBlock];
|
arrayWithObject:
|
||||||
|
[NSPasteboardItem class]]
|
||||||
|
searchOptions:@{}
|
||||||
|
usingBlock:changeImageBlock];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,11 @@ static void SetShowHiddenFileState(NSSavePanel* panel) {
|
||||||
if (gCallSecretHiddenFileAPI) {
|
if (gCallSecretHiddenFileAPI) {
|
||||||
// invoke a method to get a Cocoa-internal nav view
|
// invoke a method to get a Cocoa-internal nav view
|
||||||
SEL navViewSelector = @selector(_navView);
|
SEL navViewSelector = @selector(_navView);
|
||||||
NSMethodSignature* navViewSignature = [panel methodSignatureForSelector:navViewSelector];
|
NSMethodSignature* navViewSignature =
|
||||||
|
[panel methodSignatureForSelector:navViewSelector];
|
||||||
if (!navViewSignature) return;
|
if (!navViewSignature) return;
|
||||||
NSInvocation* navViewInvocation = [NSInvocation invocationWithMethodSignature:navViewSignature];
|
NSInvocation* navViewInvocation =
|
||||||
|
[NSInvocation invocationWithMethodSignature:navViewSignature];
|
||||||
[navViewInvocation setSelector:navViewSelector];
|
[navViewInvocation setSelector:navViewSelector];
|
||||||
[navViewInvocation setTarget:panel];
|
[navViewInvocation setTarget:panel];
|
||||||
[navViewInvocation invoke];
|
[navViewInvocation invoke];
|
||||||
|
|
@ -90,27 +92,32 @@ nsFilePicker::nsFilePicker() : mSelectedTypeIndex(0) {}
|
||||||
|
|
||||||
nsFilePicker::~nsFilePicker() {}
|
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() {
|
NSView* nsFilePicker::GetAccessoryView() {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
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.
|
// Set a label's default value.
|
||||||
NSString* label = @"Format:";
|
NSString* label = @"Format:";
|
||||||
|
|
||||||
// Try to get the localized string.
|
// 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;
|
nsCOMPtr<nsIStringBundle> bundle;
|
||||||
nsresult rv =
|
nsresult rv = sbs->CreateBundle(
|
||||||
sbs->CreateBundle("chrome://global/locale/filepicker.properties", getter_AddRefs(bundle));
|
"chrome://global/locale/filepicker.properties", getter_AddRefs(bundle));
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
nsAutoString locaLabel;
|
nsAutoString locaLabel;
|
||||||
rv = bundle->GetStringFromName("formatLabel", locaLabel);
|
rv = bundle->GetStringFromName("formatLabel", locaLabel);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
label = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get())
|
label = [NSString
|
||||||
length:locaLabel.Length()];
|
stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get())
|
||||||
|
length:locaLabel.Length()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,8 +134,9 @@ NSView* nsFilePicker::GetAccessoryView() {
|
||||||
[textField sizeToFit];
|
[textField sizeToFit];
|
||||||
|
|
||||||
// set up popup button
|
// set up popup button
|
||||||
NSPopUpButton* popupButton = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)
|
NSPopUpButton* popupButton =
|
||||||
pullsDown:NO] autorelease];
|
[[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)
|
||||||
|
pullsDown:NO] autorelease];
|
||||||
uint32_t numMenuItems = mTitles.Length();
|
uint32_t numMenuItems = mTitles.Length();
|
||||||
for (uint32_t i = 0; i < numMenuItems; i++) {
|
for (uint32_t i = 0; i < numMenuItems; i++) {
|
||||||
const nsString& currentTitle = mTitles[i];
|
const nsString& currentTitle = mTitles[i];
|
||||||
|
|
@ -136,11 +144,13 @@ NSView* nsFilePicker::GetAccessoryView() {
|
||||||
if (currentTitle.IsEmpty()) {
|
if (currentTitle.IsEmpty()) {
|
||||||
const nsString& currentFilter = mFilters[i];
|
const nsString& currentFilter = mFilters[i];
|
||||||
titleString =
|
titleString =
|
||||||
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentFilter.get())
|
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
currentFilter.get())
|
||||||
length:currentFilter.Length()];
|
length:currentFilter.Length()];
|
||||||
} else {
|
} else {
|
||||||
titleString =
|
titleString =
|
||||||
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentTitle.get())
|
[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
currentTitle.get())
|
||||||
length:currentTitle.Length()];
|
length:currentTitle.Length()];
|
||||||
}
|
}
|
||||||
[popupButton addItemWithTitle:titleString];
|
[popupButton addItemWithTitle:titleString];
|
||||||
|
|
@ -149,28 +159,34 @@ NSView* nsFilePicker::GetAccessoryView() {
|
||||||
if (mSelectedTypeIndex >= 0 && (uint32_t)mSelectedTypeIndex < numMenuItems)
|
if (mSelectedTypeIndex >= 0 && (uint32_t)mSelectedTypeIndex < numMenuItems)
|
||||||
[popupButton selectItemAtIndex:mSelectedTypeIndex];
|
[popupButton selectItemAtIndex:mSelectedTypeIndex];
|
||||||
[popupButton setTag:kSaveTypeControlTag];
|
[popupButton setTag:kSaveTypeControlTag];
|
||||||
[popupButton sizeToFit]; // we have to do sizeToFit to get the height calculated for us
|
[popupButton sizeToFit]; // we have to do sizeToFit to get the height
|
||||||
// This is just a default width that works well, doesn't truncate the vast majority of
|
// calculated for us
|
||||||
// things that might end up in the menu.
|
// 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)];
|
[popupButton setFrameSize:NSMakeSize(180, [popupButton frame].size.height)];
|
||||||
|
|
||||||
// position everything based on control sizes with kAccessoryViewPadding pix padding
|
// position everything based on control sizes with kAccessoryViewPadding pix
|
||||||
// on each side kAccessoryViewPadding pix horizontal padding between controls
|
// padding on each side kAccessoryViewPadding pix horizontal padding between
|
||||||
|
// controls
|
||||||
float greatestHeight = [textField frame].size.height;
|
float greatestHeight = [textField frame].size.height;
|
||||||
if ([popupButton frame].size.height > greatestHeight)
|
if ([popupButton frame].size.height > greatestHeight)
|
||||||
greatestHeight = [popupButton frame].size.height;
|
greatestHeight = [popupButton frame].size.height;
|
||||||
float totalViewHeight = greatestHeight + kAccessoryViewPadding * 2;
|
float totalViewHeight = greatestHeight + kAccessoryViewPadding * 2;
|
||||||
float totalViewWidth =
|
float totalViewWidth = [textField frame].size.width +
|
||||||
[textField frame].size.width + [popupButton frame].size.width + kAccessoryViewPadding * 3;
|
[popupButton frame].size.width +
|
||||||
|
kAccessoryViewPadding * 3;
|
||||||
[accessoryView setFrameSize:NSMakeSize(totalViewWidth, totalViewHeight)];
|
[accessoryView setFrameSize:NSMakeSize(totalViewWidth, totalViewHeight)];
|
||||||
|
|
||||||
float textFieldOriginY =
|
float textFieldOriginY =
|
||||||
((greatestHeight - [textField frame].size.height) / 2 + 1) + kAccessoryViewPadding;
|
((greatestHeight - [textField frame].size.height) / 2 + 1) +
|
||||||
[textField setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)];
|
kAccessoryViewPadding;
|
||||||
|
[textField
|
||||||
|
setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)];
|
||||||
|
|
||||||
float popupOriginX = [textField frame].size.width + kAccessoryViewPadding * 2;
|
float popupOriginX = [textField frame].size.width + kAccessoryViewPadding * 2;
|
||||||
float popupOriginY =
|
float popupOriginY =
|
||||||
((greatestHeight - [popupButton frame].size.height) / 2) + kAccessoryViewPadding;
|
((greatestHeight - [popupButton frame].size.height) / 2) +
|
||||||
|
kAccessoryViewPadding;
|
||||||
[popupButton setFrameOrigin:NSMakePoint(popupOriginX, popupOriginY)];
|
[popupButton setFrameOrigin:NSMakePoint(popupOriginX, popupOriginY)];
|
||||||
|
|
||||||
[accessoryView addSubview:textField];
|
[accessoryView addSubview:textField];
|
||||||
|
|
@ -255,9 +271,10 @@ static void UpdatePanelFileTypes(NSOpenPanel* aPanel, NSArray* aFilters) {
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in the dialog.
|
// Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in
|
||||||
nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
|
// the dialog.
|
||||||
nsCOMArray<nsIFile>& outFiles) {
|
nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(
|
||||||
|
bool inAllowMultiple, nsCOMArray<nsIFile>& outFiles) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
ResultCode retVal = nsIFilePicker::returnCancel;
|
ResultCode retVal = nsIFilePicker::returnCancel;
|
||||||
|
|
@ -308,10 +325,11 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
|
||||||
[observer setOpenPanel:thePanel];
|
[observer setOpenPanel:thePanel];
|
||||||
[observer setFilePicker:this];
|
[observer setFilePicker:this];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:observer
|
[[NSNotificationCenter defaultCenter]
|
||||||
selector:@selector(menuChangedItem:)
|
addObserver:observer
|
||||||
name:NSMenuWillSendActionNotification
|
selector:@selector(menuChangedItem:)
|
||||||
object:nil];
|
name:NSMenuWillSendActionNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
UpdatePanelFileTypes(thePanel, filters);
|
UpdatePanelFileTypes(thePanel, filters);
|
||||||
result = [thePanel runModal];
|
result = [thePanel runModal];
|
||||||
|
|
@ -343,7 +361,8 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
|
||||||
nsCOMPtr<nsIFile> localFile;
|
nsCOMPtr<nsIFile> localFile;
|
||||||
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
||||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(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);
|
outFiles.AppendObject(localFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -355,10 +374,13 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFiles(bool inAllowMultiple,
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nsIFilePicker::returnOK);
|
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) {
|
nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
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;
|
ResultCode retVal = nsIFilePicker::returnCancel;
|
||||||
NSOpenPanel* thePanel = [NSOpenPanel openPanel];
|
NSOpenPanel* thePanel = [NSOpenPanel openPanel];
|
||||||
|
|
@ -394,7 +416,8 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
|
||||||
nsCOMPtr<nsIFile> localFile;
|
nsCOMPtr<nsIFile> localFile;
|
||||||
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
||||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(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;
|
*outFile = localFile;
|
||||||
NS_ADDREF(*outFile);
|
NS_ADDREF(*outFile);
|
||||||
retVal = returnOK;
|
retVal = returnOK;
|
||||||
|
|
@ -409,7 +432,9 @@ nsIFilePicker::ResultCode nsFilePicker::GetLocalFolder(nsIFile** outFile) {
|
||||||
// Returns |returnOK| if the user presses OK in the dialog.
|
// Returns |returnOK| if the user presses OK in the dialog.
|
||||||
nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
|
nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
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;
|
ResultCode retVal = nsIFilePicker::returnCancel;
|
||||||
NSSavePanel* thePanel = [NSSavePanel savePanel];
|
NSSavePanel* thePanel = [NSSavePanel savePanel];
|
||||||
|
|
@ -423,8 +448,9 @@ nsIFilePicker::ResultCode nsFilePicker::PutLocalFile(nsIFile** outFile) {
|
||||||
[thePanel setAccessoryView:accessoryView];
|
[thePanel setAccessoryView:accessoryView];
|
||||||
|
|
||||||
// set up default file name
|
// set up default file name
|
||||||
NSString* defaultFilename = [NSString stringWithCharacters:(const unichar*)mDefaultFilename.get()
|
NSString* defaultFilename =
|
||||||
length:mDefaultFilename.Length()];
|
[NSString stringWithCharacters:(const unichar*)mDefaultFilename.get()
|
||||||
|
length:mDefaultFilename.Length()];
|
||||||
|
|
||||||
// Set up the allowed type. This prevents the extension from being selected.
|
// Set up the allowed type. This prevents the extension from being selected.
|
||||||
NSString* extension = defaultFilename.pathExtension;
|
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
|
// 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
|
// that all extensions are shown in the panel if the remaining extension is
|
||||||
// known by the OS.
|
// known by the OS.
|
||||||
NSString* fileName = [[defaultFilename lastPathComponent] stringByDeletingPathExtension];
|
NSString* fileName =
|
||||||
|
[[defaultFilename lastPathComponent] stringByDeletingPathExtension];
|
||||||
NSString* otherExtension = fileName.pathExtension;
|
NSString* otherExtension = fileName.pathExtension;
|
||||||
if (otherExtension.length != 0) {
|
if (otherExtension.length != 0) {
|
||||||
// There's another extension here. Get the UTI.
|
// There's another extension here. Get the UTI.
|
||||||
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
|
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(
|
||||||
(CFStringRef)otherExtension, NULL);
|
kUTTagClassFilenameExtension, (CFStringRef)otherExtension, NULL);
|
||||||
if (type) {
|
if (type) {
|
||||||
if (!CFStringHasPrefix(type, CFSTR("dyn."))) {
|
if (!CFStringHasPrefix(type, CFSTR("dyn."))) {
|
||||||
// We have a UTI, otherwise the type would have a "dyn." prefix. Ensure
|
// 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;
|
nsCOMPtr<nsIFile> localFile;
|
||||||
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
NS_NewLocalFile(u""_ns, true, getter_AddRefs(localFile));
|
||||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(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;
|
*outFile = localFile;
|
||||||
NS_ADDREF(*outFile);
|
NS_ADDREF(*outFile);
|
||||||
// We tell if we are replacing or not by just looking to see if the file exists.
|
// We tell if we are replacing or not by just looking to see if the file
|
||||||
// The user could not have hit OK and not meant to replace the file.
|
// exists. The user could not have hit OK and not meant to replace the
|
||||||
|
// file.
|
||||||
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
|
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
|
||||||
retVal = returnReplace;
|
retVal = returnReplace;
|
||||||
else
|
else
|
||||||
|
|
@ -505,7 +534,8 @@ NSArray* nsFilePicker::GetFilterList() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFilters.Length() <= (uint32_t)mSelectedTypeIndex) {
|
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;
|
mSelectedTypeIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,17 +552,21 @@ NSArray* nsFilePicker::GetFilterList() {
|
||||||
// in the format "ext" by NSOpenPanel. So we need to filter some characters.
|
// in the format "ext" by NSOpenPanel. So we need to filter some characters.
|
||||||
NSMutableString* filterString = [[[NSMutableString alloc]
|
NSMutableString* filterString = [[[NSMutableString alloc]
|
||||||
initWithString:[NSString
|
initWithString:[NSString
|
||||||
stringWithCharacters:reinterpret_cast<const unichar*>(filterWide.get())
|
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
length:filterWide.Length()]] autorelease];
|
filterWide.get())
|
||||||
NSCharacterSet* set = [NSCharacterSet characterSetWithCharactersInString:@". *"];
|
length:filterWide.Length()]]
|
||||||
|
autorelease];
|
||||||
|
NSCharacterSet* set =
|
||||||
|
[NSCharacterSet characterSetWithCharactersInString:@". *"];
|
||||||
NSRange range = [filterString rangeOfCharacterFromSet:set];
|
NSRange range = [filterString rangeOfCharacterFromSet:set];
|
||||||
while (range.length) {
|
while (range.length) {
|
||||||
[filterString replaceCharactersInRange:range withString:@""];
|
[filterString replaceCharactersInRange:range withString:@""];
|
||||||
range = [filterString rangeOfCharacterFromSet:set];
|
range = [filterString rangeOfCharacterFromSet:set];
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return [[[NSArray alloc]
|
||||||
[[[NSArray alloc] initWithArray:[filterString componentsSeparatedByString:@";"]] autorelease];
|
initWithArray:[filterString componentsSeparatedByString:@";"]]
|
||||||
|
autorelease];
|
||||||
|
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||||
}
|
}
|
||||||
|
|
@ -546,8 +580,10 @@ void nsFilePicker::SetDialogTitle(const nsString& inTitle, id aPanel) {
|
||||||
length:inTitle.Length()]];
|
length:inTitle.Length()]];
|
||||||
|
|
||||||
if (!mOkButtonLabel.IsEmpty()) {
|
if (!mOkButtonLabel.IsEmpty()) {
|
||||||
[aPanel setPrompt:[NSString stringWithCharacters:(const unichar*)mOkButtonLabel.get()
|
[aPanel
|
||||||
length:mOkButtonLabel.Length()]];
|
setPrompt:[NSString
|
||||||
|
stringWithCharacters:(const unichar*)mOkButtonLabel.get()
|
||||||
|
length:mOkButtonLabel.Length()]];
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||||
|
|
@ -562,9 +598,9 @@ NSString* nsFilePicker::PanelDefaultDirectory() {
|
||||||
if (mDisplayDirectory) {
|
if (mDisplayDirectory) {
|
||||||
nsAutoString pathStr;
|
nsAutoString pathStr;
|
||||||
mDisplayDirectory->GetPath(pathStr);
|
mDisplayDirectory->GetPath(pathStr);
|
||||||
directory =
|
directory = [[[NSString alloc]
|
||||||
[[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get())
|
initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get())
|
||||||
length:pathStr.Length()] autorelease];
|
length:pathStr.Length()] autorelease];
|
||||||
}
|
}
|
||||||
return directory;
|
return directory;
|
||||||
|
|
||||||
|
|
@ -602,7 +638,9 @@ NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString) {
|
||||||
return NS_OK;
|
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
|
// The default extension to use for files
|
||||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension) {
|
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension) {
|
||||||
|
|
@ -610,7 +648,9 @@ NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension) {
|
||||||
return NS_OK;
|
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
|
// Append an entry to the filters array
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
|
||||||
|
|
@ -47,18 +47,22 @@ void nsLookAndFeel::NativeInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static nscolor GetColorFromNSColor(NSColor* aColor) {
|
static nscolor GetColorFromNSColor(NSColor* aColor) {
|
||||||
NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
NSColor* deviceColor =
|
||||||
|
[aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
||||||
return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0),
|
return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0),
|
||||||
(unsigned int)(deviceColor.greenComponent * 255.0),
|
(unsigned int)(deviceColor.greenComponent * 255.0),
|
||||||
(unsigned int)(deviceColor.blueComponent * 255.0),
|
(unsigned int)(deviceColor.blueComponent * 255.0),
|
||||||
(unsigned int)(deviceColor.alphaComponent * 255.0));
|
(unsigned int)(deviceColor.alphaComponent * 255.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor, float alpha) {
|
static nscolor GetColorFromNSColorWithCustomAlpha(NSColor* aColor,
|
||||||
NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
float alpha) {
|
||||||
|
NSColor* deviceColor =
|
||||||
|
[aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
||||||
return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0),
|
return NS_RGBA((unsigned int)(deviceColor.redComponent * 255.0),
|
||||||
(unsigned int)(deviceColor.greenComponent * 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,
|
// 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
|
// whereas white text on dark blue (which what you get if you mix
|
||||||
// partially-transparent light blue with the black textbox background) has much
|
// partially-transparent light blue with the black textbox background) has much
|
||||||
// better contrast.
|
// better contrast.
|
||||||
nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor, ColorScheme aScheme) {
|
nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor,
|
||||||
|
ColorScheme aScheme) {
|
||||||
if (aScheme == ColorScheme::Dark) {
|
if (aScheme == ColorScheme::Dark) {
|
||||||
// When we use a dark selection color, we do not change alpha because we do
|
// 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
|
// not use dark selection in content. The dark system color is appropriate
|
||||||
// Firefox UI without needing to adjust its alpha.
|
// for Firefox UI without needing to adjust its alpha.
|
||||||
return aColor;
|
return aColor;
|
||||||
}
|
}
|
||||||
uint16_t hue, sat, value;
|
uint16_t hue, sat, value;
|
||||||
|
|
@ -100,7 +105,8 @@ nscolor nsLookAndFeel::ProcessSelectionBackground(nscolor aColor, ColorScheme aS
|
||||||
return resultColor;
|
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
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK
|
||||||
|
|
||||||
NSAppearance.currentAppearance = NSAppearanceForColorScheme(aScheme);
|
NSAppearance.currentAppearance = NSAppearanceForColorScheme(aScheme);
|
||||||
|
|
@ -108,18 +114,19 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
||||||
nscolor color = 0;
|
nscolor color = 0;
|
||||||
switch (aID) {
|
switch (aID) {
|
||||||
case ColorID::Infobackground:
|
case ColorID::Infobackground:
|
||||||
color = aScheme == ColorScheme::Light ? NS_RGB(0xdd, 0xdd, 0xdd)
|
color = aScheme == ColorScheme::Light
|
||||||
: GetColorFromNSColor(NSColor.windowBackgroundColor);
|
? NS_RGB(0xdd, 0xdd, 0xdd)
|
||||||
|
: GetColorFromNSColor(NSColor.windowBackgroundColor);
|
||||||
break;
|
break;
|
||||||
case ColorID::Highlight:
|
case ColorID::Highlight:
|
||||||
color = ProcessSelectionBackground(GetColorFromNSColor(NSColor.selectedTextBackgroundColor),
|
color = ProcessSelectionBackground(
|
||||||
aScheme);
|
GetColorFromNSColor(NSColor.selectedTextBackgroundColor), aScheme);
|
||||||
break;
|
break;
|
||||||
// This is used to gray out the selection when it's not focused. Used with
|
// This is used to gray out the selection when it's not focused. Used with
|
||||||
// nsISelectionController::SELECTION_DISABLED.
|
// nsISelectionController::SELECTION_DISABLED.
|
||||||
case ColorID::TextSelectDisabledBackground:
|
case ColorID::TextSelectDisabledBackground:
|
||||||
color = ProcessSelectionBackground(GetColorFromNSColor(NSColor.secondarySelectedControlColor),
|
color = ProcessSelectionBackground(
|
||||||
aScheme);
|
GetColorFromNSColor(NSColor.secondarySelectedControlColor), aScheme);
|
||||||
break;
|
break;
|
||||||
case ColorID::MozMenuhoverdisabled:
|
case ColorID::MozMenuhoverdisabled:
|
||||||
aColor = NS_TRANSPARENT;
|
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
|
// 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,
|
// It's really hard to effectively map these to the Appearance Manager
|
||||||
// since they are modeled word for word after the win32 system colors and don't have any
|
// properly, since they are modeled word for word after the win32 system
|
||||||
// real counterparts in the Mac world. I'm sure we'll be tweaking these for
|
// colors and don't have any real counterparts in the Mac world. I'm sure
|
||||||
// years to come.
|
// 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 ;)
|
// if querying the Appearance Manager fails ;)
|
||||||
//
|
//
|
||||||
case ColorID::MozMacDefaultbuttontext:
|
case ColorID::MozMacDefaultbuttontext:
|
||||||
color = NS_RGB(0xFF, 0xFF, 0xFF);
|
color = NS_RGB(0xFF, 0xFF, 0xFF);
|
||||||
break;
|
break;
|
||||||
case ColorID::MozButtonactivetext:
|
case ColorID::MozButtonactivetext:
|
||||||
// Pre-macOS 12, pressed buttons were filled with the highlight color and the text was white.
|
// Pre-macOS 12, pressed buttons were filled with the highlight color and
|
||||||
// Starting with macOS 12, pressed (non-default) buttons are filled with medium gray and the
|
// the text was white. Starting with macOS 12, pressed (non-default)
|
||||||
// text color is the same as in the non-pressed state.
|
// buttons are filled with medium gray and the text color is the same as
|
||||||
color = nsCocoaFeatures::OnMontereyOrLater() ? GetColorFromNSColor(NSColor.controlTextColor)
|
// in the non-pressed state.
|
||||||
: NS_RGB(0xFF, 0xFF, 0xFF);
|
color = nsCocoaFeatures::OnMontereyOrLater()
|
||||||
|
? GetColorFromNSColor(NSColor.controlTextColor)
|
||||||
|
: NS_RGB(0xFF, 0xFF, 0xFF);
|
||||||
break;
|
break;
|
||||||
case ColorID::Menutext:
|
case ColorID::Menutext:
|
||||||
case ColorID::Infotext:
|
case ColorID::Infotext:
|
||||||
|
|
@ -209,18 +219,22 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
||||||
break;
|
break;
|
||||||
case ColorID::Buttonshadow:
|
case ColorID::Buttonshadow:
|
||||||
case ColorID::Threeddarkshadow:
|
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;
|
break;
|
||||||
case ColorID::Threedshadow:
|
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;
|
break;
|
||||||
case ColorID::Threedface:
|
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;
|
break;
|
||||||
case ColorID::Threedlightshadow:
|
case ColorID::Threedlightshadow:
|
||||||
case ColorID::Buttonborder:
|
case ColorID::Buttonborder:
|
||||||
case ColorID::MozDisabledfield:
|
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;
|
break;
|
||||||
case ColorID::Menu:
|
case ColorID::Menu:
|
||||||
color = GetColorFromNSColor(NSColor.textBackgroundColor);
|
color = GetColorFromNSColor(NSColor.textBackgroundColor);
|
||||||
|
|
@ -248,7 +262,8 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
||||||
color = GetColorFromNSColor(NSColor.controlTextColor);
|
color = GetColorFromNSColor(NSColor.controlTextColor);
|
||||||
break;
|
break;
|
||||||
case ColorID::MozMacFocusring:
|
case ColorID::MozMacFocusring:
|
||||||
color = GetColorFromNSColorWithCustomAlpha(NSColor.keyboardFocusIndicatorColor, 0.48);
|
color = GetColorFromNSColorWithCustomAlpha(
|
||||||
|
NSColor.keyboardFocusIndicatorColor, 0.48);
|
||||||
break;
|
break;
|
||||||
case ColorID::MozMacMenutextdisable:
|
case ColorID::MozMacMenutextdisable:
|
||||||
color = NS_RGB(0x98, 0x98, 0x98);
|
color = NS_RGB(0x98, 0x98, 0x98);
|
||||||
|
|
@ -266,11 +281,13 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
||||||
break;
|
break;
|
||||||
case ColorID::MozEventreerow:
|
case ColorID::MozEventreerow:
|
||||||
// Background color of even list rows.
|
// Background color of even list rows.
|
||||||
color = GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[0]);
|
color =
|
||||||
|
GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[0]);
|
||||||
break;
|
break;
|
||||||
case ColorID::MozOddtreerow:
|
case ColorID::MozOddtreerow:
|
||||||
// Background color of odd list rows.
|
// Background color of odd list rows.
|
||||||
color = GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[1]);
|
color =
|
||||||
|
GetColorFromNSColor(NSColor.controlAlternatingRowBackgroundColors[1]);
|
||||||
break;
|
break;
|
||||||
case ColorID::MozNativehyperlinktext:
|
case ColorID::MozNativehyperlinktext:
|
||||||
color = GetColorFromNSColor(NSColor.linkColor);
|
color = GetColorFromNSColor(NSColor.linkColor);
|
||||||
|
|
@ -281,13 +298,16 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
||||||
case ColorID::MozMacTooltip:
|
case ColorID::MozMacTooltip:
|
||||||
case ColorID::MozMacMenupopup:
|
case ColorID::MozMacMenupopup:
|
||||||
case ColorID::MozMacMenuitem:
|
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;
|
break;
|
||||||
case ColorID::MozMacSourceList:
|
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;
|
break;
|
||||||
case ColorID::MozMacSourceListSelection:
|
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;
|
break;
|
||||||
case ColorID::MozMacActiveMenuitem:
|
case ColorID::MozMacActiveMenuitem:
|
||||||
case ColorID::MozMacActiveSourceListSelection:
|
case ColorID::MozMacActiveSourceListSelection:
|
||||||
|
|
@ -298,7 +318,8 @@ nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme aScheme, nscolor
|
||||||
case ColorID::Inactivecaption:
|
case ColorID::Inactivecaption:
|
||||||
case ColorID::Activecaption: {
|
case ColorID::Activecaption: {
|
||||||
if (aScheme == ColorScheme::Light &&
|
if (aScheme == ColorScheme::Light &&
|
||||||
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast) {
|
NSWorkspace.sharedWorkspace
|
||||||
|
.accessibilityDisplayShouldIncreaseContrast) {
|
||||||
// This has better contrast than the stand-in colors.
|
// This has better contrast than the stand-in colors.
|
||||||
aColor = GetColorFromNSColor(NSColor.windowBackgroundColor);
|
aColor = GetColorFromNSColor(NSColor.windowBackgroundColor);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -410,11 +431,13 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
|
||||||
aResult = NS_ALERT_TOP;
|
aResult = NS_ALERT_TOP;
|
||||||
break;
|
break;
|
||||||
case IntID::TabFocusModel:
|
case IntID::TabFocusModel:
|
||||||
aResult = [NSApp isFullKeyboardAccessEnabled] ? nsIContent::eTabFocus_any
|
aResult = [NSApp isFullKeyboardAccessEnabled]
|
||||||
: nsIContent::eTabFocus_textControlsMask;
|
? nsIContent::eTabFocus_any
|
||||||
|
: nsIContent::eTabFocus_textControlsMask;
|
||||||
break;
|
break;
|
||||||
case IntID::ScrollToClick: {
|
case IntID::ScrollToClick: {
|
||||||
aResult = [[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"];
|
aResult = [[NSUserDefaults standardUserDefaults]
|
||||||
|
boolForKey:@"AppleScrollerPagingBehavior"];
|
||||||
} break;
|
} break;
|
||||||
case IntID::ChosenMenuItemsShouldBlink:
|
case IntID::ChosenMenuItemsShouldBlink:
|
||||||
aResult = 1;
|
aResult = 1;
|
||||||
|
|
@ -444,19 +467,24 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
|
||||||
aResult = SystemWantsDarkTheme();
|
aResult = SystemWantsDarkTheme();
|
||||||
break;
|
break;
|
||||||
case IntID::PrefersReducedMotion:
|
case IntID::PrefersReducedMotion:
|
||||||
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion;
|
aResult =
|
||||||
|
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion;
|
||||||
break;
|
break;
|
||||||
case IntID::PrefersReducedTransparency:
|
case IntID::PrefersReducedTransparency:
|
||||||
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceTransparency;
|
aResult = NSWorkspace.sharedWorkspace
|
||||||
|
.accessibilityDisplayShouldReduceTransparency;
|
||||||
break;
|
break;
|
||||||
case IntID::InvertedColors:
|
case IntID::InvertedColors:
|
||||||
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldInvertColors;
|
aResult =
|
||||||
|
NSWorkspace.sharedWorkspace.accessibilityDisplayShouldInvertColors;
|
||||||
break;
|
break;
|
||||||
case IntID::UseAccessibilityTheme:
|
case IntID::UseAccessibilityTheme:
|
||||||
aResult = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast;
|
aResult = NSWorkspace.sharedWorkspace
|
||||||
|
.accessibilityDisplayShouldIncreaseContrast;
|
||||||
break;
|
break;
|
||||||
case IntID::VideoDynamicRange: {
|
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();
|
gfxPlatform* platform = gfxPlatform::GetPlatform();
|
||||||
MOZ_ASSERT(platform);
|
MOZ_ASSERT(platform);
|
||||||
aResult = platform->SupportsHDR();
|
aResult = platform->SupportsHDR();
|
||||||
|
|
@ -487,7 +515,8 @@ nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
|
||||||
aResult = 2.0f;
|
aResult = 2.0f;
|
||||||
break;
|
break;
|
||||||
case FloatID::CursorScale: {
|
case FloatID::CursorScale: {
|
||||||
id uaDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.universalaccess"];
|
id uaDefaults = [[NSUserDefaults alloc]
|
||||||
|
initWithSuiteName:@"com.apple.universalaccess"];
|
||||||
float f = [uaDefaults floatForKey:@"mouseDriverCursorSize"];
|
float f = [uaDefaults floatForKey:@"mouseDriverCursorSize"];
|
||||||
[uaDefaults release];
|
[uaDefaults release];
|
||||||
aResult = f > 0.0 ? f : 1.0; // default to 1.0 if value not available
|
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() {
|
bool nsLookAndFeel::SystemWantsDarkTheme() {
|
||||||
// This returns true if the macOS system appearance is set to dark mode, false otherwise.
|
// This returns true if the macOS system appearance is set to dark mode, false
|
||||||
NSAppearanceName aquaOrDarkAqua = [NSApp.effectiveAppearance
|
// otherwise.
|
||||||
bestMatchFromAppearancesWithNames:@[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
|
NSAppearanceName aquaOrDarkAqua =
|
||||||
|
[NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:@[
|
||||||
|
NSAppearanceNameAqua, NSAppearanceNameDarkAqua
|
||||||
|
]];
|
||||||
return [aquaOrDarkAqua isEqualToString:NSAppearanceNameDarkAqua];
|
return [aquaOrDarkAqua isEqualToString:NSAppearanceNameDarkAqua];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/
|
/*static*/
|
||||||
bool nsLookAndFeel::IsSystemOrientationRTL() {
|
bool nsLookAndFeel::IsSystemOrientationRTL() {
|
||||||
NSWindow* window = [[NSWindow alloc] initWithContentRect:NSZeroRect
|
NSWindow* window =
|
||||||
styleMask:NSWindowStyleMaskBorderless
|
[[NSWindow alloc] initWithContentRect:NSZeroRect
|
||||||
backing:NSBackingStoreBuffered
|
styleMask:NSWindowStyleMaskBorderless
|
||||||
defer:NO];
|
backing:NSBackingStoreBuffered
|
||||||
|
defer:NO];
|
||||||
auto direction = window.windowTitlebarLayoutDirection;
|
auto direction = window.windowTitlebarLayoutDirection;
|
||||||
[window release];
|
[window release];
|
||||||
return direction == NSUserInterfaceLayoutDirectionRightToLeft;
|
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;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsAutoCString name;
|
nsAutoCString name;
|
||||||
|
|
@ -535,8 +569,10 @@ bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName, gfxFontStyle&
|
||||||
|
|
||||||
void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
||||||
if ([[NSWorkspace sharedWorkspace]
|
if ([[NSWorkspace sharedWorkspace]
|
||||||
respondsToSelector:@selector(accessibilityDisplayShouldInvertColors)]) {
|
respondsToSelector:@selector
|
||||||
bool val = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldInvertColors];
|
(accessibilityDisplayShouldInvertColors)]) {
|
||||||
|
bool val =
|
||||||
|
[[NSWorkspace sharedWorkspace] accessibilityDisplayShouldInvertColors];
|
||||||
Telemetry::ScalarSet(Telemetry::ScalarID::A11Y_INVERT_COLORS, val);
|
Telemetry::ScalarSet(Telemetry::ScalarID::A11Y_INVERT_COLORS, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -553,14 +589,16 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
||||||
- (instancetype)init {
|
- (instancetype)init {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
[NSNotificationCenter.defaultCenter addObserver:self
|
[NSNotificationCenter.defaultCenter
|
||||||
selector:@selector(colorsChanged)
|
addObserver:self
|
||||||
name:NSControlTintDidChangeNotification
|
selector:@selector(colorsChanged)
|
||||||
object:nil];
|
name:NSControlTintDidChangeNotification
|
||||||
[NSNotificationCenter.defaultCenter addObserver:self
|
object:nil];
|
||||||
selector:@selector(colorsChanged)
|
[NSNotificationCenter.defaultCenter
|
||||||
name:NSSystemColorsDidChangeNotification
|
addObserver:self
|
||||||
object:nil];
|
selector:@selector(colorsChanged)
|
||||||
|
name:NSSystemColorsDidChangeNotification
|
||||||
|
object:nil];
|
||||||
|
|
||||||
[NSWorkspace.sharedWorkspace.notificationCenter
|
[NSWorkspace.sharedWorkspace.notificationCenter
|
||||||
addObserver:self
|
addObserver:self
|
||||||
|
|
@ -568,10 +606,11 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
||||||
name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
|
name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
[NSNotificationCenter.defaultCenter addObserver:self
|
[NSNotificationCenter.defaultCenter
|
||||||
selector:@selector(scrollbarsChanged)
|
addObserver:self
|
||||||
name:NSPreferredScrollerStyleDidChangeNotification
|
selector:@selector(scrollbarsChanged)
|
||||||
object:nil];
|
name:NSPreferredScrollerStyleDidChangeNotification
|
||||||
|
object:nil];
|
||||||
[NSDistributedNotificationCenter.defaultCenter
|
[NSDistributedNotificationCenter.defaultCenter
|
||||||
addObserver:self
|
addObserver:self
|
||||||
selector:@selector(scrollbarsChanged)
|
selector:@selector(scrollbarsChanged)
|
||||||
|
|
@ -595,7 +634,10 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
||||||
forKeyPath:@"effectiveAppearance"
|
forKeyPath:@"effectiveAppearance"
|
||||||
options:0
|
options:0
|
||||||
context:nil];
|
context:nil];
|
||||||
[NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:0 context:nil];
|
[NSApp addObserver:self
|
||||||
|
forKeyPath:@"effectiveAppearance"
|
||||||
|
options:0
|
||||||
|
context:nil];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
@ -607,7 +649,10 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
||||||
if ([keyPath isEqualToString:@"effectiveAppearance"]) {
|
if ([keyPath isEqualToString:@"effectiveAppearance"]) {
|
||||||
[self entireThemeChanged];
|
[self entireThemeChanged];
|
||||||
} else {
|
} 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 {
|
- (void)mediaQueriesChanged {
|
||||||
// Changing`Invert Colors` sends AccessibilityDisplayOptionsDidChangeNotifications.
|
// Changing`Invert Colors` sends
|
||||||
// We monitor that setting via telemetry, so call into that
|
// AccessibilityDisplayOptionsDidChangeNotifications. We monitor that setting
|
||||||
// recording method here.
|
// via telemetry, so call into that recording method here.
|
||||||
nsLookAndFeel::RecordAccessibilityTelemetry();
|
nsLookAndFeel::RecordAccessibilityTelemetry();
|
||||||
LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::MediaQueriesOnly);
|
LookAndFeel::NotifyChangedAllWindows(
|
||||||
|
widget::ThemeChangeKind::MediaQueriesOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)colorsChanged {
|
- (void)colorsChanged {
|
||||||
|
|
@ -632,9 +678,12 @@ void nsLookAndFeel::RecordAccessibilityTelemetry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cachedValuesChanged {
|
- (void)cachedValuesChanged {
|
||||||
// We only need to re-cache (and broadcast) updated LookAndFeel values, so that they're
|
// We only need to re-cache (and broadcast) updated LookAndFeel values, so
|
||||||
// up-to-date the next time they're queried. No further change handling is needed.
|
// that they're up-to-date the next time they're queried. No further change
|
||||||
// TODO: Add a change hint for this which avoids the unnecessary media query invalidation.
|
// handling is needed.
|
||||||
LookAndFeel::NotifyChangedAllWindows(widget::ThemeChangeKind::MediaQueriesOnly);
|
// TODO: Add a change hint for this which avoids the unnecessary media query
|
||||||
|
// invalidation.
|
||||||
|
LookAndFeel::NotifyChangedAllWindows(
|
||||||
|
widget::ThemeChangeKind::MediaQueriesOnly);
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@
|
||||||
|
|
||||||
/*! @category nsMacCursor (PrivateMethods)
|
/*! @category nsMacCursor (PrivateMethods)
|
||||||
@abstract Private methods internal to the nsMacCursor class.
|
@abstract Private methods internal to the nsMacCursor class.
|
||||||
@discussion <code>nsMacCursor</code> is effectively an abstract class. It does not define
|
@discussion <code>nsMacCursor</code> is effectively an abstract class. It
|
||||||
complete behaviour in and of itself, the subclasses defined in this file provide the useful
|
does not define complete behaviour in and of itself, the subclasses defined
|
||||||
implementations.
|
in this file provide the useful implementations.
|
||||||
*/
|
*/
|
||||||
@interface nsMacCursor (PrivateMethods)
|
@interface nsMacCursor (PrivateMethods)
|
||||||
|
|
||||||
|
|
@ -27,56 +27,62 @@
|
||||||
|
|
||||||
/*! @method numFrames
|
/*! @method numFrames
|
||||||
@abstract Query the number of frames in this cursor's animation.
|
@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;
|
- (int)numFrames;
|
||||||
|
|
||||||
/*! @method createTimer
|
/*! @method createTimer
|
||||||
@abstract Create a Timer to use to animate the cursor.
|
@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
|
@discussion Creates an instance of <code>NSTimer</code> which is used to
|
||||||
animation. This method should only be called for cursors that are animated.
|
drive the cursor animation. This method should only be called for cursors
|
||||||
|
that are animated.
|
||||||
*/
|
*/
|
||||||
- (void)createTimer;
|
- (void)createTimer;
|
||||||
|
|
||||||
/*! @method destroyTimer
|
/*! @method destroyTimer
|
||||||
@abstract Destroy any timer instance associated with this cursor.
|
@abstract Destroy any timer instance associated with this cursor.
|
||||||
@discussion Invalidates and releases any <code>NSTimer</code> instance associated with this
|
@discussion Invalidates and releases any <code>NSTimer</code> instance
|
||||||
cursor.
|
associated with this cursor.
|
||||||
*/
|
*/
|
||||||
- (void)destroyTimer;
|
- (void)destroyTimer;
|
||||||
/*! @method destroyTimer
|
/*! @method destroyTimer
|
||||||
@abstract Destroy any timer instance associated with this cursor.
|
@abstract Destroy any timer instance associated with this cursor.
|
||||||
@discussion Invalidates and releases any <code>NSTimer</code> instance associated with this
|
@discussion Invalidates and releases any <code>NSTimer</code> instance
|
||||||
cursor.
|
associated with this cursor.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! @method advanceAnimatedCursor:
|
/*! @method advanceAnimatedCursor:
|
||||||
@abstract Method called by animation timer to perform animation.
|
@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
|
@discussion Called by an animated cursor's associated timer to advance the
|
||||||
frame. Determines which frame should occur next and sets the cursor to that frame.
|
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
|
@param aTimer the timer causing the animation
|
||||||
*/
|
*/
|
||||||
- (void)advanceAnimatedCursor:(NSTimer*)aTimer;
|
- (void)advanceAnimatedCursor:(NSTimer*)aTimer;
|
||||||
|
|
||||||
/*! @method setFrame:
|
/*! @method setFrame:
|
||||||
@abstract Sets the current cursor, using an index to determine which frame in the animation to
|
@abstract Sets the current cursor, using an index to determine which frame
|
||||||
display.
|
in the animation to display.
|
||||||
@discussion Sets the current cursor. The frame index determines which frame is shown if the
|
@discussion Sets the current cursor. The frame index determines which frame
|
||||||
cursor is animated. Frames and numbered from <code>0</code> to <code>-[nsMacCursor numFrames] -
|
is shown if the cursor is animated. Frames and numbered from <code>0</code>
|
||||||
1</code>. A static cursor has a single frame, numbered 0.
|
to <code>-[nsMacCursor numFrames] - 1</code>. A static cursor has a single
|
||||||
@param aFrameIndex the index indicating which frame from the animation to display
|
frame, numbered 0.
|
||||||
|
@param aFrameIndex the index indicating which frame from the animation
|
||||||
|
to display
|
||||||
*/
|
*/
|
||||||
- (void)setFrame:(int)aFrameIndex;
|
- (void)setFrame:(int)aFrameIndex;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*! @class nsCocoaCursor
|
/*! @class nsCocoaCursor
|
||||||
@abstract Implementation of <code>nsMacCursor</code> that uses Cocoa <code>NSCursor</code>
|
@abstract Implementation of <code>nsMacCursor</code> that uses Cocoa
|
||||||
instances.
|
<code>NSCursor</code> instances.
|
||||||
@discussion Displays a static or animated cursor, using Cocoa <code>NSCursor</code> instances.
|
@discussion Displays a static or animated cursor, using Cocoa
|
||||||
These can be either built-in <code>NSCursor</code> instances, or custom <code>NSCursor</code>s
|
<code>NSCursor</code> instances. These can be either built-in
|
||||||
created from images. When more than one <code>NSCursor</code> is provided, the cursor will use
|
<code>NSCursor</code> instances, or custom <code>NSCursor</code>s created
|
||||||
these as animation frames.
|
from images. When more than one <code>NSCursor</code> is provided, the cursor
|
||||||
|
will use these as animation frames.
|
||||||
*/
|
*/
|
||||||
@interface nsCocoaCursor : nsMacCursor {
|
@interface nsCocoaCursor : nsMacCursor {
|
||||||
@private
|
@private
|
||||||
|
|
@ -85,13 +91,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! @method initWithFrames:
|
/*! @method initWithFrames:
|
||||||
@abstract Create an animated cursor by specifying the frames to use for the animation.
|
@abstract Create an animated cursor by specifying the frames to use for
|
||||||
@discussion Creates a cursor that will animate by cycling through the given frames. Each element
|
the animation.
|
||||||
of the array must be an instance of <code>NSCursor</code>
|
@discussion Creates a cursor that will animate by cycling through the given
|
||||||
@param aCursorFrames an array of <code>NSCursor</code>, representing the frames of an
|
frames. Each element of the array must be an instance of
|
||||||
animated cursor, in the order they should be played.
|
<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
|
@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;
|
- (id)initWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType;
|
||||||
|
|
||||||
|
|
@ -106,18 +115,22 @@
|
||||||
- (id)initWithCursor:(NSCursor*)aCursor type:(nsCursor)aType;
|
- (id)initWithCursor:(NSCursor*)aCursor type:(nsCursor)aType;
|
||||||
|
|
||||||
/*! @method initWithImageNamed:hotSpot:
|
/*! @method initWithImageNamed:hotSpot:
|
||||||
@abstract Create a cursor by specifying the name of an image resource to use for the cursor
|
@abstract Create a cursor by specifying the name of an image resource to
|
||||||
and a hotspot.
|
use for the cursor and a hotspot.
|
||||||
@discussion Creates a cursor by loading the named image using the <code>+[NSImage
|
@discussion Creates a cursor by loading the named image using the
|
||||||
imageNamed:]</code> method. <p>The image must be compatible with any restrictions laid down by
|
<code>+[NSImage imageNamed:]</code> method. <p>The image must be compatible
|
||||||
<code>NSCursor</code>. These vary by operating system version.</p> <p>The hotspot precisely
|
with any restrictions laid down by <code>NSCursor</code>. These vary by
|
||||||
determines the point where the user clicks when using the cursor.</p>
|
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 aCursor the name of the image to use for the cursor
|
||||||
@param aPoint the point within the cursor to use as the hotspot
|
@param aPoint the point within the cursor to use as the hotspot
|
||||||
@param aType the corresponding <code>nsCursor</code> constant
|
@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
|
@end
|
||||||
|
|
||||||
|
|
@ -126,7 +139,8 @@
|
||||||
+ (nsMacCursor*)cursorWithCursor:(NSCursor*)aCursor type:(nsCursor)aType {
|
+ (nsMacCursor*)cursorWithCursor:(NSCursor*)aCursor type:(nsCursor)aType {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
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);
|
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +150,8 @@
|
||||||
type:(nsCursor)aType {
|
type:(nsCursor)aType {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
return [[[nsCocoaCursor alloc] initWithImageNamed:aCursorImage hotSpot:aPoint
|
return [[[nsCocoaCursor alloc] initWithImageNamed:aCursorImage
|
||||||
|
hotSpot:aPoint
|
||||||
type:aType] autorelease];
|
type:aType] autorelease];
|
||||||
|
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||||
|
|
@ -145,12 +160,14 @@
|
||||||
+ (nsMacCursor*)cursorWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType {
|
+ (nsMacCursor*)cursorWithFrames:(NSArray*)aCursorFrames type:(nsCursor)aType {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
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);
|
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;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsCOMPtr<nsIFile> resDir;
|
nsCOMPtr<nsIFile> resDir;
|
||||||
|
|
@ -174,22 +191,26 @@
|
||||||
pathToImage = [pathToImage stringByAppendingPathExtension:@"png"];
|
pathToImage = [pathToImage stringByAppendingPathExtension:@"png"];
|
||||||
pathToHiDpiImage = [pathToHiDpiImage stringByAppendingPathExtension:@"png"];
|
pathToHiDpiImage = [pathToHiDpiImage stringByAppendingPathExtension:@"png"];
|
||||||
|
|
||||||
cursorImage = [[[NSImage alloc] initWithContentsOfFile:pathToImage] autorelease];
|
cursorImage =
|
||||||
|
[[[NSImage alloc] initWithContentsOfFile:pathToImage] autorelease];
|
||||||
if (!cursorImage) goto INIT_FAILURE;
|
if (!cursorImage) goto INIT_FAILURE;
|
||||||
|
|
||||||
// Note 1: There are a few different ways to get a hidpi image via
|
// Note 1: There are a few different ways to get a hidpi image via
|
||||||
// initWithContentsOfFile. We let the OS handle this here: when the
|
// initWithContentsOfFile. We let the OS handle this here: when the
|
||||||
// file basename ends in "@2x", it will be displayed at native resolution
|
// 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
|
// Note 2: The OS is picky, and will ignore the hidpi representation
|
||||||
// unless it is exactly twice the size of the lowdpi image.
|
// 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) {
|
if (hiDpiCursorImage) {
|
||||||
NSImageRep* imageRep = [[hiDpiCursorImage representations] objectAtIndex:0];
|
NSImageRep* imageRep = [[hiDpiCursorImage representations] objectAtIndex:0];
|
||||||
[cursorImage addRepresentation:imageRep];
|
[cursorImage addRepresentation:imageRep];
|
||||||
}
|
}
|
||||||
return [[[NSCursor alloc] initWithImage:cursorImage hotSpot:aPoint] autorelease];
|
return [[[NSCursor alloc] initWithImage:cursorImage
|
||||||
|
hotSpot:aPoint] autorelease];
|
||||||
|
|
||||||
INIT_FAILURE:
|
INIT_FAILURE:
|
||||||
NS_WARNING("Problem getting path to cursor image file!");
|
NS_WARNING("Problem getting path to cursor image file!");
|
||||||
|
|
@ -236,11 +257,12 @@ INIT_FAILURE:
|
||||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
if (!mTimer) {
|
if (!mTimer) {
|
||||||
mTimer = [[NSTimer scheduledTimerWithTimeInterval:0.25
|
mTimer = [[NSTimer
|
||||||
target:self
|
scheduledTimerWithTimeInterval:0.25
|
||||||
selector:@selector(advanceAnimatedCursor:)
|
target:self
|
||||||
userInfo:nil
|
selector:@selector(advanceAnimatedCursor:)
|
||||||
repeats:YES] retain];
|
userInfo:nil
|
||||||
|
repeats:YES] retain];
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||||
|
|
@ -316,11 +338,15 @@ INIT_FAILURE:
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
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;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
return [self initWithCursor:[nsMacCursor cocoaCursorWithImageNamed:aCursorImage hotSpot:aPoint]
|
return
|
||||||
type:aType];
|
[self initWithCursor:[nsMacCursor cocoaCursorWithImageNamed:aCursorImage
|
||||||
|
hotSpot:aPoint]
|
||||||
|
type:aType];
|
||||||
|
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ NS_IMPL_ISUPPORTS(nsMacDockSupport, nsIMacDockSupport, nsITaskbarProgress)
|
||||||
@synthesize fractionValue = mFractionValue;
|
@synthesize fractionValue = mFractionValue;
|
||||||
|
|
||||||
- (void)drawRect:(NSRect)aRect {
|
- (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];
|
[[NSColor clearColor] set];
|
||||||
NSRectFill(self.bounds);
|
NSRectFill(self.bounds);
|
||||||
|
|
||||||
|
|
@ -103,7 +104,8 @@ NS_IMETHODIMP
|
||||||
nsMacDockSupport::ActivateApplication(bool aIgnoreOtherApplications) {
|
nsMacDockSupport::ActivateApplication(bool aIgnoreOtherApplications) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:aIgnoreOtherApplications];
|
[[NSApplication sharedApplication]
|
||||||
|
activateIgnoringOtherApps:aIgnoreOtherApplications];
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
|
|
@ -118,9 +120,11 @@ nsMacDockSupport::SetBadgeText(const nsAString& aBadgeText) {
|
||||||
if (aBadgeText.IsEmpty())
|
if (aBadgeText.IsEmpty())
|
||||||
[tile setBadgeLabel:nil];
|
[tile setBadgeLabel:nil];
|
||||||
else
|
else
|
||||||
[tile setBadgeLabel:[NSString
|
[tile
|
||||||
stringWithCharacters:reinterpret_cast<const unichar*>(mBadgeText.get())
|
setBadgeLabel:[NSString
|
||||||
length:mBadgeText.Length()]];
|
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
mBadgeText.get())
|
||||||
|
length:mBadgeText.Length()]];
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
|
|
@ -133,8 +137,8 @@ nsMacDockSupport::GetBadgeText(nsAString& aBadgeText) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState, uint64_t aCurrentValue,
|
nsMacDockSupport::SetProgressState(nsTaskbarProgressState aState,
|
||||||
uint64_t aMaxValue) {
|
uint64_t aCurrentValue, uint64_t aMaxValue) {
|
||||||
NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED);
|
NS_ENSURE_ARG_RANGE(aState, 0, STATE_PAUSED);
|
||||||
if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) {
|
if (aState == STATE_NO_PROGRESS || aState == STATE_INDETERMINATE) {
|
||||||
NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
|
NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
|
||||||
|
|
@ -162,22 +166,26 @@ nsresult nsMacDockSupport::UpdateDockTile() {
|
||||||
// Create the following NSView hierarchy:
|
// Create the following NSView hierarchy:
|
||||||
// * mDockTileWrapperView (NSView)
|
// * mDockTileWrapperView (NSView)
|
||||||
// * imageView (NSImageView) <- has the application icon
|
// * 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 =
|
||||||
mDockTileWrapperView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
[[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.image = [NSImage imageNamed:@"NSApplicationIcon"];
|
||||||
imageView.imageScaling = NSImageScaleAxesIndependently;
|
imageView.imageScaling = NSImageScaleAxesIndependently;
|
||||||
imageView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
imageView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||||
[mDockTileWrapperView addSubview:imageView];
|
[mDockTileWrapperView addSubview:imageView];
|
||||||
|
|
||||||
mProgressDockOverlayView =
|
mProgressDockOverlayView = [[MOZProgressDockOverlayView alloc]
|
||||||
[[MOZProgressDockOverlayView alloc] initWithFrame:NSMakeRect(1, 3, 30, 4)];
|
initWithFrame:NSMakeRect(1, 3, 30, 4)];
|
||||||
mProgressDockOverlayView.autoresizingMask = NSViewMinXMargin | NSViewWidthSizable |
|
mProgressDockOverlayView.autoresizingMask =
|
||||||
NSViewMaxXMargin | NSViewMinYMargin |
|
NSViewMinXMargin | NSViewWidthSizable | NSViewMaxXMargin |
|
||||||
NSViewHeightSizable | NSViewMaxYMargin;
|
NSViewMinYMargin | NSViewHeightSizable | NSViewMaxYMargin;
|
||||||
[mDockTileWrapperView addSubview:mProgressDockOverlayView];
|
[mDockTileWrapperView addSubview:mProgressDockOverlayView];
|
||||||
}
|
}
|
||||||
if (NSApp.dockTile.contentView != mDockTileWrapperView) {
|
if (NSApp.dockTile.contentView != mDockTileWrapperView) {
|
||||||
|
|
@ -205,21 +213,23 @@ nsresult nsMacDockSupport::UpdateDockTile() {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// Private CFURL API used by the Dock.
|
// Private CFURL API used by the Dock.
|
||||||
CFPropertyListRef _CFURLCopyPropertyListRepresentation(CFURLRef url);
|
CFPropertyListRef _CFURLCopyPropertyListRepresentation(CFURLRef url);
|
||||||
CFURLRef _CFURLCreateFromPropertyListRepresentation(CFAllocatorRef alloc,
|
CFURLRef _CFURLCreateFromPropertyListRepresentation(
|
||||||
CFPropertyListRef pListRepresentation);
|
CFAllocatorRef alloc, CFPropertyListRef pListRepresentation);
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const NSArray* const browserAppNames =
|
const NSArray* const browserAppNames = [NSArray
|
||||||
[NSArray arrayWithObjects:@"Firefox.app", @"Firefox Beta.app", @"Firefox Nightly.app",
|
arrayWithObjects:@"Firefox.app", @"Firefox Beta.app",
|
||||||
@"Safari.app", @"WebKit.app", @"Google Chrome.app",
|
@"Firefox Nightly.app", @"Safari.app", @"WebKit.app",
|
||||||
@"Google Chrome Canary.app", @"Chromium.app", @"Opera.app", nil];
|
@"Google Chrome.app", @"Google Chrome Canary.app",
|
||||||
|
@"Chromium.app", @"Opera.app", nil];
|
||||||
|
|
||||||
constexpr NSString* const kDockDomainName = @"com.apple.dock";
|
constexpr NSString* const kDockDomainName = @"com.apple.dock";
|
||||||
// See https://developer.apple.com/documentation/devicemanagement/dock
|
// See https://developer.apple.com/documentation/devicemanagement/dock
|
||||||
constexpr NSString* const kDockPersistentAppsKey = @"persistent-apps";
|
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 kDockTileDataKey = @"tile-data";
|
||||||
constexpr NSString* const kDockFileDataKey = @"file-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.
|
// Some special tiles may not have DockFileData but we can ignore those.
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
NSURL* url = CFBridgingRelease(_CFURLCreateFromPropertyListRepresentation(NULL, fileData));
|
NSURL* url = CFBridgingRelease(
|
||||||
|
_CFURLCreateFromPropertyListRepresentation(NULL, fileData));
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return nil;
|
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
|
// The only reliable way to get our changes to take effect seems to be to use
|
||||||
// `kill`.
|
// `kill`.
|
||||||
void RefreshDock(NSDictionary* aDockPlist) {
|
void RefreshDock(NSDictionary* aDockPlist) {
|
||||||
[[NSUserDefaults standardUserDefaults] setPersistentDomain:aDockPlist forName:kDockDomainName];
|
[[NSUserDefaults standardUserDefaults] setPersistentDomain:aDockPlist
|
||||||
|
forName:kDockDomainName];
|
||||||
NSRunningApplication* dockApp = [[NSRunningApplication
|
NSRunningApplication* dockApp = [[NSRunningApplication
|
||||||
runningApplicationsWithBundleIdentifier:@"com.apple.dock"] firstObject];
|
runningApplicationsWithBundleIdentifier:@"com.apple.dock"] firstObject];
|
||||||
if (!dockApp) {
|
if (!dockApp) {
|
||||||
|
|
@ -276,8 +288,8 @@ nsresult nsMacDockSupport::GetIsAppInDock(bool* aIsInDock) {
|
||||||
|
|
||||||
*aIsInDock = false;
|
*aIsInDock = false;
|
||||||
|
|
||||||
NSDictionary* dockPlist =
|
NSDictionary* dockPlist = [[NSUserDefaults standardUserDefaults]
|
||||||
[[NSUserDefaults standardUserDefaults] persistentDomainForName:kDockDomainName];
|
persistentDomainForName:kDockDomainName];
|
||||||
if (!dockPlist) {
|
if (!dockPlist) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -302,22 +314,22 @@ nsresult nsMacDockSupport::GetIsAppInDock(bool* aIsInDock) {
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
|
nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(
|
||||||
const nsAString& aAppToReplacePath,
|
const nsAString& aAppPath, const nsAString& aAppToReplacePath,
|
||||||
bool* aIsInDock) {
|
bool* aIsInDock) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
MOZ_ASSERT(aAppPath != aAppToReplacePath || !aAppPath.IsEmpty());
|
MOZ_ASSERT(aAppPath != aAppToReplacePath || !aAppPath.IsEmpty());
|
||||||
|
|
||||||
*aIsInDock = false;
|
*aIsInDock = false;
|
||||||
|
|
||||||
NSString* appPath =
|
NSString* appPath = !aAppPath.IsEmpty() ? nsCocoaUtils::ToNSString(aAppPath)
|
||||||
!aAppPath.IsEmpty() ? nsCocoaUtils::ToNSString(aAppPath) : [[NSBundle mainBundle] bundlePath];
|
: [[NSBundle mainBundle] bundlePath];
|
||||||
NSString* appToReplacePath = nsCocoaUtils::ToNSString(aAppToReplacePath);
|
NSString* appToReplacePath = nsCocoaUtils::ToNSString(aAppToReplacePath);
|
||||||
|
|
||||||
NSMutableDictionary* dockPlist =
|
NSMutableDictionary* dockPlist = [NSMutableDictionary
|
||||||
[NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults]
|
dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults]
|
||||||
persistentDomainForName:kDockDomainName]];
|
persistentDomainForName:kDockDomainName]];
|
||||||
if (!dockPlist) {
|
if (!dockPlist) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -335,11 +347,13 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
|
||||||
NSUInteger toReplaceAppIndex = NSNotFound;
|
NSUInteger toReplaceAppIndex = NSNotFound;
|
||||||
NSUInteger lastBrowserAppIndex = NSNotFound;
|
NSUInteger lastBrowserAppIndex = NSNotFound;
|
||||||
for (NSUInteger index = 0; index < [persistentApps count]; ++index) {
|
for (NSUInteger index = 0; index < [persistentApps count]; ++index) {
|
||||||
NSString* persistentAppPath = GetPathForApp([persistentApps objectAtIndex:index]);
|
NSString* persistentAppPath =
|
||||||
|
GetPathForApp([persistentApps objectAtIndex:index]);
|
||||||
|
|
||||||
if ([persistentAppPath isEqualToString:appPath]) {
|
if ([persistentAppPath isEqualToString:appPath]) {
|
||||||
preexistingAppIndex = index;
|
preexistingAppIndex = index;
|
||||||
} else if (appToReplacePath && [persistentAppPath isEqualToString:appToReplacePath]) {
|
} else if (appToReplacePath &&
|
||||||
|
[persistentAppPath isEqualToString:appToReplacePath]) {
|
||||||
toReplaceAppIndex = index;
|
toReplaceAppIndex = index;
|
||||||
} else {
|
} else {
|
||||||
NSString* appName = [appPath lastPathComponent];
|
NSString* appName = [appPath lastPathComponent];
|
||||||
|
|
@ -381,14 +395,16 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
|
||||||
NSDictionary* newDockTile = nullptr;
|
NSDictionary* newDockTile = nullptr;
|
||||||
{
|
{
|
||||||
NSURL* appUrl = [NSURL fileURLWithPath:appPath isDirectory:YES];
|
NSURL* appUrl = [NSURL fileURLWithPath:appPath isDirectory:YES];
|
||||||
NSDictionary* dict =
|
NSDictionary* dict = CFBridgingRelease(
|
||||||
CFBridgingRelease(_CFURLCopyPropertyListRepresentation((__bridge CFURLRef)appUrl));
|
_CFURLCopyPropertyListRepresentation((__bridge CFURLRef)appUrl));
|
||||||
if (!dict) {
|
if (!dict) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
NSDictionary* dockTileData = [NSDictionary dictionaryWithObject:dict forKey:kDockFileDataKey];
|
NSDictionary* dockTileData =
|
||||||
|
[NSDictionary dictionaryWithObject:dict forKey:kDockFileDataKey];
|
||||||
if (dockTileData) {
|
if (dockTileData) {
|
||||||
newDockTile = [NSDictionary dictionaryWithObject:dockTileData forKey:kDockTileDataKey];
|
newDockTile = [NSDictionary dictionaryWithObject:dockTileData
|
||||||
|
forKey:kDockTileDataKey];
|
||||||
}
|
}
|
||||||
if (!newDockTile) {
|
if (!newDockTile) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
@ -397,7 +413,8 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(const nsAString& aAppPath,
|
||||||
|
|
||||||
// Update the Dock:
|
// Update the Dock:
|
||||||
if (toReplaceAppIndex != NSNotFound) {
|
if (toReplaceAppIndex != NSNotFound) {
|
||||||
[persistentApps replaceObjectAtIndex:toReplaceAppIndex withObject:newDockTile];
|
[persistentApps replaceObjectAtIndex:toReplaceAppIndex
|
||||||
|
withObject:newDockTile];
|
||||||
} else {
|
} else {
|
||||||
NSUInteger index;
|
NSUInteger index;
|
||||||
if (sameNameAppIndex != NSNotFound) {
|
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: */
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
|
@ -24,16 +25,19 @@ nsMacFinderProgress::~nsMacFinderProgress() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMacFinderProgress::Init(const nsAString& path,
|
nsMacFinderProgress::Init(
|
||||||
nsIMacFinderProgressCanceledCallback* cancellationCallback) {
|
const nsAString& path,
|
||||||
|
nsIMacFinderProgressCanceledCallback* cancellationCallback) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NSURL* pathUrl = [NSURL
|
NSURL* pathUrl = [NSURL
|
||||||
fileURLWithPath:[NSString
|
fileURLWithPath:[NSString
|
||||||
stringWithCharacters:reinterpret_cast<const unichar*>(path.BeginReading())
|
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
path.BeginReading())
|
||||||
length:path.Length()]];
|
length:path.Length()]];
|
||||||
NSDictionary* userInfo = @{
|
NSDictionary* userInfo = @{
|
||||||
@"NSProgressFileOperationKindKey" : @"NSProgressFileOperationKindDownloading",
|
@"NSProgressFileOperationKindKey" :
|
||||||
|
@"NSProgressFileOperationKindDownloading",
|
||||||
@"NSProgressFileURLKey" : pathUrl
|
@"NSProgressFileURLKey" : pathUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,13 +45,14 @@ nsMacFinderProgress::Init(const nsAString& path,
|
||||||
mProgress.kind = NSProgressKindFile;
|
mProgress.kind = NSProgressKindFile;
|
||||||
mProgress.cancellable = YES;
|
mProgress.cancellable = YES;
|
||||||
|
|
||||||
nsMainThreadPtrHandle<nsIMacFinderProgressCanceledCallback> cancellationCallbackHandle(
|
nsMainThreadPtrHandle<nsIMacFinderProgressCanceledCallback>
|
||||||
new nsMainThreadPtrHolder<nsIMacFinderProgressCanceledCallback>(
|
cancellationCallbackHandle(
|
||||||
"MacFinderProgress::CancellationCallback", cancellationCallback));
|
new nsMainThreadPtrHolder<nsIMacFinderProgressCanceledCallback>(
|
||||||
|
"MacFinderProgress::CancellationCallback", cancellationCallback));
|
||||||
|
|
||||||
mProgress.cancellationHandler = ^{
|
mProgress.cancellationHandler = ^{
|
||||||
NS_DispatchToMainThread(
|
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||||
NS_NewRunnableFunction("MacFinderProgress::Canceled", [cancellationCallbackHandle] {
|
"MacFinderProgress::Canceled", [cancellationCallbackHandle] {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
cancellationCallbackHandle->Canceled();
|
cancellationCallbackHandle->Canceled();
|
||||||
}));
|
}));
|
||||||
|
|
@ -61,7 +66,8 @@ nsMacFinderProgress::Init(const nsAString& path,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMacFinderProgress::UpdateProgress(uint64_t currentProgress, uint64_t totalProgress) {
|
nsMacFinderProgress::UpdateProgress(uint64_t currentProgress,
|
||||||
|
uint64_t totalProgress) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
if (mProgress) {
|
if (mProgress) {
|
||||||
mProgress.totalUnitCount = totalProgress;
|
mProgress.totalUnitCount = totalProgress;
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,13 @@
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(nsMacSharingService, nsIMacSharingService)
|
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
|
// These are some undocumented constants also used by Safari
|
||||||
// to let us open the preferences window
|
// 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';
|
const UInt32 openSharingSubpaneDescriptorType = 'ptru';
|
||||||
NSString* const openSharingSubpaneActionKey = @"action";
|
NSString* const openSharingSubpaneActionKey = @"action";
|
||||||
NSString* const openSharingSubpaneActionValue = @"revealExtensionPoint";
|
NSString* const openSharingSubpaneActionValue = @"revealExtensionPoint";
|
||||||
|
|
@ -31,10 +33,11 @@ NSString* const openSharingSubpaneProtocolValue = @"com.apple.share-services";
|
||||||
- (id)name;
|
- (id)name;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// Filter providers that we do not want to expose to the user, because they are duplicates or do not
|
// Filter providers that we do not want to expose to the user, because they are
|
||||||
// work correctly within the context
|
// duplicates or do not work correctly within the context
|
||||||
static bool ShouldIgnoreProvider(NSString* aProviderName) {
|
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
|
// Clean up the activity once the share is complete
|
||||||
|
|
@ -61,7 +64,8 @@ static bool ShouldIgnoreProvider(NSString* aProviderName) {
|
||||||
mShareActivity = nil;
|
mShareActivity = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sharingService:(NSSharingService*)sharingService didShareItems:(NSArray*)items {
|
- (void)sharingService:(NSSharingService*)sharingService
|
||||||
|
didShareItems:(NSArray*)items {
|
||||||
[self cleanup];
|
[self cleanup];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,16 +84,18 @@ static bool ShouldIgnoreProvider(NSString* aProviderName) {
|
||||||
|
|
||||||
static NSString* NSImageToBase64(const NSImage* aImage) {
|
static NSString* NSImageToBase64(const NSImage* aImage) {
|
||||||
CGImageRef cgRef = [aImage CGImageForProposedRect:nil context:nil hints:nil];
|
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]];
|
[bitmapRep setSize:[aImage size]];
|
||||||
NSData* imageData = [bitmapRep representationUsingType:NSPNGFileType properties:@{}];
|
NSData* imageData = [bitmapRep representationUsingType:NSPNGFileType
|
||||||
|
properties:@{}];
|
||||||
NSString* base64Encoded = [imageData base64EncodedStringWithOptions:0];
|
NSString* base64Encoded = [imageData base64EncodedStringWithOptions:0];
|
||||||
[bitmapRep release];
|
[bitmapRep release];
|
||||||
return [NSString stringWithFormat:@"data:image/png;base64,%@", base64Encoded];
|
return [NSString stringWithFormat:@"data:image/png;base64,%@", base64Encoded];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj, const char* aKey,
|
static void SetStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& aObj,
|
||||||
NSString* aVal) {
|
const char* aKey, NSString* aVal) {
|
||||||
nsAutoString strVal;
|
nsAutoString strVal;
|
||||||
mozilla::CopyCocoaStringToXPCOMString(aVal, strVal);
|
mozilla::CopyCocoaStringToXPCOMString(aVal, strVal);
|
||||||
JS::Rooted<JSString*> title(aCx, JS_NewUCStringCopyZ(aCx, strVal.get()));
|
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);
|
JS_SetProperty(aCx, aObj, aKey, attVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsMacSharingService::GetSharingProviders(const nsAString& aPageUrl, JSContext* aCx,
|
nsresult nsMacSharingService::GetSharingProviders(
|
||||||
JS::MutableHandle<JS::Value> aResult) {
|
const nsAString& aPageUrl, JSContext* aCx,
|
||||||
|
JS::MutableHandle<JS::Value> aResult) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NSURL* url = nsCocoaUtils::ToNSURL(aPageUrl);
|
NSURL* url = nsCocoaUtils::ToNSURL(aPageUrl);
|
||||||
|
|
@ -135,18 +142,20 @@ NS_IMETHODIMP
|
||||||
nsMacSharingService::OpenSharingPreferences() {
|
nsMacSharingService::OpenSharingPreferences() {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NSURL* prefPaneURL = [NSURL fileURLWithPath:extensionPrefPanePath isDirectory:YES];
|
NSURL* prefPaneURL = [NSURL fileURLWithPath:extensionPrefPanePath
|
||||||
|
isDirectory:YES];
|
||||||
NSDictionary* args = @{
|
NSDictionary* args = @{
|
||||||
openSharingSubpaneActionKey : openSharingSubpaneActionValue,
|
openSharingSubpaneActionKey : openSharingSubpaneActionValue,
|
||||||
openSharingSubpaneProtocolKey : openSharingSubpaneProtocolValue
|
openSharingSubpaneProtocolKey : openSharingSubpaneProtocolValue
|
||||||
};
|
};
|
||||||
NSData* data = [NSPropertyListSerialization dataWithPropertyList:args
|
NSData* data = [NSPropertyListSerialization
|
||||||
format:NSPropertyListXMLFormat_v1_0
|
dataWithPropertyList:args
|
||||||
options:0
|
format:NSPropertyListXMLFormat_v1_0
|
||||||
error:nil];
|
options:0
|
||||||
NSAppleEventDescriptor* descriptor =
|
error:nil];
|
||||||
[[NSAppleEventDescriptor alloc] initWithDescriptorType:openSharingSubpaneDescriptorType
|
NSAppleEventDescriptor* descriptor = [[NSAppleEventDescriptor alloc]
|
||||||
data:data];
|
initWithDescriptorType:openSharingSubpaneDescriptorType
|
||||||
|
data:data];
|
||||||
|
|
||||||
[[NSWorkspace sharedWorkspace] openURLs:@[ prefPaneURL ]
|
[[NSWorkspace sharedWorkspace] openURLs:@[ prefPaneURL ]
|
||||||
withAppBundleIdentifier:nil
|
withAppBundleIdentifier:nil
|
||||||
|
|
@ -161,19 +170,21 @@ nsMacSharingService::OpenSharingPreferences() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMacSharingService::ShareUrl(const nsAString& aServiceName, const nsAString& aPageUrl,
|
nsMacSharingService::ShareUrl(const nsAString& aServiceName,
|
||||||
|
const nsAString& aPageUrl,
|
||||||
const nsAString& aPageTitle) {
|
const nsAString& aPageTitle) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
NSString* serviceName = nsCocoaUtils::ToNSString(aServiceName);
|
NSString* serviceName = nsCocoaUtils::ToNSString(aServiceName);
|
||||||
NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl);
|
NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl);
|
||||||
NSString* pageTitle = nsCocoaUtils::ToNSString(aPageTitle);
|
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
|
// Reminders fetch its data from an activity, not the share data
|
||||||
if ([[service name] isEqual:remindersServiceName]) {
|
if ([[service name] isEqual:remindersServiceName]) {
|
||||||
NSUserActivity* shareActivity =
|
NSUserActivity* shareActivity = [[NSUserActivity alloc]
|
||||||
[[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
||||||
|
|
||||||
if ([pageUrl.scheme hasPrefix:@"http"]) {
|
if ([pageUrl.scheme hasPrefix:@"http"]) {
|
||||||
[shareActivity setWebpageURL:pageUrl];
|
[shareActivity setWebpageURL:pageUrl];
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
NS_IMPL_ISUPPORTS(nsMacUserActivityUpdater, nsIMacUserActivityUpdater)
|
NS_IMPL_ISUPPORTS(nsMacUserActivityUpdater, nsIMacUserActivityUpdater)
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAString& aPageTitle,
|
nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl,
|
||||||
|
const nsAString& aPageTitle,
|
||||||
nsIBaseWindow* aWindow) {
|
nsIBaseWindow* aWindow) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
if (gfxPlatform::IsHeadless()) {
|
if (gfxPlatform::IsHeadless()) {
|
||||||
|
|
@ -27,8 +28,8 @@ nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAStr
|
||||||
}
|
}
|
||||||
|
|
||||||
NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl);
|
NSURL* pageUrl = nsCocoaUtils::ToNSURL(aPageUrl);
|
||||||
if (!pageUrl ||
|
if (!pageUrl || (![pageUrl.scheme isEqualToString:@"https"] &&
|
||||||
(![pageUrl.scheme isEqualToString:@"https"] && ![pageUrl.scheme isEqualToString:@"http"])) {
|
![pageUrl.scheme isEqualToString:@"http"])) {
|
||||||
[cocoaWin.userActivity invalidate];
|
[cocoaWin.userActivity invalidate];
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -38,8 +39,8 @@ nsMacUserActivityUpdater::UpdateLocation(const nsAString& aPageUrl, const nsAStr
|
||||||
pageTitle = pageUrl.absoluteString;
|
pageTitle = pageUrl.absoluteString;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSUserActivity* userActivity =
|
NSUserActivity* userActivity = [[NSUserActivity alloc]
|
||||||
[[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
||||||
userActivity.webpageURL = pageUrl;
|
userActivity.webpageURL = pageUrl;
|
||||||
userActivity.title = pageTitle;
|
userActivity.title = pageTitle;
|
||||||
cocoaWin.userActivity = userActivity;
|
cocoaWin.userActivity = userActivity;
|
||||||
|
|
|
||||||
|
|
@ -13,25 +13,28 @@
|
||||||
#include "nsObjCExceptions.h"
|
#include "nsObjCExceptions.h"
|
||||||
|
|
||||||
// Find the path to the app with the given bundleIdentifier, if any.
|
// 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.
|
// Note that the OS will return the path to the newest binary, if there is more
|
||||||
// The determination of 'newest' is complex and beyond the scope of this comment.
|
// than one. The determination of 'newest' is complex and beyond the scope of
|
||||||
|
// this comment.
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(nsMacWebAppUtils, nsIMacWebAppUtils)
|
NS_IMPL_ISUPPORTS(nsMacWebAppUtils, nsIMacWebAppUtils)
|
||||||
|
|
||||||
NS_IMETHODIMP nsMacWebAppUtils::PathForAppWithIdentifier(const nsAString& bundleIdentifier,
|
NS_IMETHODIMP nsMacWebAppUtils::PathForAppWithIdentifier(
|
||||||
nsAString& outPath) {
|
const nsAString& bundleIdentifier, nsAString& outPath) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
outPath.Truncate();
|
outPath.Truncate();
|
||||||
|
|
||||||
nsAutoreleasePool localPool;
|
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]
|
NSString* temp = [[NSWorkspace sharedWorkspace]
|
||||||
absolutePathForAppBundleWithIdentifier:
|
absolutePathForAppBundleWithIdentifier:
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
[NSString
|
||||||
((nsString)bundleIdentifier).get())
|
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
length:((nsString)bundleIdentifier).Length()]];
|
((nsString)bundleIdentifier).get())
|
||||||
|
length:((nsString)bundleIdentifier).Length()]];
|
||||||
|
|
||||||
if (temp) {
|
if (temp) {
|
||||||
// Copy out the resultant absolute path into outPath if non-nil.
|
// 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_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;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
nsAutoreleasePool localPool;
|
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]
|
BOOL success = [[NSWorkspace sharedWorkspace]
|
||||||
launchAppWithBundleIdentifier:[NSString
|
launchAppWithBundleIdentifier:
|
||||||
stringWithCharacters:reinterpret_cast<const unichar*>(
|
[NSString
|
||||||
((nsString)bundleIdentifier)
|
stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
.get())
|
((nsString)bundleIdentifier).get())
|
||||||
length:((nsString)bundleIdentifier).Length()]
|
length:((nsString)bundleIdentifier).Length()]
|
||||||
options:(NSWorkspaceLaunchOptions)0
|
options:(NSWorkspaceLaunchOptions)0
|
||||||
additionalEventParamDescriptor:nil
|
additionalEventParamDescriptor:nil
|
||||||
launchIdentifier:NULL];
|
launchIdentifier:NULL];
|
||||||
|
|
@ -64,7 +69,8 @@ NS_IMETHODIMP nsMacWebAppUtils::LaunchAppWithIdentifier(const nsAString& bundleI
|
||||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
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;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
if (NS_WARN_IF(!aCallback)) {
|
if (NS_WARN_IF(!aCallback)) {
|
||||||
|
|
@ -74,11 +80,13 @@ NS_IMETHODIMP nsMacWebAppUtils::TrashApp(const nsAString& path, nsITrashAppCallb
|
||||||
nsCOMPtr<nsITrashAppCallback> callback = aCallback;
|
nsCOMPtr<nsITrashAppCallback> callback = aCallback;
|
||||||
|
|
||||||
NSString* tempString =
|
NSString* tempString =
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(((nsString)path).get())
|
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
((nsString)path).get())
|
||||||
length:path.Length()];
|
length:path.Length()];
|
||||||
|
|
||||||
[[NSWorkspace sharedWorkspace]
|
[[NSWorkspace sharedWorkspace]
|
||||||
recycleURLs:[NSArray arrayWithObject:[NSURL fileURLWithPath:tempString]]
|
recycleURLs:[NSArray
|
||||||
|
arrayWithObject:[NSURL fileURLWithPath:tempString]]
|
||||||
completionHandler:^(NSDictionary* newURLs, NSError* error) {
|
completionHandler:^(NSDictionary* newURLs, NSError* error) {
|
||||||
nsresult rv = (error == nil) ? NS_OK : NS_ERROR_FAILURE;
|
nsresult rv = (error == nil) ? NS_OK : NS_ERROR_FAILURE;
|
||||||
callback->TrashAppFinished(rv);
|
callback->TrashAppFinished(rv);
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,11 @@ BOOL gSomeMenuBarPainted = NO;
|
||||||
// defined in nsCocoaWindow.mm.
|
// defined in nsCocoaWindow.mm.
|
||||||
extern BOOL sTouchBarIsInitialized;
|
extern BOOL sTouchBarIsInitialized;
|
||||||
|
|
||||||
// We keep references to the first quit and pref item content nodes we find, which
|
// We keep references to the first quit and pref item content nodes we find,
|
||||||
// will be from the hidden window. We use these when the document for the current
|
// which will be from the hidden window. We use these when the document for the
|
||||||
// window does not have a quit or pref item. We don't need strong refs here because
|
// current window does not have a quit or pref item. We don't need strong refs
|
||||||
// these items are always strong ref'd by their owning menu bar (instance variable).
|
// here because these items are always strong ref'd by their owning menu bar
|
||||||
|
// (instance variable).
|
||||||
static nsIContent* sAboutItemContent = nullptr;
|
static nsIContent* sAboutItemContent = nullptr;
|
||||||
static nsIContent* sPrefItemContent = nullptr;
|
static nsIContent* sPrefItemContent = nullptr;
|
||||||
static nsIContent* sAccountItemContent = nullptr;
|
static nsIContent* sAccountItemContent = nullptr;
|
||||||
|
|
@ -140,8 +141,9 @@ void nsMenuBarX::ConstructNativeMenus() {
|
||||||
for (nsIContent* menuContent = mContent->GetFirstChild(); menuContent;
|
for (nsIContent* menuContent = mContent->GetFirstChild(); menuContent;
|
||||||
menuContent = menuContent->GetNextSibling()) {
|
menuContent = menuContent->GetNextSibling()) {
|
||||||
if (menuContent->IsXULElement(nsGkAtoms::menu)) {
|
if (menuContent->IsXULElement(nsGkAtoms::menu)) {
|
||||||
InsertMenuAtIndex(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, menuContent->AsElement()),
|
InsertMenuAtIndex(
|
||||||
GetMenuCount());
|
MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, menuContent->AsElement()),
|
||||||
|
GetMenuCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +158,8 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
|
||||||
|
|
||||||
nsCOMPtr<nsIStringBundle> stringBundle;
|
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",
|
bundleSvc->CreateBundle("chrome://global/locale/fallbackMenubar.properties",
|
||||||
getter_AddRefs(stringBundle));
|
getter_AddRefs(stringBundle));
|
||||||
|
|
||||||
|
|
@ -173,8 +176,10 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
|
||||||
stringBundle->GetStringFromName(labelProp, labelUTF16);
|
stringBundle->GetStringFromName(labelProp, labelUTF16);
|
||||||
stringBundle->GetStringFromName(keyProp, keyUTF16);
|
stringBundle->GetStringFromName(keyProp, keyUTF16);
|
||||||
|
|
||||||
NSString* labelStr = [NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(labelUTF16).get()];
|
NSString* labelStr =
|
||||||
NSString* keyStr = [NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(keyUTF16).get()];
|
[NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(labelUTF16).get()];
|
||||||
|
NSString* keyStr =
|
||||||
|
[NSString stringWithUTF8String:NS_ConvertUTF16toUTF8(keyUTF16).get()];
|
||||||
|
|
||||||
if (!nsMenuBarX::sNativeEventTarget) {
|
if (!nsMenuBarX::sNativeEventTarget) {
|
||||||
nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init];
|
nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init];
|
||||||
|
|
@ -182,12 +187,14 @@ void nsMenuBarX::ConstructFallbackNativeMenus() {
|
||||||
|
|
||||||
sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain];
|
sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain];
|
||||||
if (!mApplicationMenuDelegate) {
|
if (!mApplicationMenuDelegate) {
|
||||||
mApplicationMenuDelegate = [[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
|
mApplicationMenuDelegate =
|
||||||
|
[[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
|
||||||
}
|
}
|
||||||
sApplicationMenu.delegate = mApplicationMenuDelegate;
|
sApplicationMenu.delegate = mApplicationMenuDelegate;
|
||||||
NSMenuItem* quitMenuItem = [[[NSMenuItem alloc] initWithTitle:labelStr
|
NSMenuItem* quitMenuItem =
|
||||||
action:@selector(menuItemHit:)
|
[[[NSMenuItem alloc] initWithTitle:labelStr
|
||||||
keyEquivalent:keyStr] autorelease];
|
action:@selector(menuItemHit:)
|
||||||
|
keyEquivalent:keyStr] autorelease];
|
||||||
quitMenuItem.target = nsMenuBarX::sNativeEventTarget;
|
quitMenuItem.target = nsMenuBarX::sNativeEventTarget;
|
||||||
quitMenuItem.tag = eCommand_ID_Quit;
|
quitMenuItem.tag = eCommand_ID_Quit;
|
||||||
[sApplicationMenu addItem:quitMenuItem];
|
[sApplicationMenu addItem:quitMenuItem];
|
||||||
|
|
@ -201,7 +208,8 @@ uint32_t nsMenuBarX::GetMenuCount() { return mMenuArray.Length(); }
|
||||||
bool nsMenuBarX::MenuContainsAppMenu() {
|
bool nsMenuBarX::MenuContainsAppMenu() {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
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;
|
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.
|
// Hook the new Application menu up to the menu bar.
|
||||||
NSMenu* mainMenu = NSApp.mainMenu;
|
NSMenu* mainMenu = NSApp.mainMenu;
|
||||||
NS_ASSERTION(mainMenu.numberOfItems > 0,
|
NS_ASSERTION(
|
||||||
"Main menu does not have any items, something is terribly wrong!");
|
mainMenu.numberOfItems > 0,
|
||||||
|
"Main menu does not have any items, something is terribly wrong!");
|
||||||
[mainMenu itemAtIndex:0].submenu = sApplicationMenu;
|
[mainMenu itemAtIndex:0].submenu = sApplicationMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,7 +239,8 @@ void nsMenuBarX::InsertMenuAtIndex(RefPtr<nsMenuX>&& aMenu, uint32_t aIndex) {
|
||||||
|
|
||||||
// hook up submenus
|
// hook up submenus
|
||||||
RefPtr<nsIContent> menuContent = aMenu->Content();
|
RefPtr<nsIContent> menuContent = aMenu->Content();
|
||||||
if (menuContent->GetChildCount() > 0 && !nsMenuUtilsX::NodeIsHiddenOrCollapsed(menuContent)) {
|
if (menuContent->GetChildCount() > 0 &&
|
||||||
|
!nsMenuUtilsX::NodeIsHiddenOrCollapsed(menuContent)) {
|
||||||
MenuChildChangedVisibility(MenuChild(aMenu), true);
|
MenuChildChangedVisibility(MenuChild(aMenu), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,11 +273,14 @@ void nsMenuBarX::RemoveMenuAtIndex(uint32_t aIndex) {
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
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) {}
|
nsAtom* aAttribute) {}
|
||||||
|
|
||||||
void nsMenuBarX::ObserveContentRemoved(mozilla::dom::Document* aDocument, nsIContent* aContainer,
|
void nsMenuBarX::ObserveContentRemoved(mozilla::dom::Document* aDocument,
|
||||||
nsIContent* aChild, nsIContent* aPreviousSibling) {
|
nsIContent* aContainer,
|
||||||
|
nsIContent* aChild,
|
||||||
|
nsIContent* aPreviousSibling) {
|
||||||
nsINode* parent = NODE_FROM(aContainer, aDocument);
|
nsINode* parent = NODE_FROM(aContainer, aDocument);
|
||||||
MOZ_ASSERT(parent);
|
MOZ_ASSERT(parent);
|
||||||
const Maybe<uint32_t> index = parent->ComputeIndexOf(aPreviousSibling);
|
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);
|
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) {
|
nsIContent* aChild) {
|
||||||
InsertMenuAtIndex(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aChild),
|
InsertMenuAtIndex(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aChild),
|
||||||
aContainer->ComputeIndexOf(aChild).valueOr(UINT32_MAX));
|
aContainer->ComputeIndexOf(aChild).valueOr(UINT32_MAX));
|
||||||
|
|
@ -285,7 +299,8 @@ void nsMenuBarX::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||||
|
|
||||||
NSString* locationString =
|
NSString* locationString =
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(aIndexString.BeginReading())
|
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(
|
||||||
|
aIndexString.BeginReading())
|
||||||
length:aIndexString.Length()];
|
length:aIndexString.Length()];
|
||||||
NSArray* indexes = [locationString componentsSeparatedByString:@"|"];
|
NSArray* indexes = [locationString componentsSeparatedByString:@"|"];
|
||||||
unsigned int indexCount = indexes.count;
|
unsigned int indexCount = indexes.count;
|
||||||
|
|
@ -329,7 +344,9 @@ void nsMenuBarX::ForceUpdateNativeMenuAt(const nsAString& aIndexString) {
|
||||||
}
|
}
|
||||||
RefPtr<nsIContent> content = targetMenu->match(
|
RefPtr<nsIContent> content = targetMenu->match(
|
||||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
[](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)) {
|
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
|
||||||
visible++;
|
visible++;
|
||||||
if (targetMenu->is<RefPtr<nsMenuX>>() && visible == (targetIndex + 1)) {
|
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
|
// We have to keep the same menu item for the Application menu so we keep
|
||||||
// passing it along.
|
// passing it along.
|
||||||
NSMenu* outgoingMenu = NSApp.mainMenu;
|
NSMenu* outgoingMenu = NSApp.mainMenu;
|
||||||
NS_ASSERTION(outgoingMenu.numberOfItems > 0,
|
NS_ASSERTION(
|
||||||
"Main menu does not have any items, something is terribly wrong!");
|
outgoingMenu.numberOfItems > 0,
|
||||||
|
"Main menu does not have any items, something is terribly wrong!");
|
||||||
|
|
||||||
NSMenuItem* appMenuItem = [[outgoingMenu itemAtIndex:0] retain];
|
NSMenuItem* appMenuItem = [[outgoingMenu itemAtIndex:0] retain];
|
||||||
[outgoingMenu removeItemAtIndex:0];
|
[outgoingMenu removeItemAtIndex:0];
|
||||||
|
|
@ -456,8 +474,10 @@ bool nsMenuBarX::PerformKeyEquivalent(NSEvent* aEvent) {
|
||||||
return [mNativeMenu performSuperKeyEquivalent:aEvent];
|
return [mNativeMenu performSuperKeyEquivalent:aEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsMenuBarX::MenuChildChangedVisibility(const MenuChild& aChild, bool aIsVisible) {
|
void nsMenuBarX::MenuChildChangedVisibility(const MenuChild& aChild,
|
||||||
MOZ_RELEASE_ASSERT(aChild.is<RefPtr<nsMenuX>>(), "nsMenuBarX only has nsMenuX children");
|
bool aIsVisible) {
|
||||||
|
MOZ_RELEASE_ASSERT(aChild.is<RefPtr<nsMenuX>>(),
|
||||||
|
"nsMenuBarX only has nsMenuX children");
|
||||||
const RefPtr<nsMenuX>& child = aChild.as<RefPtr<nsMenuX>>();
|
const RefPtr<nsMenuX>& child = aChild.as<RefPtr<nsMenuX>>();
|
||||||
NSMenuItem* item = child->NativeNSMenuItem();
|
NSMenuItem* item = child->NativeNSMenuItem();
|
||||||
if (aIsVisible) {
|
if (aIsVisible) {
|
||||||
|
|
@ -475,8 +495,9 @@ NSInteger nsMenuBarX::CalculateNativeInsertionPoint(nsMenuX* aChild) {
|
||||||
return insertionPoint;
|
return insertionPoint;
|
||||||
}
|
}
|
||||||
// Only count items that are inside a menu.
|
// Only count items that are inside a menu.
|
||||||
// XXXmstange Not sure what would cause free-standing items. Maybe for collapsed/hidden menus?
|
// XXXmstange Not sure what would cause free-standing items. Maybe for
|
||||||
// In that case, an nsMenuX::IsVisible() method would be better.
|
// collapsed/hidden menus? In that case, an nsMenuX::IsVisible() method
|
||||||
|
// would be better.
|
||||||
if (currMenu->NativeNSMenuItem().menu) {
|
if (currMenu->NativeNSMenuItem().menu) {
|
||||||
insertionPoint++;
|
insertionPoint++;
|
||||||
}
|
}
|
||||||
|
|
@ -486,10 +507,12 @@ NSInteger nsMenuBarX::CalculateNativeInsertionPoint(nsMenuX* aChild) {
|
||||||
|
|
||||||
// Hide the item in the menu by setting the 'hidden' attribute. Returns it so
|
// Hide the item in the menu by setting the 'hidden' attribute. Returns it so
|
||||||
// the caller can hang onto it if they so choose.
|
// 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);
|
RefPtr<Element> menuElement = aDocument->GetElementById(aID);
|
||||||
if (menuElement) {
|
if (menuElement) {
|
||||||
menuElement->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, u"true"_ns, false);
|
menuElement->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, u"true"_ns,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
return menuElement;
|
return menuElement;
|
||||||
}
|
}
|
||||||
|
|
@ -536,7 +559,8 @@ void nsMenuBarX::AquifyMenuBar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// for creating menu items destined for the Application menu
|
// 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,
|
SEL aAction, int aTag,
|
||||||
NativeMenuItemTarget* aTarget) {
|
NativeMenuItemTarget* aTarget) {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
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
|
// Check collapsed rather than hidden since the app menu items are always
|
||||||
// hidden in AquifyMenuBar.
|
// hidden in AquifyMenuBar.
|
||||||
if (menuItem->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed, nsGkAtoms::_true,
|
if (menuItem->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed,
|
||||||
eCaseMatters)) {
|
nsGkAtoms::_true, eCaseMatters)) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -577,20 +601,23 @@ NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString&
|
||||||
nsAutoString keyChar(u" "_ns);
|
nsAutoString keyChar(u" "_ns);
|
||||||
keyElement->GetAttr(nsGkAtoms::key, keyChar);
|
keyElement->GetAttr(nsGkAtoms::key, keyChar);
|
||||||
if (!keyChar.EqualsLiteral(" ")) {
|
if (!keyChar.EqualsLiteral(" ")) {
|
||||||
keyEquiv = [[NSString stringWithCharacters:reinterpret_cast<const unichar*>(keyChar.get())
|
keyEquiv = [[NSString
|
||||||
length:keyChar.Length()] lowercaseString];
|
stringWithCharacters:reinterpret_cast<const unichar*>(keyChar.get())
|
||||||
|
length:keyChar.Length()] lowercaseString];
|
||||||
}
|
}
|
||||||
// now grab the key equivalent modifiers
|
// now grab the key equivalent modifiers
|
||||||
nsAutoString modifiersStr;
|
nsAutoString modifiersStr;
|
||||||
keyElement->GetAttr(nsGkAtoms::modifiers, modifiersStr);
|
keyElement->GetAttr(nsGkAtoms::modifiers, modifiersStr);
|
||||||
uint8_t geckoModifiers = nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr);
|
uint8_t geckoModifiers =
|
||||||
macKeyModifiers = nsMenuUtilsX::MacModifiersForGeckoModifiers(geckoModifiers);
|
nsMenuUtilsX::GeckoModifiersForNodeAttribute(modifiersStr);
|
||||||
|
macKeyModifiers =
|
||||||
|
nsMenuUtilsX::MacModifiersForGeckoModifiers(geckoModifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get the label into NSString-form
|
// get the label into NSString-form
|
||||||
NSString* labelString =
|
NSString* labelString = [NSString
|
||||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(label.get())
|
stringWithCharacters:reinterpret_cast<const unichar*>(label.get())
|
||||||
length:label.Length()];
|
length:label.Length()];
|
||||||
|
|
||||||
if (!labelString) {
|
if (!labelString) {
|
||||||
labelString = @"";
|
labelString = @"";
|
||||||
|
|
@ -634,7 +661,8 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
= Preferences... = <- menu_preferences
|
= Preferences... = <- menu_preferences
|
||||||
= Account Settings = <- menu_accountmgr Only on Thunderbird
|
= 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 App = <- menu_mac_hide_app
|
||||||
= Hide Others = <- menu_mac_hide_others
|
= 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
|
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
|
them. We always add a "Quit" item, but if an app developer does not provide
|
||||||
DOM node with the right ID for the Quit item, we add it in English. App
|
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
|
developers need only add each node with a label and a key equivalent (if
|
||||||
want one). Other attributes are optional. Like so:
|
they want one). Other attributes are optional. Like so:
|
||||||
|
|
||||||
<menuitem id="menu_preferences"
|
<menuitem id="menu_preferences"
|
||||||
label="&preferencesCmdMac.label;"
|
label="&preferencesCmdMac.label;"
|
||||||
key="open_prefs_key"/>
|
key="open_prefs_key"/>
|
||||||
|
|
||||||
We need to use this system for localization purposes, until we have a better way
|
We need to use this system for localization purposes, until we have a better
|
||||||
to define the Application menu to be used on Mac OS X.
|
way to define the Application menu to be used on Mac OS X.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (sApplicationMenu) {
|
if (sApplicationMenu) {
|
||||||
if (!mApplicationMenuDelegate) {
|
if (!mApplicationMenuDelegate) {
|
||||||
mApplicationMenuDelegate = [[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
|
mApplicationMenuDelegate =
|
||||||
|
[[ApplicationMenuDelegate alloc] initWithApplicationMenu:this];
|
||||||
}
|
}
|
||||||
sApplicationMenu.delegate = mApplicationMenuDelegate;
|
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;
|
NSMenuItem* itemBeingAdded = nil;
|
||||||
BOOL addAboutSeparator = FALSE;
|
BOOL addAboutSeparator = FALSE;
|
||||||
BOOL addPrefsSeparator = FALSE;
|
BOOL addPrefsSeparator = FALSE;
|
||||||
|
|
||||||
// Add the About menu item
|
// Add the About menu item
|
||||||
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"aboutName"_ns, @selector(menuItemHit:),
|
itemBeingAdded = CreateNativeAppMenuItem(
|
||||||
eCommand_ID_About, nsMenuBarX::sNativeEventTarget);
|
aMenu, u"aboutName"_ns, @selector(menuItemHit:), eCommand_ID_About,
|
||||||
|
nsMenuBarX::sNativeEventTarget);
|
||||||
if (itemBeingAdded) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
[itemBeingAdded release];
|
[itemBeingAdded release];
|
||||||
|
|
@ -688,8 +719,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the Preferences menu item
|
// Add the Preferences menu item
|
||||||
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"menu_preferences"_ns, @selector(menuItemHit:),
|
itemBeingAdded = CreateNativeAppMenuItem(
|
||||||
eCommand_ID_Prefs, nsMenuBarX::sNativeEventTarget);
|
aMenu, u"menu_preferences"_ns, @selector(menuItemHit:),
|
||||||
|
eCommand_ID_Prefs, nsMenuBarX::sNativeEventTarget);
|
||||||
if (itemBeingAdded) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
[itemBeingAdded release];
|
[itemBeingAdded release];
|
||||||
|
|
@ -699,8 +731,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the Account Settings menu item. This is Thunderbird only
|
// Add the Account Settings menu item. This is Thunderbird only
|
||||||
itemBeingAdded = CreateNativeAppMenuItem(aMenu, u"menu_accountmgr"_ns, @selector(menuItemHit:),
|
itemBeingAdded = CreateNativeAppMenuItem(
|
||||||
eCommand_ID_Account, nsMenuBarX::sNativeEventTarget);
|
aMenu, u"menu_accountmgr"_ns, @selector(menuItemHit:),
|
||||||
|
eCommand_ID_Account, nsMenuBarX::sNativeEventTarget);
|
||||||
if (itemBeingAdded) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
[itemBeingAdded release];
|
[itemBeingAdded release];
|
||||||
|
|
@ -713,7 +746,8 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add Services menu item
|
// 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) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
|
|
||||||
|
|
@ -732,9 +766,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
BOOL addHideShowSeparator = FALSE;
|
BOOL addHideShowSeparator = FALSE;
|
||||||
|
|
||||||
// Add menu item to hide this application
|
// Add menu item to hide this application
|
||||||
itemBeingAdded =
|
itemBeingAdded = CreateNativeAppMenuItem(
|
||||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_hide_app"_ns, @selector(menuItemHit:),
|
aMenu, u"menu_mac_hide_app"_ns, @selector(menuItemHit:),
|
||||||
eCommand_ID_HideApp, nsMenuBarX::sNativeEventTarget);
|
eCommand_ID_HideApp, nsMenuBarX::sNativeEventTarget);
|
||||||
if (itemBeingAdded) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
[itemBeingAdded release];
|
[itemBeingAdded release];
|
||||||
|
|
@ -744,9 +778,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add menu item to hide other applications
|
// Add menu item to hide other applications
|
||||||
itemBeingAdded =
|
itemBeingAdded = CreateNativeAppMenuItem(
|
||||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_hide_others"_ns, @selector(menuItemHit:),
|
aMenu, u"menu_mac_hide_others"_ns, @selector(menuItemHit:),
|
||||||
eCommand_ID_HideOthers, nsMenuBarX::sNativeEventTarget);
|
eCommand_ID_HideOthers, nsMenuBarX::sNativeEventTarget);
|
||||||
if (itemBeingAdded) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
[itemBeingAdded release];
|
[itemBeingAdded release];
|
||||||
|
|
@ -756,9 +790,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add menu item to show all applications
|
// Add menu item to show all applications
|
||||||
itemBeingAdded =
|
itemBeingAdded = CreateNativeAppMenuItem(
|
||||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_show_all"_ns, @selector(menuItemHit:),
|
aMenu, u"menu_mac_show_all"_ns, @selector(menuItemHit:),
|
||||||
eCommand_ID_ShowAll, nsMenuBarX::sNativeEventTarget);
|
eCommand_ID_ShowAll, nsMenuBarX::sNativeEventTarget);
|
||||||
if (itemBeingAdded) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
[itemBeingAdded release];
|
[itemBeingAdded release];
|
||||||
|
|
@ -775,9 +809,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
BOOL addTouchBarSeparator = NO;
|
BOOL addTouchBarSeparator = NO;
|
||||||
|
|
||||||
// Add Touch Bar customization menu item.
|
// Add Touch Bar customization menu item.
|
||||||
itemBeingAdded =
|
itemBeingAdded = CreateNativeAppMenuItem(
|
||||||
CreateNativeAppMenuItem(aMenu, u"menu_mac_touch_bar"_ns, @selector(menuItemHit:),
|
aMenu, u"menu_mac_touch_bar"_ns, @selector(menuItemHit:),
|
||||||
eCommand_ID_TouchBar, nsMenuBarX::sNativeEventTarget);
|
eCommand_ID_TouchBar, nsMenuBarX::sNativeEventTarget);
|
||||||
|
|
||||||
if (itemBeingAdded) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
|
|
@ -797,9 +831,9 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add quit menu item
|
// Add quit menu item
|
||||||
itemBeingAdded =
|
itemBeingAdded = CreateNativeAppMenuItem(
|
||||||
CreateNativeAppMenuItem(aMenu, u"menu_FileQuitItem"_ns, @selector(menuItemHit:),
|
aMenu, u"menu_FileQuitItem"_ns, @selector(menuItemHit:),
|
||||||
eCommand_ID_Quit, nsMenuBarX::sNativeEventTarget);
|
eCommand_ID_Quit, nsMenuBarX::sNativeEventTarget);
|
||||||
if (itemBeingAdded) {
|
if (itemBeingAdded) {
|
||||||
[sApplicationMenu addItem:itemBeingAdded];
|
[sApplicationMenu addItem:itemBeingAdded];
|
||||||
[itemBeingAdded release];
|
[itemBeingAdded release];
|
||||||
|
|
@ -807,9 +841,10 @@ void nsMenuBarX::CreateApplicationMenu(nsMenuX* aMenu) {
|
||||||
} else {
|
} else {
|
||||||
// the current application does not have a DOM node for "Quit". Add one
|
// the current application does not have a DOM node for "Quit". Add one
|
||||||
// anyway, in English.
|
// anyway, in English.
|
||||||
NSMenuItem* defaultQuitItem = [[[NSMenuItem alloc] initWithTitle:@"Quit"
|
NSMenuItem* defaultQuitItem =
|
||||||
action:@selector(menuItemHit:)
|
[[[NSMenuItem alloc] initWithTitle:@"Quit"
|
||||||
keyEquivalent:@"q"] autorelease];
|
action:@selector(menuItemHit:)
|
||||||
|
keyEquivalent:@"q"] autorelease];
|
||||||
defaultQuitItem.target = nsMenuBarX::sNativeEventTarget;
|
defaultQuitItem.target = nsMenuBarX::sNativeEventTarget;
|
||||||
defaultQuitItem.tag = eCommand_ID_Quit;
|
defaultQuitItem.tag = eCommand_ID_Quit;
|
||||||
[sApplicationMenu addItem:defaultQuitItem];
|
[sApplicationMenu addItem:defaultQuitItem];
|
||||||
|
|
@ -860,9 +895,9 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
||||||
[super performKeyEquivalent:aEvent];
|
[super performKeyEquivalent:aEvent];
|
||||||
gMenuItemsExecuteCommands = YES; // return to default
|
gMenuItemsExecuteCommands = YES; // return to default
|
||||||
|
|
||||||
// Return YES if we invoked a command and there is now no key window or we changed
|
// Return YES if we invoked a command and there is now no key window or we
|
||||||
// the first responder. In this case we do not want to propagate the event because
|
// changed the first responder. In this case we do not want to propagate the
|
||||||
// we don't want it handled again.
|
// event because we don't want it handled again.
|
||||||
if (!NSApp.keyWindow || NSApp.keyWindow.firstResponder != firstResponder) {
|
if (!NSApp.keyWindow || NSApp.keyWindow.firstResponder != firstResponder) {
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
@ -898,7 +933,8 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
||||||
|
|
||||||
nsMenuGroupOwnerX* menuGroupOwner = nullptr;
|
nsMenuGroupOwnerX* menuGroupOwner = nullptr;
|
||||||
nsMenuBarX* menuBar = nullptr;
|
nsMenuBarX* menuBar = nullptr;
|
||||||
MOZMenuItemRepresentedObject* representedObject = nativeMenuItem.representedObject;
|
MOZMenuItemRepresentedObject* representedObject =
|
||||||
|
nativeMenuItem.representedObject;
|
||||||
|
|
||||||
if (representedObject) {
|
if (representedObject) {
|
||||||
menuGroupOwner = representedObject.menuGroupOwner;
|
menuGroupOwner = representedObject.menuGroupOwner;
|
||||||
|
|
@ -914,13 +950,15 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
||||||
[(MenuDelegate*)menu.delegate menu:menu willActivateItem:nativeMenuItem];
|
[(MenuDelegate*)menu.delegate menu:menu willActivateItem:nativeMenuItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the modifier flags and button for this menu item activation. The menu system does not pass
|
// Get the modifier flags and button for this menu item activation. The menu
|
||||||
// an NSEvent to our action selector, but we can query the current NSEvent instead. The current
|
// system does not pass an NSEvent to our action selector, but we can query
|
||||||
// NSEvent can be a key event or a mouseup event, depending on how the menu item is activated.
|
// the current NSEvent instead. The current NSEvent can be a key event or a
|
||||||
NSEventModifierFlags modifierFlags = NSApp.currentEvent ? NSApp.currentEvent.modifierFlags : 0;
|
// mouseup event, depending on how the menu item is activated.
|
||||||
mozilla::MouseButton button = NSApp.currentEvent
|
NSEventModifierFlags modifierFlags =
|
||||||
? nsCocoaUtils::ButtonForEvent(NSApp.currentEvent)
|
NSApp.currentEvent ? NSApp.currentEvent.modifierFlags : 0;
|
||||||
: mozilla::MouseButton::ePrimary;
|
mozilla::MouseButton button =
|
||||||
|
NSApp.currentEvent ? nsCocoaUtils::ButtonForEvent(NSApp.currentEvent)
|
||||||
|
: mozilla::MouseButton::ePrimary;
|
||||||
|
|
||||||
// Do special processing if this is for an app-global command.
|
// Do special processing if this is for an app-global command.
|
||||||
if (tag == eCommand_ID_About) {
|
if (tag == eCommand_ID_About) {
|
||||||
|
|
@ -968,13 +1006,15 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
||||||
if (menuBar && menuBar->mQuitItemContent) {
|
if (menuBar && menuBar->mQuitItemContent) {
|
||||||
mostSpecificContent = menuBar->mQuitItemContent;
|
mostSpecificContent = menuBar->mQuitItemContent;
|
||||||
}
|
}
|
||||||
// If we have some content for quit we execute it. Otherwise we send a native app terminate
|
// If we have some content for quit we execute it. Otherwise we send a
|
||||||
// message. If you want to stop a quit from happening, provide quit content and return
|
// native app terminate message. If you want to stop a quit from happening,
|
||||||
// the event as unhandled.
|
// provide quit content and return the event as unhandled.
|
||||||
if (mostSpecificContent) {
|
if (mostSpecificContent) {
|
||||||
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags, button);
|
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent, modifierFlags,
|
||||||
|
button);
|
||||||
} else {
|
} else {
|
||||||
nsCOMPtr<nsIAppStartup> appStartup = mozilla::components::AppStartup::Service();
|
nsCOMPtr<nsIAppStartup> appStartup =
|
||||||
|
mozilla::components::AppStartup::Service();
|
||||||
if (appStartup) {
|
if (appStartup) {
|
||||||
bool userAllowedQuit = true;
|
bool userAllowedQuit = true;
|
||||||
appStartup->Quit(nsIAppStartup::eAttemptQuit, 0, &userAllowedQuit);
|
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
|
// given the commandID, look it up in our hashtable and dispatch to
|
||||||
// that menu item.
|
// that menu item.
|
||||||
if (menuGroupOwner) {
|
if (menuGroupOwner) {
|
||||||
if (RefPtr<nsMenuItemX> menuItem =
|
if (RefPtr<nsMenuItemX> menuItem = menuGroupOwner->GetMenuItemForCommandID(
|
||||||
menuGroupOwner->GetMenuItemForCommandID(static_cast<uint32_t>(tag))) {
|
static_cast<uint32_t>(tag))) {
|
||||||
if (nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest) {
|
if (nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest) {
|
||||||
menuItem->DoCommand(modifierFlags, button);
|
menuItem->DoCommand(modifierFlags, button);
|
||||||
} else if (RefPtr<nsMenuX> menu = menuItem->ParentMenu()) {
|
} 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
|
- (NSMenuItem*)addItemWithTitle:(NSString*)aString
|
||||||
action:(SEL)aSelector
|
action:(SEL)aSelector
|
||||||
keyEquivalent:(NSString*)aKeyEquiv {
|
keyEquivalent:(NSString*)aKeyEquiv {
|
||||||
NSMenuItem* newItem = [super addItemWithTitle:aString action:aSelector keyEquivalent:aKeyEquiv];
|
NSMenuItem* newItem = [super addItemWithTitle:aString
|
||||||
|
action:aSelector
|
||||||
|
keyEquivalent:aKeyEquiv];
|
||||||
[self _overrideClassOfMenuItem:newItem];
|
[self _overrideClassOfMenuItem:newItem];
|
||||||
return newItem;
|
return newItem;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,16 @@ using namespace mozilla;
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(nsMenuGroupOwnerX, nsIObserver, nsIMutationObserver)
|
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) {
|
: mContent(aElement), mMenuBar(aMenuBarIfMenuBar) {
|
||||||
mRepresentedObject = [[MOZMenuItemRepresentedObject alloc] initWithMenuGroupOwner:this];
|
mRepresentedObject =
|
||||||
|
[[MOZMenuItemRepresentedObject alloc] initWithMenuGroupOwner:this];
|
||||||
}
|
}
|
||||||
|
|
||||||
nsMenuGroupOwnerX::~nsMenuGroupOwnerX() {
|
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 setMenuGroupOwner:nullptr];
|
||||||
[mRepresentedObject release];
|
[mRepresentedObject release];
|
||||||
}
|
}
|
||||||
|
|
@ -41,11 +44,11 @@ nsMenuGroupOwnerX::~nsMenuGroupOwnerX() {
|
||||||
// nsIMutationObserver
|
// nsIMutationObserver
|
||||||
//
|
//
|
||||||
|
|
||||||
void nsMenuGroupOwnerX::CharacterDataWillChange(nsIContent* aContent,
|
void nsMenuGroupOwnerX::CharacterDataWillChange(
|
||||||
const CharacterDataChangeInfo&) {}
|
nsIContent* aContent, const CharacterDataChangeInfo&) {}
|
||||||
|
|
||||||
void nsMenuGroupOwnerX::CharacterDataChanged(nsIContent* aContent, const CharacterDataChangeInfo&) {
|
void nsMenuGroupOwnerX::CharacterDataChanged(nsIContent* aContent,
|
||||||
}
|
const CharacterDataChangeInfo&) {}
|
||||||
|
|
||||||
void nsMenuGroupOwnerX::ContentAppended(nsIContent* aFirstNewContent) {
|
void nsMenuGroupOwnerX::ContentAppended(nsIContent* aFirstNewContent) {
|
||||||
for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
|
for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
|
||||||
|
|
@ -55,10 +58,13 @@ void nsMenuGroupOwnerX::ContentAppended(nsIContent* aFirstNewContent) {
|
||||||
|
|
||||||
void nsMenuGroupOwnerX::NodeWillBeDestroyed(nsINode* aNode) {}
|
void nsMenuGroupOwnerX::NodeWillBeDestroyed(nsINode* aNode) {}
|
||||||
|
|
||||||
void nsMenuGroupOwnerX::AttributeWillChange(dom::Element* aElement, int32_t aNameSpaceID,
|
void nsMenuGroupOwnerX::AttributeWillChange(dom::Element* aElement,
|
||||||
nsAtom* aAttribute, int32_t aModType) {}
|
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,
|
nsAtom* aAttribute, int32_t aModType,
|
||||||
const nsAttrValue* aOldValue) {
|
const nsAttrValue* aOldValue) {
|
||||||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
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();
|
nsIContent* container = aChild->GetParent();
|
||||||
if (!container) {
|
if (!container) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -77,7 +84,8 @@ void nsMenuGroupOwnerX::ContentRemoved(nsIContent* aChild, nsIContent* aPrevious
|
||||||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
||||||
nsChangeObserver* obs = LookupContentChangeObserver(container);
|
nsChangeObserver* obs = LookupContentChangeObserver(container);
|
||||||
if (obs) {
|
if (obs) {
|
||||||
obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild, aPreviousSibling);
|
obs->ObserveContentRemoved(aChild->OwnerDoc(), container, aChild,
|
||||||
|
aPreviousSibling);
|
||||||
} else if (container != mContent) {
|
} else if (container != mContent) {
|
||||||
// We do a lookup on the parent container in case things were removed
|
// 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
|
// 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) {
|
if (parent) {
|
||||||
obs = LookupContentChangeObserver(parent);
|
obs = LookupContentChangeObserver(parent);
|
||||||
if (obs) {
|
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::ParentChainChanged(nsIContent* aContent) {}
|
||||||
|
|
||||||
void nsMenuGroupOwnerX::ARIAAttributeDefaultWillChange(mozilla::dom::Element* aElement,
|
void nsMenuGroupOwnerX::ARIAAttributeDefaultWillChange(
|
||||||
nsAtom* aAttribute, int32_t aModType) {}
|
mozilla::dom::Element* aElement, nsAtom* aAttribute, int32_t aModType) {}
|
||||||
|
|
||||||
void nsMenuGroupOwnerX::ARIAAttributeDefaultChanged(mozilla::dom::Element* aElement,
|
void nsMenuGroupOwnerX::ARIAAttributeDefaultChanged(
|
||||||
nsAtom* aAttribute, int32_t aModType) {}
|
mozilla::dom::Element* aElement, nsAtom* aAttribute, int32_t aModType) {}
|
||||||
|
|
||||||
// For change management, we don't use a |nsSupportsHashtable| because
|
// For change management, we don't use a |nsSupportsHashtable| because
|
||||||
// we know that the lifetime of all these items is bounded by the
|
// 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
|
// lifetime of the menubar. No need to add any more strong refs to the
|
||||||
// picture because the containment hierarchy already uses strong refs.
|
// picture because the containment hierarchy already uses strong refs.
|
||||||
void nsMenuGroupOwnerX::RegisterForContentChanges(nsIContent* aContent,
|
void nsMenuGroupOwnerX::RegisterForContentChanges(
|
||||||
nsChangeObserver* aMenuObject) {
|
nsIContent* aContent, nsChangeObserver* aMenuObject) {
|
||||||
if (!mContentToObserverTable.Contains(aContent)) {
|
if (!mContentToObserverTable.Contains(aContent)) {
|
||||||
aContent->AddMutationObserver(this);
|
aContent->AddMutationObserver(this);
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +167,8 @@ void nsMenuGroupOwnerX::UnregisterForLocaleChanges() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
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")) {
|
if (mMenuBar && !strcmp(aTopic, "intl:app-locales-changed")) {
|
||||||
// Rebuild the menu with the new locale strings.
|
// Rebuild the menu with the new locale strings.
|
||||||
mMenuBar->SetNeedsRebuild();
|
mMenuBar->SetNeedsRebuild();
|
||||||
|
|
@ -166,7 +176,8 @@ nsMenuGroupOwnerX::Observe(nsISupports* aSubject, const char* aTopic, const char
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsChangeObserver* nsMenuGroupOwnerX::LookupContentChangeObserver(nsIContent* aContent) {
|
nsChangeObserver* nsMenuGroupOwnerX::LookupContentChangeObserver(
|
||||||
|
nsIContent* aContent) {
|
||||||
nsChangeObserver* result;
|
nsChangeObserver* result;
|
||||||
if (mContentToObserverTable.Get(aContent, &result)) {
|
if (mContentToObserverTable.Get(aContent, &result)) {
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -206,7 +217,8 @@ nsMenuItemX* nsMenuGroupOwnerX::GetMenuItemForCommandID(uint32_t aCommandID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation MOZMenuItemRepresentedObject {
|
@implementation MOZMenuItemRepresentedObject {
|
||||||
nsMenuGroupOwnerX* mMenuGroupOwner; // weak, cleared by nsMenuGroupOwnerX's destructor
|
nsMenuGroupOwnerX*
|
||||||
|
mMenuGroupOwner; // weak, cleared by nsMenuGroupOwnerX's destructor
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithMenuGroupOwner:(nsMenuGroupOwnerX*)aMenuGroupOwner {
|
- (id)initWithMenuGroupOwner:(nsMenuGroupOwnerX*)aMenuGroupOwner {
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ void nsMenuItemIconX::SetupIcon(nsIContent* aContent) {
|
||||||
|
|
||||||
bool shouldHaveIcon = StartIconLoad(aContent);
|
bool shouldHaveIcon = StartIconLoad(aContent);
|
||||||
if (!shouldHaveIcon) {
|
if (!shouldHaveIcon) {
|
||||||
// There is no icon for this menu item, as an error occurred while loading it.
|
// There is no icon for this menu item, as an error occurred while loading
|
||||||
// An icon might have been set earlier or the place holder icon may have
|
// it. An icon might have been set earlier or the place holder icon may have
|
||||||
// been set. Clear it.
|
// been set. Clear it.
|
||||||
if (mIconImage) {
|
if (mIconImage) {
|
||||||
[mIconImage release];
|
[mIconImage release];
|
||||||
|
|
@ -73,8 +73,9 @@ void nsMenuItemIconX::SetupIcon(nsIContent* aContent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mIconImage) {
|
if (!mIconImage) {
|
||||||
// Set a placeholder icon, so that the menuitem reserves space for the icon during the load and
|
// Set a placeholder icon, so that the menuitem reserves space for the icon
|
||||||
// there is no sudden shift once the icon finishes loading.
|
// during the load and there is no sudden shift once the icon finishes
|
||||||
|
// loading.
|
||||||
NSSize iconSize = NSMakeSize(kIconSize, kIconSize);
|
NSSize iconSize = NSMakeSize(kIconSize, kIconSize);
|
||||||
mIconImage = [[MOZIconHelper placeholderIconWithSize:iconSize] retain];
|
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.
|
// First, look at the content node's "image" attribute.
|
||||||
nsAutoString imageURIString;
|
nsAutoString imageURIString;
|
||||||
bool hasImageAttr =
|
bool hasImageAttr =
|
||||||
aContent->IsElement() && aContent->AsElement()->GetAttr(nsGkAtoms::image, imageURIString);
|
aContent->IsElement() &&
|
||||||
|
aContent->AsElement()->GetAttr(nsGkAtoms::image, imageURIString);
|
||||||
|
|
||||||
if (hasImageAttr) {
|
if (hasImageAttr) {
|
||||||
// Use the URL from the image attribute.
|
// Use the URL from the image attribute.
|
||||||
|
|
@ -121,7 +123,8 @@ already_AddRefed<nsIURI> nsMenuItemIconX::GetIconURI(nsIContent* aContent) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<const ComputedStyle> sc = nsComputedDOMStyle::GetComputedStyle(aContent->AsElement());
|
RefPtr<const ComputedStyle> sc =
|
||||||
|
nsComputedDOMStyle::GetComputedStyle(aContent->AsElement());
|
||||||
if (!sc) {
|
if (!sc) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -149,11 +152,12 @@ nsresult nsMenuItemIconX::OnComplete(imgIContainer* aImage) {
|
||||||
mIconImage = nil;
|
mIconImage = nil;
|
||||||
}
|
}
|
||||||
RefPtr<nsPresContext> pc = mPresContext.get();
|
RefPtr<nsPresContext> pc = mPresContext.get();
|
||||||
mIconImage = [[MOZIconHelper iconImageFromImageContainer:aImage
|
mIconImage = [[MOZIconHelper
|
||||||
withSize:NSMakeSize(kIconSize, kIconSize)
|
iconImageFromImageContainer:aImage
|
||||||
presContext:pc
|
withSize:NSMakeSize(kIconSize, kIconSize)
|
||||||
computedStyle:mComputedStyle
|
presContext:pc
|
||||||
scaleFactor:0.0f] retain];
|
computedStyle:mComputedStyle
|
||||||
|
scaleFactor:0.0f] retain];
|
||||||
mComputedStyle = nullptr;
|
mComputedStyle = nullptr;
|
||||||
mPresContext = nullptr;
|
mPresContext = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,19 @@ using namespace mozilla;
|
||||||
using mozilla::dom::CallerType;
|
using mozilla::dom::CallerType;
|
||||||
using mozilla::dom::Event;
|
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)
|
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;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||||
|
|
||||||
MOZ_COUNT_CTOR(nsMenuItemX);
|
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!");
|
NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one!");
|
||||||
|
|
||||||
mMenuGroupOwner->RegisterForContentChanges(mContent, this);
|
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
|
// decide enabled state based on command content if it exists, otherwise do it
|
||||||
// on our own content
|
// based on our own content
|
||||||
bool isEnabled;
|
bool isEnabled;
|
||||||
if (mCommandElement) {
|
if (mCommandElement) {
|
||||||
isEnabled = !mCommandElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
isEnabled = !mCommandElement->AttrValueIs(
|
||||||
nsGkAtoms::_true, eCaseMatters);
|
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
|
||||||
} else {
|
} else {
|
||||||
isEnabled = !mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
isEnabled = !mContent->AsElement()->AttrValueIs(
|
||||||
nsGkAtoms::_true, eCaseMatters);
|
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up the native menu item
|
// set up the native menu item
|
||||||
if (mType == eSeparatorMenuItemType) {
|
if (mType == eSeparatorMenuItemType) {
|
||||||
mNativeMenuItem = [[NSMenuItem separatorItem] retain];
|
mNativeMenuItem = [[NSMenuItem separatorItem] retain];
|
||||||
} else {
|
} else {
|
||||||
NSString* newCocoaLabelString = nsMenuUtilsX::GetTruncatedCocoaLabel(aLabel);
|
NSString* newCocoaLabelString =
|
||||||
|
nsMenuUtilsX::GetTruncatedCocoaLabel(aLabel);
|
||||||
mNativeMenuItem = [[NSMenuItem alloc] initWithTitle:newCocoaLabelString
|
mNativeMenuItem = [[NSMenuItem alloc] initWithTitle:newCocoaLabelString
|
||||||
action:nil
|
action:nil
|
||||||
keyEquivalent:@""];
|
keyEquivalent:@""];
|
||||||
|
|
||||||
mIsChecked = mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
|
mIsChecked = mContent->AsElement()->AttrValueIs(
|
||||||
nsGkAtoms::_true, eCaseMatters);
|
kNameSpaceID_None, nsGkAtoms::checked, nsGkAtoms::_true, eCaseMatters);
|
||||||
|
|
||||||
mNativeMenuItem.enabled = isEnabled;
|
mNativeMenuItem.enabled = isEnabled;
|
||||||
mNativeMenuItem.state = mIsChecked ? NSOnState : NSOffState;
|
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
|
// update the content model. This will also handle unchecking our siblings
|
||||||
// if we are a radiomenu
|
// if we are a radiomenu
|
||||||
if (mIsChecked) {
|
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 {
|
} else {
|
||||||
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked, true);
|
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update native menu item
|
// update native menu item
|
||||||
|
|
@ -158,10 +166,13 @@ EMenuItemType nsMenuItemX::GetMenuItemType() { return mType; }
|
||||||
|
|
||||||
// Executes the "cached" javaScript command.
|
// Executes the "cached" javaScript command.
|
||||||
// Returns NS_OK if the command was executed properly, otherwise an error code.
|
// 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
|
// flip "checked" state if we're a checkbox menu, or an un-checked radio menu
|
||||||
if (mType == eCheckboxMenuItemType || (mType == eRadioMenuItemType && !mIsChecked)) {
|
if (mType == eCheckboxMenuItemType ||
|
||||||
if (!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocheck,
|
(mType == eRadioMenuItemType && !mIsChecked)) {
|
||||||
|
if (!mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
|
||||||
|
nsGkAtoms::autocheck,
|
||||||
nsGkAtoms::_false, eCaseMatters)) {
|
nsGkAtoms::_false, eCaseMatters)) {
|
||||||
SetChecked(!mIsChecked);
|
SetChecked(!mIsChecked);
|
||||||
}
|
}
|
||||||
|
|
@ -171,7 +182,8 @@ void nsMenuItemX::DoCommand(NSEventModifierFlags aModifierFlags, int16_t aButton
|
||||||
nsMenuUtilsX::DispatchCommandTo(mContent, aModifierFlags, aButton);
|
nsMenuUtilsX::DispatchCommandTo(mContent, aModifierFlags, aButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventDefaultCalled) {
|
nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName,
|
||||||
|
bool* preventDefaultCalled) {
|
||||||
if (!mContent) {
|
if (!mContent) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +193,8 @@ nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventD
|
||||||
|
|
||||||
// create DOM event
|
// create DOM event
|
||||||
ErrorResult rv;
|
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()) {
|
if (rv.Failed()) {
|
||||||
NS_WARNING("Failed to create Event");
|
NS_WARNING("Failed to create Event");
|
||||||
return rv.StealNSResult();
|
return rv.StealNSResult();
|
||||||
|
|
@ -192,7 +205,8 @@ nsresult nsMenuItemX::DispatchDOMEvent(const nsString& eventName, bool* preventD
|
||||||
event->SetTrusted(true);
|
event->SetTrusted(true);
|
||||||
|
|
||||||
// send DOM event
|
// send DOM event
|
||||||
*preventDefaultCalled = mContent->DispatchEvent(*event, CallerType::System, rv);
|
*preventDefaultCalled =
|
||||||
|
mContent->DispatchEvent(*event, CallerType::System, rv);
|
||||||
if (rv.Failed()) {
|
if (rv.Failed()) {
|
||||||
NS_WARNING("Failed to send DOM event via EventTarget");
|
NS_WARNING("Failed to send DOM event via EventTarget");
|
||||||
return rv.StealNSResult();
|
return rv.StealNSResult();
|
||||||
|
|
@ -220,9 +234,10 @@ void nsMenuItemX::UncheckRadioSiblings(nsIContent* aCheckedContent) {
|
||||||
sibling = sibling->GetNextSibling()) {
|
sibling = sibling->GetNextSibling()) {
|
||||||
if (sibling != aCheckedContent && sibling->IsElement()) { // skip this node
|
if (sibling != aCheckedContent && sibling->IsElement()) { // skip this node
|
||||||
// if the current sibling is in the same group, clear it
|
// if the current sibling is in the same group, clear it
|
||||||
if (sibling->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, myGroupName,
|
if (sibling->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
||||||
eCaseMatters)) {
|
myGroupName, eCaseMatters)) {
|
||||||
sibling->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, u"false"_ns, true);
|
sibling->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::checked,
|
||||||
|
u"false"_ns, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -236,7 +251,8 @@ void nsMenuItemX::SetKeyEquiv() {
|
||||||
mContent->AsElement()->GetAttr(nsGkAtoms::key, keyValue);
|
mContent->AsElement()->GetAttr(nsGkAtoms::key, keyValue);
|
||||||
|
|
||||||
if (!keyValue.IsEmpty() && mContent->GetUncomposedDoc()) {
|
if (!keyValue.IsEmpty() && mContent->GetUncomposedDoc()) {
|
||||||
dom::Element* keyContent = mContent->GetUncomposedDoc()->GetElementById(keyValue);
|
dom::Element* keyContent =
|
||||||
|
mContent->GetUncomposedDoc()->GetElementById(keyValue);
|
||||||
if (keyContent) {
|
if (keyContent) {
|
||||||
nsAutoString keyChar;
|
nsAutoString keyChar;
|
||||||
bool hasKey = keyContent->GetAttr(nsGkAtoms::key, keyChar);
|
bool hasKey = keyContent->GetAttr(nsGkAtoms::key, keyChar);
|
||||||
|
|
@ -244,7 +260,8 @@ void nsMenuItemX::SetKeyEquiv() {
|
||||||
if (!hasKey || keyChar.IsEmpty()) {
|
if (!hasKey || keyChar.IsEmpty()) {
|
||||||
nsAutoString keyCodeName;
|
nsAutoString keyCodeName;
|
||||||
keyContent->GetAttr(nsGkAtoms::keycode, keyCodeName);
|
keyContent->GetAttr(nsGkAtoms::keycode, keyCodeName);
|
||||||
uint32_t charCode = nsCocoaUtils::ConvertGeckoNameToMacCharCode(keyCodeName);
|
uint32_t charCode =
|
||||||
|
nsCocoaUtils::ConvertGeckoNameToMacCharCode(keyCodeName);
|
||||||
if (charCode) {
|
if (charCode) {
|
||||||
keyChar.Assign(charCode);
|
keyChar.Assign(charCode);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -254,13 +271,16 @@ void nsMenuItemX::SetKeyEquiv() {
|
||||||
|
|
||||||
nsAutoString modifiersStr;
|
nsAutoString modifiersStr;
|
||||||
keyContent->GetAttr(nsGkAtoms::modifiers, 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;
|
mNativeMenuItem.keyEquivalentModifierMask = macModifiers;
|
||||||
|
|
||||||
NSString* keyEquivalent = [[NSString stringWithCharacters:(unichar*)keyChar.get()
|
NSString* keyEquivalent =
|
||||||
length:keyChar.Length()] lowercaseString];
|
[[NSString stringWithCharacters:(unichar*)keyChar.get()
|
||||||
|
length:keyChar.Length()] lowercaseString];
|
||||||
if ([keyEquivalent isEqualToString:@" "]) {
|
if ([keyEquivalent isEqualToString:@" "]) {
|
||||||
mNativeMenuItem.keyEquivalent = @"";
|
mNativeMenuItem.keyEquivalent = @"";
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -279,7 +299,8 @@ void nsMenuItemX::SetKeyEquiv() {
|
||||||
|
|
||||||
void nsMenuItemX::Dump(uint32_t aIndent) const {
|
void nsMenuItemX::Dump(uint32_t aIndent) const {
|
||||||
printf("%*s - item [%p] %-16s <%s>\n", aIndent * 2, "", this,
|
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());
|
NS_ConvertUTF16toUTF8(mContent->NodeName()).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,7 +308,8 @@ void nsMenuItemX::Dump(uint32_t aIndent) const {
|
||||||
// nsChangeObserver
|
// nsChangeObserver
|
||||||
//
|
//
|
||||||
|
|
||||||
void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aContent,
|
void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument,
|
||||||
|
nsIContent* aContent,
|
||||||
nsAtom* aAttribute) {
|
nsAtom* aAttribute) {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
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
|
// 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.
|
// do any of this if we're just a normal check menu.
|
||||||
if (mType == eRadioMenuItemType &&
|
if (mType == eRadioMenuItemType &&
|
||||||
mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
|
mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
|
||||||
|
nsGkAtoms::checked,
|
||||||
nsGkAtoms::_true, eCaseMatters)) {
|
nsGkAtoms::_true, eCaseMatters)) {
|
||||||
UncheckRadioSiblings(mContent);
|
UncheckRadioSiblings(mContent);
|
||||||
}
|
}
|
||||||
mMenuParent->SetRebuild(true);
|
mMenuParent->SetRebuild(true);
|
||||||
} else if (aAttribute == nsGkAtoms::hidden || aAttribute == nsGkAtoms::collapsed) {
|
} else if (aAttribute == nsGkAtoms::hidden ||
|
||||||
|
aAttribute == nsGkAtoms::collapsed) {
|
||||||
bool isVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent);
|
bool isVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent);
|
||||||
if (isVisible != mIsVisible) {
|
if (isVisible != mIsVisible) {
|
||||||
mIsVisible = isVisible;
|
mIsVisible = isVisible;
|
||||||
RefPtr<nsMenuItemX> self = this;
|
RefPtr<nsMenuItemX> self = this;
|
||||||
mMenuParent->MenuChildChangedVisibility(nsMenuParentX::MenuChild(self), isVisible);
|
mMenuParent->MenuChildChangedVisibility(nsMenuParentX::MenuChild(self),
|
||||||
|
isVisible);
|
||||||
if (mIsVisible) {
|
if (mIsVisible) {
|
||||||
SetupIcon();
|
SetupIcon();
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +353,8 @@ void nsMenuItemX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent*
|
||||||
SetupIcon();
|
SetupIcon();
|
||||||
} else if (aAttribute == nsGkAtoms::disabled) {
|
} else if (aAttribute == nsGkAtoms::disabled) {
|
||||||
mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs(
|
mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs(
|
||||||
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters);
|
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
|
||||||
|
eCaseMatters);
|
||||||
}
|
}
|
||||||
} else if (aContent == mCommandElement) {
|
} else if (aContent == mCommandElement) {
|
||||||
// the only thing that really matters when the menu isn't showing is the
|
// 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)) {
|
if (!commandDisabled.Equals(menuDisabled)) {
|
||||||
// The menu's disabled state needs to be updated to match the command.
|
// The menu's disabled state needs to be updated to match the command.
|
||||||
if (commandDisabled.IsEmpty()) {
|
if (commandDisabled.IsEmpty()) {
|
||||||
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
|
mContent->AsElement()->UnsetAttr(kNameSpaceID_None,
|
||||||
|
nsGkAtoms::disabled, true);
|
||||||
} else {
|
} else {
|
||||||
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandDisabled,
|
mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||||
true);
|
commandDisabled, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// now we sync our native menu item with the command DOM node
|
// now we sync our native menu item with the command DOM node
|
||||||
mNativeMenuItem.enabled = !aContent->AsElement()->AttrValueIs(
|
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);
|
nsGkAtoms::menuseparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsMenuItemX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aContainer,
|
void nsMenuItemX::ObserveContentRemoved(dom::Document* aDocument,
|
||||||
nsIContent* aChild, nsIContent* aPreviousSibling) {
|
nsIContent* aContainer,
|
||||||
|
nsIContent* aChild,
|
||||||
|
nsIContent* aPreviousSibling) {
|
||||||
MOZ_RELEASE_ASSERT(mMenuGroupOwner);
|
MOZ_RELEASE_ASSERT(mMenuGroupOwner);
|
||||||
MOZ_RELEASE_ASSERT(mMenuParent);
|
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) {
|
nsIContent* aChild) {
|
||||||
MOZ_RELEASE_ASSERT(mMenuParent);
|
MOZ_RELEASE_ASSERT(mMenuParent);
|
||||||
|
|
||||||
|
|
@ -390,7 +421,8 @@ void nsMenuItemX::ObserveContentInserted(dom::Document* aDocument, nsIContent* a
|
||||||
|
|
||||||
void nsMenuItemX::SetupIcon() {
|
void nsMenuItemX::SetupIcon() {
|
||||||
if (mType != eRegularMenuItemType) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -398,4 +430,6 @@ void nsMenuItemX::SetupIcon() {
|
||||||
mNativeMenuItem.image = mIcon->GetIconImage();
|
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;
|
bool nsMenuUtilsX::gIsSynchronouslyActivatingNativeMenuItemDuringTest = false;
|
||||||
|
|
||||||
void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
|
void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
|
||||||
NSEventModifierFlags aModifierFlags, int16_t aButton) {
|
NSEventModifierFlags aModifierFlags,
|
||||||
|
int16_t aButton) {
|
||||||
MOZ_ASSERT(aTargetContent, "null ptr");
|
MOZ_ASSERT(aTargetContent, "null ptr");
|
||||||
|
|
||||||
dom::Document* doc = aTargetContent->OwnerDoc();
|
dom::Document* doc = aTargetContent->OwnerDoc();
|
||||||
|
|
@ -43,8 +44,9 @@ void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
|
||||||
|
|
||||||
IgnoredErrorResult rv;
|
IgnoredErrorResult rv;
|
||||||
event->InitCommandEvent(u"command"_ns, true, true,
|
event->InitCommandEvent(u"command"_ns, true, true,
|
||||||
nsGlobalWindowInner::Cast(doc->GetInnerWindow()), 0, ctrlKey, altKey,
|
nsGlobalWindowInner::Cast(doc->GetInnerWindow()), 0,
|
||||||
shiftKey, cmdKey, aButton, nullptr, 0, rv);
|
ctrlKey, altKey, shiftKey, cmdKey, aButton, nullptr,
|
||||||
|
0, rv);
|
||||||
if (!rv.Failed()) {
|
if (!rv.Failed()) {
|
||||||
event->SetTrusted(true);
|
event->SetTrusted(true);
|
||||||
aTargetContent->DispatchEvent(*event);
|
aTargetContent->DispatchEvent(*event);
|
||||||
|
|
@ -55,17 +57,19 @@ void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent,
|
||||||
NSString* nsMenuUtilsX::GetTruncatedCocoaLabel(const nsString& itemLabel) {
|
NSString* nsMenuUtilsX::GetTruncatedCocoaLabel(const nsString& itemLabel) {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||||
|
|
||||||
// We want to truncate long strings to some reasonable pixel length but there is no
|
// We want to truncate long strings to some reasonable pixel length but there
|
||||||
// good API for doing that which works for all OS versions and architectures. For now
|
// is no good API for doing that which works for all OS versions and
|
||||||
// we'll do nothing for consistency and depend on good user interface design to limit
|
// architectures. For now we'll do nothing for consistency and depend on good
|
||||||
// string lengths.
|
// user interface design to limit string lengths.
|
||||||
return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(itemLabel.get())
|
return [NSString
|
||||||
length:itemLabel.Length()];
|
stringWithCharacters:reinterpret_cast<const unichar*>(itemLabel.get())
|
||||||
|
length:itemLabel.Length()];
|
||||||
|
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(const nsString& modifiersAttribute) {
|
uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(
|
||||||
|
const nsString& modifiersAttribute) {
|
||||||
uint8_t modifiers = knsMenuItemNoModifier;
|
uint8_t modifiers = knsMenuItemNoModifier;
|
||||||
char* str = ToNewCString(modifiersAttribute);
|
char* str = ToNewCString(modifiersAttribute);
|
||||||
char* newStr;
|
char* newStr;
|
||||||
|
|
@ -87,7 +91,8 @@ uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(const nsString& modifiersAt
|
||||||
return modifiers;
|
return modifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(uint8_t geckoModifiers) {
|
unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(
|
||||||
|
uint8_t geckoModifiers) {
|
||||||
unsigned int macModifiers = 0;
|
unsigned int macModifiers = 0;
|
||||||
|
|
||||||
if (geckoModifiers & knsMenuItemShiftModifier) {
|
if (geckoModifiers & knsMenuItemShiftModifier) {
|
||||||
|
|
@ -109,7 +114,8 @@ unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(uint8_t geckoModifiers)
|
||||||
nsMenuBarX* nsMenuUtilsX::GetHiddenWindowMenuBar() {
|
nsMenuBarX* nsMenuUtilsX::GetHiddenWindowMenuBar() {
|
||||||
nsIWidget* hiddenWindowWidgetNoCOMPtr = nsCocoaUtils::GetHiddenWindowWidget();
|
nsIWidget* hiddenWindowWidgetNoCOMPtr = nsCocoaUtils::GetHiddenWindowWidget();
|
||||||
if (hiddenWindowWidgetNoCOMPtr) {
|
if (hiddenWindowWidgetNoCOMPtr) {
|
||||||
return static_cast<nsCocoaWindow*>(hiddenWindowWidgetNoCOMPtr)->GetMenuBar();
|
return static_cast<nsCocoaWindow*>(hiddenWindowWidgetNoCOMPtr)
|
||||||
|
->GetMenuBar();
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -123,9 +129,9 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
|
||||||
// app-modal dialogs and Gecko-modal dialogs that open above them. So what
|
// 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
|
// we return here isn't always released before it needs to be added to
|
||||||
// another menu. See bmo bug 468393.
|
// another menu. See bmo bug 468393.
|
||||||
NSMenuItem* standardEditMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Edit"
|
NSMenuItem* standardEditMenuItem =
|
||||||
action:nil
|
[[[NSMenuItem alloc] initWithTitle:@"Edit" action:nil
|
||||||
keyEquivalent:@""] autorelease];
|
keyEquivalent:@""] autorelease];
|
||||||
NSMenu* standardEditMenu = [[NSMenu alloc] initWithTitle:@"Edit"];
|
NSMenu* standardEditMenu = [[NSMenu alloc] initWithTitle:@"Edit"];
|
||||||
standardEditMenuItem.submenu = standardEditMenu;
|
standardEditMenuItem.submenu = standardEditMenu;
|
||||||
[standardEditMenu release];
|
[standardEditMenu release];
|
||||||
|
|
@ -176,9 +182,10 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
|
||||||
[deleteItem release];
|
[deleteItem release];
|
||||||
|
|
||||||
// Add Select All
|
// Add Select All
|
||||||
NSMenuItem* selectAllItem = [[NSMenuItem alloc] initWithTitle:@"Select All"
|
NSMenuItem* selectAllItem =
|
||||||
action:@selector(selectAll:)
|
[[NSMenuItem alloc] initWithTitle:@"Select All"
|
||||||
keyEquivalent:@"a"];
|
action:@selector(selectAll:)
|
||||||
|
keyEquivalent:@"a"];
|
||||||
[standardEditMenu addItem:selectAllItem];
|
[standardEditMenu addItem:selectAllItem];
|
||||||
[selectAllItem release];
|
[selectAllItem release];
|
||||||
|
|
||||||
|
|
@ -188,16 +195,19 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsMenuUtilsX::NodeIsHiddenOrCollapsed(nsIContent* aContent) {
|
bool nsMenuUtilsX::NodeIsHiddenOrCollapsed(nsIContent* aContent) {
|
||||||
return aContent->IsElement() &&
|
return aContent->IsElement() && (aContent->AsElement()->AttrValueIs(
|
||||||
(aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden, nsGkAtoms::_true,
|
kNameSpaceID_None, nsGkAtoms::hidden,
|
||||||
eCaseMatters) ||
|
nsGkAtoms::_true, eCaseMatters) ||
|
||||||
aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed,
|
aContent->AsElement()->AttrValueIs(
|
||||||
nsGkAtoms::_true, eCaseMatters));
|
kNameSpaceID_None, nsGkAtoms::collapsed,
|
||||||
|
nsGkAtoms::_true, eCaseMatters));
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString* aLocationString,
|
NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu,
|
||||||
|
NSString* aLocationString,
|
||||||
bool aIsMenuBar) {
|
bool aIsMenuBar) {
|
||||||
NSArray<NSString*>* indexes = [aLocationString componentsSeparatedByString:@"|"];
|
NSArray<NSString*>* indexes =
|
||||||
|
[aLocationString componentsSeparatedByString:@"|"];
|
||||||
unsigned int pathLength = indexes.count;
|
unsigned int pathLength = indexes.count;
|
||||||
if (pathLength == 0) {
|
if (pathLength == 0) {
|
||||||
return nil;
|
return nil;
|
||||||
|
|
@ -207,7 +217,8 @@ NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString
|
||||||
for (unsigned int depth = 0; depth < pathLength; depth++) {
|
for (unsigned int depth = 0; depth < pathLength; depth++) {
|
||||||
NSInteger targetIndex = [indexes objectAtIndex:depth].integerValue;
|
NSInteger targetIndex = [indexes objectAtIndex:depth].integerValue;
|
||||||
if (aIsMenuBar && depth == 0) {
|
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++;
|
targetIndex++;
|
||||||
}
|
}
|
||||||
int itemCount = currentSubmenu.numberOfItems;
|
int itemCount = currentSubmenu.numberOfItems;
|
||||||
|
|
@ -230,20 +241,24 @@ NSMenuItem* nsMenuUtilsX::NativeMenuItemWithLocation(NSMenu* aRootMenu, NSString
|
||||||
return nil;
|
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,
|
static void CheckNativeMenuItemConsistencyImpl(
|
||||||
std::unordered_set<void*>& aSeenObjects) {
|
NSMenuItem* aMenuItem, std::unordered_set<void*>& aSeenObjects) {
|
||||||
bool inserted = aSeenObjects.insert(aMenuItem).second;
|
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) {
|
if (aMenuItem.hasSubmenu) {
|
||||||
CheckNativeMenuConsistencyImpl(aMenuItem.submenu, aSeenObjects);
|
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;
|
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) {
|
for (NSMenuItem* item in aMenu.itemArray) {
|
||||||
CheckNativeMenuItemConsistencyImpl(item, aSeenObjects);
|
CheckNativeMenuItemConsistencyImpl(item, aSeenObjects);
|
||||||
}
|
}
|
||||||
|
|
@ -278,16 +293,20 @@ static void DumpNativeNSMenuItemImpl(NSMenuItem* aItem, uint32_t aIndent,
|
||||||
if (aIndexInParentMenu) {
|
if (aIndexInParentMenu) {
|
||||||
printf("[%d] ", *aIndexInParentMenu);
|
printf("[%d] ", *aIndexInParentMenu);
|
||||||
}
|
}
|
||||||
printf("NSMenuItem [%p] %-16s%s\n", aItem,
|
printf(
|
||||||
aItem.isSeparatorItem ? "----"
|
"NSMenuItem [%p] %-16s%s\n", aItem,
|
||||||
: (aItem.title.length == 0 ? "(no title)" : aItem.title.UTF8String),
|
aItem.isSeparatorItem
|
||||||
aItem.hasSubmenu ? " [hasSubmenu]" : "");
|
? "----"
|
||||||
|
: (aItem.title.length == 0 ? "(no title)" : aItem.title.UTF8String),
|
||||||
|
aItem.hasSubmenu ? " [hasSubmenu]" : "");
|
||||||
if (aItem.hasSubmenu) {
|
if (aItem.hasSubmenu) {
|
||||||
DumpNativeNSMenuImpl(aItem.submenu, aIndent + 1);
|
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) {
|
void nsMenuUtilsX::DumpNativeMenuItem(NSMenuItem* aMenuItem) {
|
||||||
DumpNativeNSMenuItemImpl(aMenuItem, 0, Nothing());
|
DumpNativeNSMenuItemImpl(aMenuItem, 0, Nothing());
|
||||||
|
|
|
||||||
|
|
@ -57,20 +57,25 @@ static void SwizzleDynamicIndexingMethods() {
|
||||||
nsToolkit::SwizzleMethods([NSMenu class], @selector(_addItem:toTable:),
|
nsToolkit::SwizzleMethods([NSMenu class], @selector(_addItem:toTable:),
|
||||||
@selector(nsMenuX_NSMenu_addItem:toTable:), true);
|
@selector(nsMenuX_NSMenu_addItem:toTable:), true);
|
||||||
nsToolkit::SwizzleMethods([NSMenu class], @selector(_removeItem:fromTable:),
|
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
|
// On SnowLeopard the Shortcut framework (which contains the
|
||||||
// SCTGRLIndex class) is loaded on demand, whenever the user first opens
|
// 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
|
// a menu (which normally hasn't happened yet). So we need to load it
|
||||||
// here explicitly.
|
// here explicitly.
|
||||||
dlopen("/System/Library/PrivateFrameworks/Shortcut.framework/Shortcut", RTLD_LAZY);
|
dlopen("/System/Library/PrivateFrameworks/Shortcut.framework/Shortcut",
|
||||||
|
RTLD_LAZY);
|
||||||
Class SCTGRLIndexClass = ::NSClassFromString(@"SCTGRLIndex");
|
Class SCTGRLIndexClass = ::NSClassFromString(@"SCTGRLIndex");
|
||||||
nsToolkit::SwizzleMethods(SCTGRLIndexClass, @selector(indexMenuBarDynamically),
|
nsToolkit::SwizzleMethods(
|
||||||
@selector(nsMenuX_SCTGRLIndex_indexMenuBarDynamically));
|
SCTGRLIndexClass, @selector(indexMenuBarDynamically),
|
||||||
|
@selector(nsMenuX_SCTGRLIndex_indexMenuBarDynamically));
|
||||||
|
|
||||||
Class NSServicesMenuUpdaterClass = ::NSClassFromString(@"_NSServicesMenuUpdater");
|
Class NSServicesMenuUpdaterClass =
|
||||||
nsToolkit::SwizzleMethods(NSServicesMenuUpdaterClass,
|
::NSClassFromString(@"_NSServicesMenuUpdater");
|
||||||
@selector(populateMenu:withServiceEntries:forDisplay:),
|
nsToolkit::SwizzleMethods(
|
||||||
@selector(nsMenuX_populateMenu:withServiceEntries:forDisplay:));
|
NSServicesMenuUpdaterClass,
|
||||||
|
@selector(populateMenu:withServiceEntries:forDisplay:),
|
||||||
|
@selector(nsMenuX_populateMenu:withServiceEntries:forDisplay:));
|
||||||
|
|
||||||
gMenuMethodsSwizzled = true;
|
gMenuMethodsSwizzled = true;
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +84,8 @@ static void SwizzleDynamicIndexingMethods() {
|
||||||
// nsMenuX
|
// nsMenuX
|
||||||
//
|
//
|
||||||
|
|
||||||
nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsIContent* aContent)
|
nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner,
|
||||||
|
nsIContent* aContent)
|
||||||
: mContent(aContent), mParent(aParent), mMenuGroupOwner(aMenuGroupOwner) {
|
: mContent(aContent), mParent(aParent), mMenuGroupOwner(aMenuGroupOwner) {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||||
|
|
||||||
|
|
@ -98,7 +104,8 @@ nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsI
|
||||||
}
|
}
|
||||||
mNativeMenu = CreateMenuWithGeckoString(mLabel);
|
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");
|
NS_ASSERTION(mMenuGroupOwner, "No menu owner given, must have one");
|
||||||
mMenuGroupOwner->RegisterForContentChanges(mContent, this);
|
mMenuGroupOwner->RegisterForContentChanges(mContent, this);
|
||||||
|
|
||||||
|
|
@ -111,8 +118,9 @@ nsMenuX::nsMenuX(nsMenuParentX* aParent, nsMenuGroupOwnerX* aMenuGroupOwner, nsI
|
||||||
mNativeMenuItem.submenu = mNativeMenu;
|
mNativeMenuItem.submenu = mNativeMenu;
|
||||||
|
|
||||||
SetEnabled(!mContent->IsElement() ||
|
SetEnabled(!mContent->IsElement() ||
|
||||||
!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
!mContent->AsElement()->AttrValueIs(
|
||||||
nsGkAtoms::_true, eCaseMatters));
|
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
|
||||||
|
eCaseMatters));
|
||||||
|
|
||||||
// We call RebuildMenu here because keyboard commands are dependent upon
|
// We call RebuildMenu here because keyboard commands are dependent upon
|
||||||
// native menu items being created. If we only call RebuildMenu when a menu
|
// native menu items being created. If we only call RebuildMenu when a menu
|
||||||
|
|
@ -168,8 +176,9 @@ nsMenuX::~nsMenuX() {
|
||||||
void nsMenuX::DetachFromGroupOwnerRecursive() {
|
void nsMenuX::DetachFromGroupOwnerRecursive() {
|
||||||
if (!mMenuGroupOwner) {
|
if (!mMenuGroupOwner) {
|
||||||
// Don't recurse if this subtree is already detached.
|
// Don't recurse if this subtree is already detached.
|
||||||
// This avoids repeated recursion during the destruction of nested nsMenuX structures.
|
// This avoids repeated recursion during the destruction of nested nsMenuX
|
||||||
// Our invariant is: If we are detached, all of our contents are also detached.
|
// structures. Our invariant is: If we are detached, all of our contents are
|
||||||
|
// also detached.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,8 +189,13 @@ void nsMenuX::DetachFromGroupOwnerRecursive() {
|
||||||
|
|
||||||
// Also detach all our children.
|
// Also detach all our children.
|
||||||
for (auto& child : mMenuChildren) {
|
for (auto& child : mMenuChildren) {
|
||||||
child.match([](const RefPtr<nsMenuX>& aMenu) { aMenu->DetachFromGroupOwnerRecursive(); },
|
child.match(
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { aMenuItem->DetachFromGroupOwner(); });
|
[](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);
|
RefPtr<nsMenuX> kungFuDeathGrip(this);
|
||||||
if (mObserver) {
|
if (mObserver) {
|
||||||
mObserver->OnMenuWillActivateItem(aPopupElement, aMenuItemElement);
|
mObserver->OnMenuWillActivateItem(aPopupElement, aMenuItemElement);
|
||||||
|
|
@ -219,12 +234,16 @@ void nsMenuX::AddMenuChild(MenuChild&& aChild) {
|
||||||
WillInsertChild(aChild);
|
WillInsertChild(aChild);
|
||||||
mMenuChildren.AppendElement(aChild);
|
mMenuChildren.AppendElement(aChild);
|
||||||
|
|
||||||
bool isVisible =
|
bool isVisible = aChild.match(
|
||||||
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); });
|
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||||
|
return aMenuItem->IsVisible();
|
||||||
|
});
|
||||||
NSMenuItem* nativeItem = aChild.match(
|
NSMenuItem* nativeItem = aChild.match(
|
||||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
|
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->NativeNSMenuItem(); });
|
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||||
|
return aMenuItem->NativeNSMenuItem();
|
||||||
|
});
|
||||||
|
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
RemovePlaceholderIfPresent();
|
RemovePlaceholderIfPresent();
|
||||||
|
|
@ -242,9 +261,11 @@ void nsMenuX::InsertMenuChild(MenuChild&& aChild) {
|
||||||
size_t insertionIndex = FindInsertionIndex(aChild);
|
size_t insertionIndex = FindInsertionIndex(aChild);
|
||||||
mMenuChildren.InsertElementAt(insertionIndex, aChild);
|
mMenuChildren.InsertElementAt(insertionIndex, aChild);
|
||||||
|
|
||||||
bool isVisible =
|
bool isVisible = aChild.match(
|
||||||
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); });
|
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||||
|
return aMenuItem->IsVisible();
|
||||||
|
});
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
MenuChildChangedVisibility(aChild, true);
|
MenuChildChangedVisibility(aChild, true);
|
||||||
}
|
}
|
||||||
|
|
@ -253,9 +274,11 @@ void nsMenuX::InsertMenuChild(MenuChild&& aChild) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsMenuX::RemoveMenuChild(const MenuChild& aChild) {
|
void nsMenuX::RemoveMenuChild(const MenuChild& aChild) {
|
||||||
bool isVisible =
|
bool isVisible = aChild.match(
|
||||||
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->IsVisible(); },
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->IsVisible(); });
|
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||||
|
return aMenuItem->IsVisible();
|
||||||
|
});
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
MenuChildChangedVisibility(aChild, false);
|
MenuChildChangedVisibility(aChild, false);
|
||||||
}
|
}
|
||||||
|
|
@ -268,16 +291,20 @@ size_t nsMenuX::FindInsertionIndex(const MenuChild& aChild) {
|
||||||
nsCOMPtr<nsIContent> menuPopup = GetMenuPopupContent();
|
nsCOMPtr<nsIContent> menuPopup = GetMenuPopupContent();
|
||||||
MOZ_RELEASE_ASSERT(menuPopup);
|
MOZ_RELEASE_ASSERT(menuPopup);
|
||||||
|
|
||||||
RefPtr<nsIContent> insertedContent =
|
RefPtr<nsIContent> insertedContent = aChild.match(
|
||||||
aChild.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||||
|
return aMenuItem->Content();
|
||||||
|
});
|
||||||
|
|
||||||
MOZ_RELEASE_ASSERT(insertedContent->GetParent() == menuPopup);
|
MOZ_RELEASE_ASSERT(insertedContent->GetParent() == menuPopup);
|
||||||
|
|
||||||
// Iterate over menuPopup's children (insertedContent's siblings) until we encounter
|
// Iterate over menuPopup's children (insertedContent's siblings) until we
|
||||||
// insertedContent. At the same time, keep track of the index in mMenuChildren.
|
// encounter insertedContent. At the same time, keep track of the index in
|
||||||
|
// mMenuChildren.
|
||||||
size_t index = 0;
|
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()) {
|
child = child->GetNextSibling()) {
|
||||||
if (child == insertedContent) {
|
if (child == insertedContent) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -285,7 +312,9 @@ size_t nsMenuX::FindInsertionIndex(const MenuChild& aChild) {
|
||||||
|
|
||||||
RefPtr<nsIContent> contentAtIndex = mMenuChildren[index].match(
|
RefPtr<nsIContent> contentAtIndex = mMenuChildren[index].match(
|
||||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||||
|
return aMenuItem->Content();
|
||||||
|
});
|
||||||
if (child == contentAtIndex) {
|
if (child == contentAtIndex) {
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
@ -313,7 +342,8 @@ nsresult nsMenuX::GetVisibleItemCount(uint32_t& aCount) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only includes visible items. Note that this is provides O(N) access
|
// 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) {
|
Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
|
||||||
uint32_t count = mMenuChildren.Length();
|
uint32_t count = mMenuChildren.Length();
|
||||||
if (aPos >= mVisibleItemsCount || aPos >= count) {
|
if (aPos >= mVisibleItemsCount || aPos >= count) {
|
||||||
|
|
@ -329,9 +359,11 @@ Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
|
||||||
uint32_t visibleNodeIndex = 0;
|
uint32_t visibleNodeIndex = 0;
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
MenuChild item = *GetItemAt(i);
|
MenuChild item = *GetItemAt(i);
|
||||||
RefPtr<nsIContent> content =
|
RefPtr<nsIContent> content = item.match(
|
||||||
item.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
[](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)) {
|
if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(content)) {
|
||||||
if (aPos == visibleNodeIndex) {
|
if (aPos == visibleNodeIndex) {
|
||||||
// we found the visible node we're looking for, return it
|
// we found the visible node we're looking for, return it
|
||||||
|
|
@ -344,11 +376,14 @@ Maybe<nsMenuX::MenuChild> nsMenuX::GetVisibleItemAt(uint32_t aPos) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<nsMenuX::MenuChild> nsMenuX::GetItemForElement(Element* aMenuChildElement) {
|
Maybe<nsMenuX::MenuChild> nsMenuX::GetItemForElement(
|
||||||
|
Element* aMenuChildElement) {
|
||||||
for (auto& child : mMenuChildren) {
|
for (auto& child : mMenuChildren) {
|
||||||
RefPtr<nsIContent> content =
|
RefPtr<nsIContent> content = child.match(
|
||||||
child.match([](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->Content(); },
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->Content(); });
|
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||||
|
return aMenuItem->Content();
|
||||||
|
});
|
||||||
if (content == aMenuChildElement) {
|
if (content == aMenuChildElement) {
|
||||||
return Some(child);
|
return Some(child);
|
||||||
}
|
}
|
||||||
|
|
@ -397,7 +432,8 @@ void nsMenuX::MenuOpened() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we fire any pending popupshown / popuphiding / popuphidden events first.
|
// Make sure we fire any pending popupshown / popuphiding / popuphidden events
|
||||||
|
// first.
|
||||||
FlushMenuOpenedRunnable();
|
FlushMenuOpenedRunnable();
|
||||||
FlushMenuClosedRunnable();
|
FlushMenuClosedRunnable();
|
||||||
|
|
||||||
|
|
@ -405,10 +441,11 @@ void nsMenuX::MenuOpened() {
|
||||||
// Fire popupshowing now.
|
// Fire popupshowing now.
|
||||||
bool approvedToOpen = OnOpen();
|
bool approvedToOpen = OnOpen();
|
||||||
if (!approvedToOpen) {
|
if (!approvedToOpen) {
|
||||||
// We can only stop menus from opening which we open ourselves. We cannot stop menubar root
|
// We can only stop menus from opening which we open ourselves. We cannot
|
||||||
// menus or menu submenus from opening.
|
// stop menubar root menus or menu submenus from opening. For context
|
||||||
// For context menus, we can call OnOpen() before we ask the system to open the menu.
|
// 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 "
|
NS_WARNING("The popupshowing event had preventDefault() called on it, "
|
||||||
|
"but in MenuOpened() it "
|
||||||
"is too late to stop the menu from opening.");
|
"is too late to stop the menu from opening.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -425,10 +462,9 @@ void nsMenuX::MenuOpened() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire the popupshown event in MenuOpenedAsync.
|
// Fire the popupshown event in MenuOpenedAsync.
|
||||||
// MenuOpened() is called during menuWillOpen, and if cancelTracking is called now, menuDidClose
|
// MenuOpened() is called during menuWillOpen, and if cancelTracking is called
|
||||||
// will not be called.
|
// now, menuDidClose will not be called. The runnable object must not hold a
|
||||||
// The runnable object must not hold a strong reference to the nsMenuX, so that there is no
|
// strong reference to the nsMenuX, so that there is no reference cycle.
|
||||||
// reference cycle.
|
|
||||||
class MenuOpenedAsyncRunnable final : public mozilla::CancelableRunnable {
|
class MenuOpenedAsyncRunnable final : public mozilla::CancelableRunnable {
|
||||||
public:
|
public:
|
||||||
explicit MenuOpenedAsyncRunnable(nsMenuX* aMenu)
|
explicit MenuOpenedAsyncRunnable(nsMenuX* aMenu)
|
||||||
|
|
@ -470,7 +506,8 @@ void nsMenuX::MenuOpenedAsync() {
|
||||||
|
|
||||||
// Open the node.
|
// Open the node.
|
||||||
if (mContent->IsElement()) {
|
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();
|
RefPtr<nsIContent> popupContent = GetMenuPopupContent();
|
||||||
|
|
@ -482,7 +519,8 @@ void nsMenuX::MenuOpenedAsync() {
|
||||||
|
|
||||||
// Fire popupshown.
|
// Fire popupshown.
|
||||||
nsEventStatus status = nsEventStatus_eIgnore;
|
nsEventStatus status = nsEventStatus_eIgnore;
|
||||||
WidgetMouseEvent event(true, eXULPopupShown, nullptr, WidgetMouseEvent::eReal);
|
WidgetMouseEvent event(true, eXULPopupShown, nullptr,
|
||||||
|
WidgetMouseEvent::eReal);
|
||||||
RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
|
RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
|
||||||
EventDispatcher::Dispatch(dispatchTo, nullptr, &event, nullptr, &status);
|
EventDispatcher::Dispatch(dispatchTo, nullptr, &event, nullptr, &status);
|
||||||
}
|
}
|
||||||
|
|
@ -495,7 +533,8 @@ void nsMenuX::MenuClosed() {
|
||||||
// Make sure we fire any pending popupshown events first.
|
// Make sure we fire any pending popupshown events first.
|
||||||
FlushMenuOpenedRunnable();
|
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) {
|
for (auto& child : mMenuChildren) {
|
||||||
if (child.is<RefPtr<nsMenuX>>()) {
|
if (child.is<RefPtr<nsMenuX>>()) {
|
||||||
child.as<RefPtr<nsMenuX>>()->MenuClosed();
|
child.as<RefPtr<nsMenuX>>()->MenuClosed();
|
||||||
|
|
@ -505,11 +544,11 @@ void nsMenuX::MenuClosed() {
|
||||||
mIsOpen = false;
|
mIsOpen = false;
|
||||||
|
|
||||||
// Do the rest of the MenuClosed work in MenuClosedAsync.
|
// Do the rest of the MenuClosed work in MenuClosedAsync.
|
||||||
// MenuClosed() is called from -[NSMenuDelegate menuDidClose:]. If a menuitem was clicked,
|
// MenuClosed() is called from -[NSMenuDelegate menuDidClose:]. If a menuitem
|
||||||
// menuDidClose is called *before* menuItemHit for the clicked menu item is called.
|
// was clicked, menuDidClose is called *before* menuItemHit for the clicked
|
||||||
// This runnable will be canceled if ~nsMenuX runs before the runnable.
|
// menu item is called. This runnable will be canceled if ~nsMenuX runs before
|
||||||
// The runnable object must not hold a strong reference to the nsMenuX, so that there is no
|
// the runnable. The runnable object must not hold a strong reference to the
|
||||||
// reference cycle.
|
// nsMenuX, so that there is no reference cycle.
|
||||||
class MenuClosedAsyncRunnable final : public mozilla::CancelableRunnable {
|
class MenuClosedAsyncRunnable final : public mozilla::CancelableRunnable {
|
||||||
public:
|
public:
|
||||||
explicit MenuClosedAsyncRunnable(nsMenuX* aMenu)
|
explicit MenuClosedAsyncRunnable(nsMenuX* aMenu)
|
||||||
|
|
@ -538,7 +577,8 @@ void nsMenuX::MenuClosed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsMenuX::FlushMenuClosedRunnable() {
|
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) {
|
for (auto& child : mMenuChildren) {
|
||||||
if (child.is<RefPtr<nsMenuX>>()) {
|
if (child.is<RefPtr<nsMenuX>>()) {
|
||||||
child.as<RefPtr<nsMenuX>>()->FlushMenuClosedRunnable();
|
child.as<RefPtr<nsMenuX>>()->FlushMenuClosedRunnable();
|
||||||
|
|
@ -569,8 +609,10 @@ void nsMenuX::MenuClosedAsync() {
|
||||||
nsCOMPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
|
nsCOMPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
|
||||||
|
|
||||||
nsEventStatus status = nsEventStatus_eIgnore;
|
nsEventStatus status = nsEventStatus_eIgnore;
|
||||||
WidgetMouseEvent popupHiding(true, eXULPopupHiding, nullptr, WidgetMouseEvent::eReal);
|
WidgetMouseEvent popupHiding(true, eXULPopupHiding, nullptr,
|
||||||
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHiding, nullptr, &status);
|
WidgetMouseEvent::eReal);
|
||||||
|
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHiding, nullptr,
|
||||||
|
&status);
|
||||||
|
|
||||||
mIsOpenForGecko = false;
|
mIsOpenForGecko = false;
|
||||||
|
|
||||||
|
|
@ -578,8 +620,10 @@ void nsMenuX::MenuClosedAsync() {
|
||||||
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
|
mContent->AsElement()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetMouseEvent popupHidden(true, eXULPopupHidden, nullptr, WidgetMouseEvent::eReal);
|
WidgetMouseEvent popupHidden(true, eXULPopupHidden, nullptr,
|
||||||
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHidden, nullptr, &status);
|
WidgetMouseEvent::eReal);
|
||||||
|
EventDispatcher::Dispatch(dispatchTo, nullptr, &popupHidden, nullptr,
|
||||||
|
&status);
|
||||||
|
|
||||||
// Notify our observer.
|
// Notify our observer.
|
||||||
if (mObserver && popupContent) {
|
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) {
|
int16_t aButton) {
|
||||||
if (mIsOpenForGecko) {
|
if (mIsOpenForGecko) {
|
||||||
// Queue the event into mPendingCommandEvents. We will call aItem->DoCommand in
|
// Queue the event into mPendingCommandEvents. We will call aItem->DoCommand
|
||||||
// MenuClosedAsync(). We rely on the assumption that MenuClosedAsync will run soon.
|
// in MenuClosedAsync(). We rely on the assumption that MenuClosedAsync will
|
||||||
mPendingCommandEvents.AppendElement(PendingCommandEvent{std::move(aItem), aModifiers, aButton});
|
// run soon.
|
||||||
|
mPendingCommandEvents.AppendElement(
|
||||||
|
PendingCommandEvent{std::move(aItem), aModifiers, aButton});
|
||||||
} else {
|
} else {
|
||||||
// The menu item was activated outside of a regular open / activate / close sequence.
|
// The menu item was activated outside of a regular open / activate / close
|
||||||
// This happens in multiple cases:
|
// sequence. This happens in multiple cases:
|
||||||
// - When a menu item is activated by a keyboard shortcut while all windows are closed
|
// - When a menu item is activated by a keyboard shortcut while all windows
|
||||||
// (otherwise those shortcuts go through Gecko's manual keyboard handling)
|
// are closed
|
||||||
|
// (otherwise those shortcuts go through Gecko's manual keyboard
|
||||||
|
// handling)
|
||||||
// - When a menu item in the Dock menu is clicked
|
// - When a menu item in the Dock menu is clicked
|
||||||
// - During native menu tests
|
// - During native menu tests
|
||||||
//
|
//
|
||||||
|
|
@ -610,10 +659,11 @@ bool nsMenuX::Close() {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||||
|
|
||||||
if (mDidFirePopupshowingAndIsApprovedToOpen && !mIsOpen) {
|
if (mDidFirePopupshowingAndIsApprovedToOpen && !mIsOpen) {
|
||||||
// Close is being called right after this menu was opened, but before MenuOpened() had a chance
|
// Close is being called right after this menu was opened, but before
|
||||||
// to run. Call it here so that we can go through the entire popupshown -> popuphiding ->
|
// MenuOpened() had a chance to run. Call it here so that we can go through
|
||||||
// popuphidden sequence. Some callers expect to get a popuphidden event even if they close the
|
// the entire popupshown -> popuphiding -> popuphidden sequence. Some
|
||||||
// popup before it was fully open.
|
// callers expect to get a popuphidden event even if they close the popup
|
||||||
|
// before it was fully open.
|
||||||
MenuOpened();
|
MenuOpened();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -623,11 +673,12 @@ bool nsMenuX::Close() {
|
||||||
|
|
||||||
if (mIsOpen) {
|
if (mIsOpen) {
|
||||||
// Close the menu.
|
// Close the menu.
|
||||||
// We usually don't get here during normal Firefox usage: If the user closes the menu by
|
// We usually don't get here during normal Firefox usage: If the user closes
|
||||||
// clicking an item, or by clicking outside the menu, or by pressing escape, then the menu gets
|
// the menu by clicking an item, or by clicking outside the menu, or by
|
||||||
// closed by macOS, and not by a call to nsMenuX::Close().
|
// pressing escape, then the menu gets closed by macOS, and not by a call to
|
||||||
// If we do get here, it's usually because we're running an automated test. Close the menu
|
// nsMenuX::Close(). If we do get here, it's usually because we're running
|
||||||
// without the fade-out animation so that we don't unnecessarily slow down the automated tests.
|
// an automated test. Close the menu without the fade-out animation so that
|
||||||
|
// we don't unnecessarily slow down the automated tests.
|
||||||
[mNativeMenu cancelTrackingWithoutAnimation];
|
[mNativeMenu cancelTrackingWithoutAnimation];
|
||||||
MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES;
|
MOZMenuOpeningCoordinator.needToUnwindForMenuClosing = YES;
|
||||||
|
|
||||||
|
|
@ -642,7 +693,8 @@ bool nsMenuX::Close() {
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
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) {
|
if (mHighlightedItemIndex == aNewHighlightedIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -651,16 +703,16 @@ void nsMenuX::OnHighlightedItemChanged(const Maybe<uint32_t>& aNewHighlightedInd
|
||||||
Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*mHighlightedItemIndex);
|
Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*mHighlightedItemIndex);
|
||||||
if (target && target->is<RefPtr<nsMenuItemX>>()) {
|
if (target && target->is<RefPtr<nsMenuItemX>>()) {
|
||||||
bool handlerCalledPreventDefault; // but we don't actually care
|
bool handlerCalledPreventDefault; // but we don't actually care
|
||||||
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(u"DOMMenuItemInactive"_ns,
|
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(
|
||||||
&handlerCalledPreventDefault);
|
u"DOMMenuItemInactive"_ns, &handlerCalledPreventDefault);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (aNewHighlightedIndex) {
|
if (aNewHighlightedIndex) {
|
||||||
Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*aNewHighlightedIndex);
|
Maybe<nsMenuX::MenuChild> target = GetVisibleItemAt(*aNewHighlightedIndex);
|
||||||
if (target && target->is<RefPtr<nsMenuItemX>>()) {
|
if (target && target->is<RefPtr<nsMenuItemX>>()) {
|
||||||
bool handlerCalledPreventDefault; // but we don't actually care
|
bool handlerCalledPreventDefault; // but we don't actually care
|
||||||
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(u"DOMMenuItemActive"_ns,
|
target->as<RefPtr<nsMenuItemX>>()->DispatchDOMEvent(
|
||||||
&handlerCalledPreventDefault);
|
u"DOMMenuItemActive"_ns, &handlerCalledPreventDefault);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mHighlightedItemIndex = aNewHighlightedIndex;
|
mHighlightedItemIndex = aNewHighlightedIndex;
|
||||||
|
|
@ -672,21 +724,25 @@ void nsMenuX::OnWillActivateItem(NSMenuItem* aItem) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMenuGroupOwner && mObserver) {
|
if (mMenuGroupOwner && mObserver) {
|
||||||
nsMenuItemX* item = mMenuGroupOwner->GetMenuItemForCommandID(uint32_t(aItem.tag));
|
nsMenuItemX* item =
|
||||||
|
mMenuGroupOwner->GetMenuItemForCommandID(uint32_t(aItem.tag));
|
||||||
if (item && item->Content()->IsElement()) {
|
if (item && item->Content()->IsElement()) {
|
||||||
RefPtr<dom::Element> itemElement = item->Content()->AsElement();
|
RefPtr<dom::Element> itemElement = item->Content()->AsElement();
|
||||||
if (nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent()) {
|
if (nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent()) {
|
||||||
mObserver->OnMenuWillActivateItem(popupContent->AsElement(), itemElement);
|
mObserver->OnMenuWillActivateItem(popupContent->AsElement(),
|
||||||
|
itemElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flushes style.
|
// Flushes style.
|
||||||
static NSUserInterfaceLayoutDirection DirectionForElement(dom::Element* aElement) {
|
static NSUserInterfaceLayoutDirection DirectionForElement(
|
||||||
// Get the direction from the computed style so that inheritance into submenus is respected.
|
dom::Element* aElement) {
|
||||||
// aElement may not have a frame.
|
// Get the direction from the computed style so that inheritance into submenus
|
||||||
RefPtr<const ComputedStyle> sc = nsComputedDOMStyle::GetComputedStyle(aElement);
|
// is respected. aElement may not have a frame.
|
||||||
|
RefPtr<const ComputedStyle> sc =
|
||||||
|
nsComputedDOMStyle::GetComputedStyle(aElement);
|
||||||
if (!sc) {
|
if (!sc) {
|
||||||
return NSApp.userInterfaceLayoutDirection;
|
return NSApp.userInterfaceLayoutDirection;
|
||||||
}
|
}
|
||||||
|
|
@ -711,11 +767,13 @@ void nsMenuX::RebuildMenu() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menuPopup->IsElement()) {
|
if (menuPopup->IsElement()) {
|
||||||
mNativeMenu.userInterfaceLayoutDirection = DirectionForElement(menuPopup->AsElement());
|
mNativeMenu.userInterfaceLayoutDirection =
|
||||||
|
DirectionForElement(menuPopup->AsElement());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over the kids
|
// 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)) {
|
if (Maybe<MenuChild> menuChild = CreateMenuChild(child)) {
|
||||||
AddMenuChild(std::move(*menuChild));
|
AddMenuChild(std::move(*menuChild));
|
||||||
}
|
}
|
||||||
|
|
@ -732,9 +790,12 @@ void nsMenuX::InsertPlaceholderIfNeeded() {
|
||||||
|
|
||||||
if ([mNativeMenu numberOfItems] == 0) {
|
if ([mNativeMenu numberOfItems] == 0) {
|
||||||
MOZ_RELEASE_ASSERT(mVisibleItemsCount == 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.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];
|
[mNativeMenu addItem:item];
|
||||||
[item release];
|
[item release];
|
||||||
}
|
}
|
||||||
|
|
@ -800,11 +861,13 @@ GeckoNSMenu* nsMenuX::CreateMenuWithGeckoString(nsString& aMenuTitle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<nsMenuX::MenuChild> nsMenuX::CreateMenuChild(nsIContent* aContent) {
|
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)));
|
return Some(MenuChild(CreateMenuItem(aContent)));
|
||||||
}
|
}
|
||||||
if (aContent->IsXULElement(nsGkAtoms::menu)) {
|
if (aContent->IsXULElement(nsGkAtoms::menu)) {
|
||||||
return Some(MenuChild(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aContent)));
|
return Some(
|
||||||
|
MenuChild(MakeRefPtr<nsMenuX>(this, mMenuGroupOwner, aContent)));
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
@ -821,9 +884,10 @@ RefPtr<nsMenuItemX> nsMenuX::CreateMenuItem(nsIContent* aMenuItemContent) {
|
||||||
if (aMenuItemContent->IsXULElement(nsGkAtoms::menuseparator)) {
|
if (aMenuItemContent->IsXULElement(nsGkAtoms::menuseparator)) {
|
||||||
itemType = eSeparatorMenuItemType;
|
itemType = eSeparatorMenuItemType;
|
||||||
} else if (aMenuItemContent->IsElement()) {
|
} else if (aMenuItemContent->IsElement()) {
|
||||||
static Element::AttrValuesArray strings[] = {nsGkAtoms::checkbox, nsGkAtoms::radio, nullptr};
|
static Element::AttrValuesArray strings[] = {nsGkAtoms::checkbox,
|
||||||
switch (aMenuItemContent->AsElement()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
|
nsGkAtoms::radio, nullptr};
|
||||||
strings, eCaseMatters)) {
|
switch (aMenuItemContent->AsElement()->FindAttrValueIn(
|
||||||
|
kNameSpaceID_None, nsGkAtoms::type, strings, eCaseMatters)) {
|
||||||
case 0:
|
case 0:
|
||||||
itemType = eCheckboxMenuItemType;
|
itemType = eCheckboxMenuItemType;
|
||||||
break;
|
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() {
|
bool nsMenuX::OnOpen() {
|
||||||
if (mDidFirePopupshowingAndIsApprovedToOpen) {
|
if (mDidFirePopupshowingAndIsApprovedToOpen) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsOpen) {
|
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.");
|
"seems odd.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -854,7 +921,8 @@ bool nsMenuX::OnOpen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
nsEventStatus status = nsEventStatus_eIgnore;
|
nsEventStatus status = nsEventStatus_eIgnore;
|
||||||
WidgetMouseEvent event(true, eXULPopupShowing, nullptr, WidgetMouseEvent::eReal);
|
WidgetMouseEvent event(true, eXULPopupShowing, nullptr,
|
||||||
|
WidgetMouseEvent::eReal);
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
RefPtr<nsIContent> dispatchTo = popupContent ? popupContent : mContent;
|
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
|
// Find the |menupopup| child in the |popup| representing this menu. It should
|
||||||
// of a very few children so we won't be iterating over a bazillion menu items to find
|
// be one of a very few children so we won't be iterating over a bazillion menu
|
||||||
// it (so the strcmp won't kill us).
|
// items to find it (so the strcmp won't kill us).
|
||||||
already_AddRefed<nsIContent> nsMenuX::GetMenuPopupContent() {
|
already_AddRefed<nsIContent> nsMenuX::GetMenuPopupContent() {
|
||||||
// Check to see if we are a "menupopup" node (if we are a native menu).
|
// Check to see if we are a "menupopup" node (if we are a native menu).
|
||||||
if (mContent->IsXULElement(nsGkAtoms::menupopup)) {
|
if (mContent->IsXULElement(nsGkAtoms::menupopup)) {
|
||||||
|
|
@ -935,7 +1003,8 @@ bool nsMenuX::IsXULWindowMenu(nsIContent* aMenuContent) {
|
||||||
// nsChangeObserver
|
// nsChangeObserver
|
||||||
//
|
//
|
||||||
|
|
||||||
void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aContent,
|
void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument,
|
||||||
|
nsIContent* aContent,
|
||||||
nsAtom* aAttribute) {
|
nsAtom* aAttribute) {
|
||||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||||
|
|
||||||
|
|
@ -945,14 +1014,17 @@ void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aCon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aAttribute == nsGkAtoms::disabled) {
|
if (aAttribute == nsGkAtoms::disabled) {
|
||||||
SetEnabled(!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
SetEnabled(!mContent->AsElement()->AttrValueIs(
|
||||||
nsGkAtoms::_true, eCaseMatters));
|
kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true,
|
||||||
|
eCaseMatters));
|
||||||
} else if (aAttribute == nsGkAtoms::label) {
|
} else if (aAttribute == nsGkAtoms::label) {
|
||||||
mContent->AsElement()->GetAttr(nsGkAtoms::label, mLabel);
|
mContent->AsElement()->GetAttr(nsGkAtoms::label, mLabel);
|
||||||
NSString* newCocoaLabelString = nsMenuUtilsX::GetTruncatedCocoaLabel(mLabel);
|
NSString* newCocoaLabelString =
|
||||||
|
nsMenuUtilsX::GetTruncatedCocoaLabel(mLabel);
|
||||||
mNativeMenu.title = newCocoaLabelString;
|
mNativeMenu.title = newCocoaLabelString;
|
||||||
mNativeMenuItem.title = newCocoaLabelString;
|
mNativeMenuItem.title = newCocoaLabelString;
|
||||||
} else if (aAttribute == nsGkAtoms::hidden || aAttribute == nsGkAtoms::collapsed) {
|
} else if (aAttribute == nsGkAtoms::hidden ||
|
||||||
|
aAttribute == nsGkAtoms::collapsed) {
|
||||||
SetRebuild(true);
|
SetRebuild(true);
|
||||||
|
|
||||||
bool newVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent);
|
bool newVisible = !nsMenuUtilsX::NodeIsHiddenOrCollapsed(mContent);
|
||||||
|
|
@ -977,8 +1049,9 @@ void nsMenuX::ObserveAttributeChanged(dom::Document* aDocument, nsIContent* aCon
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsMenuX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aContainer,
|
void nsMenuX::ObserveContentRemoved(dom::Document* aDocument,
|
||||||
nsIContent* aChild, nsIContent* aPreviousSibling) {
|
nsIContent* aContainer, nsIContent* aChild,
|
||||||
|
nsIContent* aPreviousSibling) {
|
||||||
if (gConstructingMenu) {
|
if (gConstructingMenu) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -991,7 +1064,8 @@ void nsMenuX::ObserveContentRemoved(dom::Document* aDocument, nsIContent* aConta
|
||||||
return;
|
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();
|
nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent();
|
||||||
if (popupContent && aContainer == popupContent && aChild->IsElement()) {
|
if (popupContent && aContainer == popupContent && aChild->IsElement()) {
|
||||||
if (Maybe<MenuChild> child = GetItemForElement(aChild->AsElement())) {
|
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) {
|
nsIContent* aChild) {
|
||||||
if (gConstructingMenu) {
|
if (gConstructingMenu) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1013,7 +1088,8 @@ void nsMenuX::ObserveContentInserted(dom::Document* aDocument, nsIContent* aCont
|
||||||
return;
|
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();
|
nsCOMPtr<nsIContent> popupContent = GetMenuPopupContent();
|
||||||
if (popupContent && aContainer == popupContent) {
|
if (popupContent && aContainer == popupContent) {
|
||||||
if (Maybe<MenuChild> child = CreateMenuChild(aChild)) {
|
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;
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||||
|
|
||||||
NSMenuItem* nativeItem = aChild.match(
|
NSMenuItem* nativeItem = aChild.match(
|
||||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
|
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
|
||||||
[](const RefPtr<nsMenuItemX>& aMenuItem) { return aMenuItem->NativeNSMenuItem(); });
|
[](const RefPtr<nsMenuItemX>& aMenuItem) {
|
||||||
|
return aMenuItem->NativeNSMenuItem();
|
||||||
|
});
|
||||||
if (aIsVisible) {
|
if (aIsVisible) {
|
||||||
MOZ_RELEASE_ASSERT(!nativeItem.menu,
|
MOZ_RELEASE_ASSERT(
|
||||||
"The native item should not be in a menu while it is hidden");
|
!nativeItem.menu,
|
||||||
|
"The native item should not be in a menu while it is hidden");
|
||||||
RemovePlaceholderIfPresent();
|
RemovePlaceholderIfPresent();
|
||||||
NSInteger insertionPoint = CalculateNativeInsertionPoint(aChild);
|
NSInteger insertionPoint = CalculateNativeInsertionPoint(aChild);
|
||||||
[mNativeMenu insertItem:nativeItem atIndex:insertionPoint];
|
[mNativeMenu insertItem:nativeItem atIndex:insertionPoint];
|
||||||
mVisibleItemsCount++;
|
mVisibleItemsCount++;
|
||||||
} else {
|
} else {
|
||||||
MOZ_RELEASE_ASSERT([mNativeMenu indexOfItem:nativeItem] != -1,
|
MOZ_RELEASE_ASSERT(
|
||||||
"The native item should be in this menu while it is visible");
|
[mNativeMenu indexOfItem:nativeItem] != -1,
|
||||||
|
"The native item should be in this menu while it is visible");
|
||||||
[mNativeMenu removeItem:nativeItem];
|
[mNativeMenu removeItem:nativeItem];
|
||||||
mVisibleItemsCount--;
|
mVisibleItemsCount--;
|
||||||
InsertPlaceholderIfNeeded();
|
InsertPlaceholderIfNeeded();
|
||||||
|
|
@ -1067,7 +1148,9 @@ NSInteger nsMenuX::CalculateNativeInsertionPoint(const MenuChild& aChild) {
|
||||||
}
|
}
|
||||||
NSMenuItem* nativeItem = currItem.match(
|
NSMenuItem* nativeItem = currItem.match(
|
||||||
[](const RefPtr<nsMenuX>& aMenu) { return aMenu->NativeNSMenuItem(); },
|
[](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.
|
// Only count visible items.
|
||||||
if (nativeItem.menu) {
|
if (nativeItem.menu) {
|
||||||
insertionPoint++;
|
insertionPoint++;
|
||||||
|
|
@ -1077,9 +1160,10 @@ NSInteger nsMenuX::CalculateNativeInsertionPoint(const MenuChild& aChild) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsMenuX::Dump(uint32_t aIndent) const {
|
void nsMenuX::Dump(uint32_t aIndent) const {
|
||||||
printf("%*s - menu [%p] %-16s <%s>", aIndent * 2, "", this,
|
printf(
|
||||||
mLabel.IsEmpty() ? "(empty label)" : NS_ConvertUTF16toUTF8(mLabel).get(),
|
"%*s - menu [%p] %-16s <%s>", aIndent * 2, "", this,
|
||||||
NS_ConvertUTF16toUTF8(mContent->NodeName()).get());
|
mLabel.IsEmpty() ? "(empty label)" : NS_ConvertUTF16toUTF8(mLabel).get(),
|
||||||
|
NS_ConvertUTF16toUTF8(mContent->NodeName()).get());
|
||||||
if (mNeedsRebuild) {
|
if (mNeedsRebuild) {
|
||||||
printf(" [NeedsRebuild]");
|
printf(" [NeedsRebuild]");
|
||||||
}
|
}
|
||||||
|
|
@ -1095,8 +1179,11 @@ void nsMenuX::Dump(uint32_t aIndent) const {
|
||||||
printf(" (%d visible items)", int(mVisibleItemsCount));
|
printf(" (%d visible items)", int(mVisibleItemsCount));
|
||||||
printf("\n");
|
printf("\n");
|
||||||
for (const auto& subitem : mMenuChildren) {
|
for (const auto& subitem : mMenuChildren) {
|
||||||
subitem.match([=](const RefPtr<nsMenuX>& aMenu) { aMenu->Dump(aIndent + 1); },
|
subitem.match(
|
||||||
[=](const RefPtr<nsMenuItemX>& aMenuItem) { aMenuItem->Dump(aIndent + 1); });
|
[=](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 {
|
- (id)initWithGeckoMenu:(nsMenuX*)geckoMenu {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
NS_ASSERTION(geckoMenu,
|
NS_ASSERTION(geckoMenu, "Cannot initialize native menu delegate with NULL "
|
||||||
"Cannot initialize native menu delegate with NULL gecko menu! Will crash!");
|
"gecko menu! Will crash!");
|
||||||
mGeckoMenu = geckoMenu;
|
mGeckoMenu = geckoMenu;
|
||||||
mBlocksToRunWhenOpen = [[NSMutableArray alloc] init];
|
mBlocksToRunWhenOpen = [[NSMutableArray alloc] init];
|
||||||
}
|
}
|
||||||
|
|
@ -1131,7 +1218,8 @@ void nsMenuX::Dump(uint32_t aIndent) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<uint32_t> index =
|
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);
|
mGeckoMenu->OnHighlightedItemChanged(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1269,7 +1357,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
|
||||||
|
|
||||||
- (int)removeTable:(NSMapTable*)aTable {
|
- (int)removeTable:(NSMapTable*)aTable {
|
||||||
if (aTable) {
|
if (aTable) {
|
||||||
NSValue* objectToRemove = [mTables member:[NSValue valueWithPointer:aTable]];
|
NSValue* objectToRemove =
|
||||||
|
[mTables member:[NSValue valueWithPointer:aTable]];
|
||||||
if (objectToRemove) {
|
if (objectToRemove) {
|
||||||
[mTables removeObject:objectToRemove];
|
[mTables removeObject:objectToRemove];
|
||||||
}
|
}
|
||||||
|
|
@ -1281,7 +1370,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
|
||||||
|
|
||||||
@interface NSMenu (MethodSwizzling)
|
@interface NSMenu (MethodSwizzling)
|
||||||
+ (void)nsMenuX_NSMenu_addItem:(NSMenuItem*)aItem toTable:(NSMapTable*)aTable;
|
+ (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
|
@end
|
||||||
|
|
||||||
@implementation NSMenu (MethodSwizzling)
|
@implementation NSMenu (MethodSwizzling)
|
||||||
|
|
@ -1304,7 +1394,8 @@ static NSMutableDictionary* gShadowKeyEquivDB = nil;
|
||||||
[self nsMenuX_NSMenu_addItem:aItem toTable:aTable];
|
[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];
|
[self nsMenuX_NSMenu_removeItem:aItem fromTable:aTable];
|
||||||
|
|
||||||
if (aItem && 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
|
@end
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -73,7 +73,8 @@ NS_IMETHODIMP
|
||||||
nsPrintDialogServiceX::Init() { return NS_OK; }
|
nsPrintDialogServiceX::Init() { return NS_OK; }
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSelection,
|
nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent,
|
||||||
|
bool aHaveSelection,
|
||||||
nsIPrintSettings* aSettings) {
|
nsIPrintSettings* aSettings) {
|
||||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||||
|
|
||||||
|
|
@ -84,7 +85,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSPrintInfo* printInfo = settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
|
NSPrintInfo* printInfo =
|
||||||
|
settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
|
||||||
if (NS_WARN_IF(!printInfo)) {
|
if (NS_WARN_IF(!printInfo)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +102,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
||||||
NULL, reinterpret_cast<const UniChar*>(adjustedTitle.BeginReading()),
|
NULL, reinterpret_cast<const UniChar*>(adjustedTitle.BeginReading()),
|
||||||
adjustedTitle.Length());
|
adjustedTitle.Length());
|
||||||
if (cfTitleString) {
|
if (cfTitleString) {
|
||||||
auto pmPrintSettings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
|
auto pmPrintSettings =
|
||||||
|
static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
|
||||||
::PMPrintSettingsSetJobName(pmPrintSettings, cfTitleString);
|
::PMPrintSettingsSetJobName(pmPrintSettings, cfTitleString);
|
||||||
[printInfo updateFromPMPrintSettings];
|
[printInfo updateFromPMPrintSettings];
|
||||||
CFRelease(cfTitleString);
|
CFRelease(cfTitleString);
|
||||||
|
|
@ -117,8 +120,8 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
||||||
// [panel runModal] will look for it. We create the view because otherwise
|
// [panel runModal] will look for it. We create the view because otherwise
|
||||||
// we'll get unrelated warnings printed to the console.
|
// we'll get unrelated warnings printed to the console.
|
||||||
NSView* tmpView = [[NSView alloc] init];
|
NSView* tmpView = [[NSView alloc] init];
|
||||||
NSPrintOperation* printOperation = [NSPrintOperation printOperationWithView:tmpView
|
NSPrintOperation* printOperation =
|
||||||
printInfo:printInfo];
|
[NSPrintOperation printOperationWithView:tmpView printInfo:printInfo];
|
||||||
[NSPrintOperation setCurrentOperation:printOperation];
|
[NSPrintOperation setCurrentOperation:printOperation];
|
||||||
|
|
||||||
NSPrintPanel* panel = [NSPrintPanel printPanel];
|
NSPrintPanel* panel = [NSPrintPanel printPanel];
|
||||||
|
|
@ -136,8 +139,9 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
||||||
int button = [panel runModal];
|
int button = [panel runModal];
|
||||||
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
||||||
|
|
||||||
// Retrieve a printInfo with the updated settings. (The NSPrintOperation operates on a
|
// Retrieve a printInfo with the updated settings. (The NSPrintOperation
|
||||||
// copy, so the object we passed in will not have been modified.)
|
// operates on a copy, so the object we passed in will not have been
|
||||||
|
// modified.)
|
||||||
NSPrintInfo* result = [[NSPrintOperation currentOperation] printInfo];
|
NSPrintInfo* result = [[NSPrintOperation currentOperation] printInfo];
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
@ -164,9 +168,9 @@ nsPrintDialogServiceX::ShowPrintDialog(mozIDOMWindowProxy* aParent, bool aHaveSe
|
||||||
[viewController exportSettings];
|
[viewController exportSettings];
|
||||||
|
|
||||||
// Update our settings object based on the user's choices in the dialog.
|
// 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,
|
// We tell settingsX to adopt this printInfo so that it will be used to run
|
||||||
// so that any printer-specific custom settings from print dialog extension panels
|
// print job, so that any printer-specific custom settings from print dialog
|
||||||
// will be carried through.
|
// extension panels will be carried through.
|
||||||
settingsX->SetFromPrintInfo(result, /* aAdoptPrintInfo = */ true);
|
settingsX->SetFromPrintInfo(result, /* aAdoptPrintInfo = */ true);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -188,7 +192,8 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSPrintInfo* printInfo = settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
|
NSPrintInfo* printInfo =
|
||||||
|
settingsX->CreateOrCopyPrintInfo(/* aWithScaling = */ true);
|
||||||
if (NS_WARN_IF(!printInfo)) {
|
if (NS_WARN_IF(!printInfo)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -200,15 +205,17 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
|
||||||
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
||||||
|
|
||||||
if (button == NSFileHandlingPanelOKButton) {
|
if (button == NSFileHandlingPanelOKButton) {
|
||||||
// The Page Setup dialog does not include non-standard settings that need to be preserved,
|
// The Page Setup dialog does not include non-standard settings that need to
|
||||||
// separate from what the base printSettings object handles, so we do not need it to adopt
|
// be preserved, separate from what the base printSettings object handles,
|
||||||
// the printInfo object here.
|
// so we do not need it to adopt the printInfo object here.
|
||||||
settingsX->SetFromPrintInfo(printInfo, /* aAdoptPrintInfo = */ false);
|
settingsX->SetFromPrintInfo(printInfo, /* aAdoptPrintInfo = */ false);
|
||||||
nsCOMPtr<nsIPrintSettingsService> printSettingsService =
|
nsCOMPtr<nsIPrintSettingsService> printSettingsService =
|
||||||
do_GetService("@mozilla.org/gfx/printsettings-service;1");
|
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 |
|
uint32_t flags = nsIPrintSettings::kInitSavePaperSize |
|
||||||
nsIPrintSettings::kInitSaveOrientation | nsIPrintSettings::kInitSaveScaling;
|
nsIPrintSettings::kInitSaveOrientation |
|
||||||
|
nsIPrintSettings::kInitSaveScaling;
|
||||||
printSettingsService->MaybeSavePrintSettingsToPrefs(aNSSettings, flags);
|
printSettingsService->MaybeSavePrintSettingsToPrefs(aNSSettings, flags);
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
@ -234,7 +241,9 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
|
||||||
withFrame:(NSRect)aRect
|
withFrame:(NSRect)aRect
|
||||||
alignment:(NSTextAlignment)aAlignment;
|
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;
|
- (void)addLabel:(const char*)aLabel withFrame:(NSRect)aRect;
|
||||||
|
|
||||||
|
|
@ -243,7 +252,8 @@ nsPrintDialogServiceX::ShowPageSetupDialog(mozIDOMWindowProxy* aParent,
|
||||||
- (NSButton*)checkboxWithLabel:(const char*)aLabel andFrame:(NSRect)aRect;
|
- (NSButton*)checkboxWithLabel:(const char*)aLabel andFrame:(NSRect)aRect;
|
||||||
|
|
||||||
- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
|
- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
|
||||||
selectedItem:(const nsAString&)aCurrentString;
|
selectedItem:
|
||||||
|
(const nsAString&)aCurrentString;
|
||||||
|
|
||||||
- (void)addOptionsSection:(bool)aHaveSelection;
|
- (void)addOptionsSection:(bool)aHaveSelection;
|
||||||
|
|
||||||
|
|
@ -265,7 +275,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
|
|
||||||
// Public methods
|
// Public methods
|
||||||
|
|
||||||
- (id)initWithSettings:(nsIPrintSettings*)aSettings haveSelection:(bool)aHaveSelection {
|
- (id)initWithSettings:(nsIPrintSettings*)aSettings
|
||||||
|
haveSelection:(bool)aHaveSelection {
|
||||||
[super initWithFrame:NSMakeRect(0, 0, 540, 185)];
|
[super initWithFrame:NSMakeRect(0, 0, 540, 185)];
|
||||||
|
|
||||||
mSettings = aSettings;
|
mSettings = aSettings;
|
||||||
|
|
@ -278,7 +289,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)exportSettings {
|
- (void)exportSettings {
|
||||||
mSettings->SetPrintSelectionOnly([mPrintSelectionOnlyCheckbox state] == NSOnState);
|
mSettings->SetPrintSelectionOnly([mPrintSelectionOnlyCheckbox state] ==
|
||||||
|
NSOnState);
|
||||||
mSettings->SetShrinkToFit([mShrinkToFitCheckbox state] == NSOnState);
|
mSettings->SetShrinkToFit([mShrinkToFitCheckbox state] == NSOnState);
|
||||||
mSettings->SetPrintBGColors([mPrintBGColorsCheckbox state] == NSOnState);
|
mSettings->SetPrintBGColors([mPrintBGColorsCheckbox state] == NSOnState);
|
||||||
mSettings->SetPrintBGImages([mPrintBGImagesCheckbox state] == NSOnState);
|
mSettings->SetPrintBGImages([mPrintBGImagesCheckbox state] == NSOnState);
|
||||||
|
|
@ -294,8 +306,10 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
// Localization
|
// Localization
|
||||||
|
|
||||||
- (void)initBundle {
|
- (void)initBundle {
|
||||||
nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
nsCOMPtr<nsIStringBundleService> bundleSvc =
|
||||||
bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties", &mPrintBundle);
|
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||||
|
bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties",
|
||||||
|
&mPrintBundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString*)localizedString:(const char*)aKey {
|
- (NSString*)localizedString:(const char*)aKey {
|
||||||
|
|
@ -303,11 +317,14 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
|
|
||||||
nsAutoString intlString;
|
nsAutoString intlString;
|
||||||
mPrintBundle->GetStringFromName(aKey, intlString);
|
mPrintBundle->GetStringFromName(aKey, intlString);
|
||||||
NSMutableString* s =
|
NSMutableString* s = [NSMutableString
|
||||||
[NSMutableString stringWithUTF8String:NS_ConvertUTF16toUTF8(intlString).get()];
|
stringWithUTF8String:NS_ConvertUTF16toUTF8(intlString).get()];
|
||||||
|
|
||||||
// Remove all underscores (they're used in the GTK dialog for accesskeys).
|
// 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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -328,7 +345,9 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
return label;
|
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];
|
NSTextField* label = [self label:aLabel withFrame:aRect alignment:aAlignment];
|
||||||
[self addSubview:label];
|
[self addSubview:label];
|
||||||
}
|
}
|
||||||
|
|
@ -352,16 +371,19 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
|
- (NSPopUpButton*)headerFooterItemListWithFrame:(NSRect)aRect
|
||||||
selectedItem:(const nsAString&)aCurrentString {
|
selectedItem:
|
||||||
NSPopUpButton* list = [[[NSPopUpButton alloc] initWithFrame:aRect pullsDown:NO] autorelease];
|
(const nsAString&)aCurrentString {
|
||||||
|
NSPopUpButton* list = [[[NSPopUpButton alloc] initWithFrame:aRect
|
||||||
|
pullsDown:NO] autorelease];
|
||||||
[list setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
[list setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
||||||
[[list cell] setControlSize:NSControlSizeSmall];
|
[[list cell] setControlSize:NSControlSizeSmall];
|
||||||
NSArray* items = [NSArray arrayWithObjects:[self localizedString:"headerFooterBlank"],
|
NSArray* items = [NSArray
|
||||||
[self localizedString:"headerFooterTitle"],
|
arrayWithObjects:[self localizedString:"headerFooterBlank"],
|
||||||
[self localizedString:"headerFooterURL"],
|
[self localizedString:"headerFooterTitle"],
|
||||||
[self localizedString:"headerFooterDate"],
|
[self localizedString:"headerFooterURL"],
|
||||||
[self localizedString:"headerFooterPage"],
|
[self localizedString:"headerFooterDate"],
|
||||||
[self localizedString:"headerFooterPageTotal"], nil];
|
[self localizedString:"headerFooterPage"],
|
||||||
|
[self localizedString:"headerFooterPageTotal"], nil];
|
||||||
[list addItemsWithTitles:items];
|
[list addItemsWithTitles:items];
|
||||||
|
|
||||||
NS_ConvertUTF16toUTF8 currentStringUTF8(aCurrentString);
|
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)];
|
[self addLabel:"optionsTitleMac" withFrame:NSMakeRect(0, 155, 151, 22)];
|
||||||
|
|
||||||
// "Print Selection Only"
|
// "Print Selection Only"
|
||||||
mPrintSelectionOnlyCheckbox = [self checkboxWithLabel:"selectionOnly"
|
mPrintSelectionOnlyCheckbox =
|
||||||
andFrame:NSMakeRect(156, 155, 0, 0)];
|
[self checkboxWithLabel:"selectionOnly"
|
||||||
|
andFrame:NSMakeRect(156, 155, 0, 0)];
|
||||||
[mPrintSelectionOnlyCheckbox setEnabled:aHaveSelection];
|
[mPrintSelectionOnlyCheckbox setEnabled:aHaveSelection];
|
||||||
|
|
||||||
if (mSettings->GetPrintSelectionOnly()) {
|
if (mSettings->GetPrintSelectionOnly()) {
|
||||||
|
|
@ -393,7 +416,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
[self addSubview:mPrintSelectionOnlyCheckbox];
|
[self addSubview:mPrintSelectionOnlyCheckbox];
|
||||||
|
|
||||||
// "Shrink To Fit"
|
// "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;
|
bool shrinkToFit;
|
||||||
mSettings->GetShrinkToFit(&shrinkToFit);
|
mSettings->GetShrinkToFit(&shrinkToFit);
|
||||||
|
|
@ -437,33 +461,39 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
nsString sel;
|
nsString sel;
|
||||||
|
|
||||||
mSettings->GetHeaderStrLeft(sel);
|
mSettings->GetHeaderStrLeft(sel);
|
||||||
mHeaderLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22)
|
mHeaderLeftList =
|
||||||
selectedItem:sel];
|
[self headerFooterItemListWithFrame:NSMakeRect(156, 44, 100, 22)
|
||||||
|
selectedItem:sel];
|
||||||
[self addSubview:mHeaderLeftList];
|
[self addSubview:mHeaderLeftList];
|
||||||
|
|
||||||
mSettings->GetHeaderStrCenter(sel);
|
mSettings->GetHeaderStrCenter(sel);
|
||||||
mHeaderCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22)
|
mHeaderCenterList =
|
||||||
selectedItem:sel];
|
[self headerFooterItemListWithFrame:NSMakeRect(256, 44, 100, 22)
|
||||||
|
selectedItem:sel];
|
||||||
[self addSubview:mHeaderCenterList];
|
[self addSubview:mHeaderCenterList];
|
||||||
|
|
||||||
mSettings->GetHeaderStrRight(sel);
|
mSettings->GetHeaderStrRight(sel);
|
||||||
mHeaderRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 44, 100, 22)
|
mHeaderRightList =
|
||||||
selectedItem:sel];
|
[self headerFooterItemListWithFrame:NSMakeRect(356, 44, 100, 22)
|
||||||
|
selectedItem:sel];
|
||||||
[self addSubview:mHeaderRightList];
|
[self addSubview:mHeaderRightList];
|
||||||
|
|
||||||
mSettings->GetFooterStrLeft(sel);
|
mSettings->GetFooterStrLeft(sel);
|
||||||
mFooterLeftList = [self headerFooterItemListWithFrame:NSMakeRect(156, 0, 100, 22)
|
mFooterLeftList =
|
||||||
selectedItem:sel];
|
[self headerFooterItemListWithFrame:NSMakeRect(156, 0, 100, 22)
|
||||||
|
selectedItem:sel];
|
||||||
[self addSubview:mFooterLeftList];
|
[self addSubview:mFooterLeftList];
|
||||||
|
|
||||||
mSettings->GetFooterStrCenter(sel);
|
mSettings->GetFooterStrCenter(sel);
|
||||||
mFooterCenterList = [self headerFooterItemListWithFrame:NSMakeRect(256, 0, 100, 22)
|
mFooterCenterList =
|
||||||
selectedItem:sel];
|
[self headerFooterItemListWithFrame:NSMakeRect(256, 0, 100, 22)
|
||||||
|
selectedItem:sel];
|
||||||
[self addSubview:mFooterCenterList];
|
[self addSubview:mFooterCenterList];
|
||||||
|
|
||||||
mSettings->GetFooterStrRight(sel);
|
mSettings->GetFooterStrRight(sel);
|
||||||
mFooterRightList = [self headerFooterItemListWithFrame:NSMakeRect(356, 0, 100, 22)
|
mFooterRightList =
|
||||||
selectedItem:sel];
|
[self headerFooterItemListWithFrame:NSMakeRect(356, 0, 100, 22)
|
||||||
|
selectedItem:sel];
|
||||||
[self addSubview:mFooterRightList];
|
[self addSubview:mFooterRightList];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,8 +532,9 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
- (NSString*)summaryValueForCheckbox:(NSButton*)aCheckbox {
|
- (NSString*)summaryValueForCheckbox:(NSButton*)aCheckbox {
|
||||||
if (![aCheckbox isEnabled]) return [self localizedString:"summaryNAValue"];
|
if (![aCheckbox isEnabled]) return [self localizedString:"summaryNAValue"];
|
||||||
|
|
||||||
return [aCheckbox state] == NSOnState ? [self localizedString:"summaryOnValue"]
|
return [aCheckbox state] == NSOnState
|
||||||
: [self localizedString:"summaryOffValue"];
|
? [self localizedString:"summaryOnValue"]
|
||||||
|
: [self localizedString:"summaryOffValue"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString*)headerSummaryValue {
|
- (NSString*)headerSummaryValue {
|
||||||
|
|
@ -513,7 +544,8 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
stringByAppendingString:
|
stringByAppendingString:
|
||||||
[[mHeaderCenterList titleOfSelectedItem]
|
[[mHeaderCenterList titleOfSelectedItem]
|
||||||
stringByAppendingString:
|
stringByAppendingString:
|
||||||
[@", " stringByAppendingString:[mHeaderRightList titleOfSelectedItem]]]]];
|
[@", " stringByAppendingString:
|
||||||
|
[mHeaderRightList titleOfSelectedItem]]]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString*)footerSummaryValue {
|
- (NSString*)footerSummaryValue {
|
||||||
|
|
@ -523,43 +555,49 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
stringByAppendingString:
|
stringByAppendingString:
|
||||||
[[mFooterCenterList titleOfSelectedItem]
|
[[mFooterCenterList titleOfSelectedItem]
|
||||||
stringByAppendingString:
|
stringByAppendingString:
|
||||||
[@", " stringByAppendingString:[mFooterRightList titleOfSelectedItem]]]]];
|
[@", " stringByAppendingString:
|
||||||
|
[mFooterRightList titleOfSelectedItem]]]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray*)localizedSummaryItems {
|
- (NSArray*)localizedSummaryItems {
|
||||||
return [NSArray
|
return [NSArray
|
||||||
arrayWithObjects:
|
arrayWithObjects:
|
||||||
[NSDictionary
|
[NSDictionary
|
||||||
dictionaryWithObjectsAndKeys:[self localizedString:"summarySelectionOnlyTitle"],
|
dictionaryWithObjectsAndKeys:
|
||||||
NSPrintPanelAccessorySummaryItemNameKey,
|
[self localizedString:"summarySelectionOnlyTitle"],
|
||||||
[self
|
NSPrintPanelAccessorySummaryItemNameKey,
|
||||||
summaryValueForCheckbox:mPrintSelectionOnlyCheckbox],
|
[self summaryValueForCheckbox:mPrintSelectionOnlyCheckbox],
|
||||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
[self localizedString:"summaryShrinkToFitTitle"],
|
||||||
|
NSPrintPanelAccessorySummaryItemNameKey,
|
||||||
|
[self summaryValueForCheckbox:mShrinkToFitCheckbox],
|
||||||
|
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
||||||
|
nil],
|
||||||
[NSDictionary
|
[NSDictionary
|
||||||
dictionaryWithObjectsAndKeys:[self localizedString:"summaryShrinkToFitTitle"],
|
dictionaryWithObjectsAndKeys:
|
||||||
NSPrintPanelAccessorySummaryItemNameKey,
|
[self localizedString:"summaryPrintBGColorsTitle"],
|
||||||
[self summaryValueForCheckbox:mShrinkToFitCheckbox],
|
NSPrintPanelAccessorySummaryItemNameKey,
|
||||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
[self summaryValueForCheckbox:mPrintBGColorsCheckbox],
|
||||||
|
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||||
[NSDictionary
|
[NSDictionary
|
||||||
dictionaryWithObjectsAndKeys:[self localizedString:"summaryPrintBGColorsTitle"],
|
dictionaryWithObjectsAndKeys:
|
||||||
NSPrintPanelAccessorySummaryItemNameKey,
|
[self localizedString:"summaryPrintBGImagesTitle"],
|
||||||
[self summaryValueForCheckbox:mPrintBGColorsCheckbox],
|
NSPrintPanelAccessorySummaryItemNameKey,
|
||||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
[self summaryValueForCheckbox:mPrintBGImagesCheckbox],
|
||||||
[NSDictionary
|
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
||||||
dictionaryWithObjectsAndKeys:[self localizedString:"summaryPrintBGImagesTitle"],
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
NSPrintPanelAccessorySummaryItemNameKey,
|
[self localizedString:"summaryHeaderTitle"],
|
||||||
[self summaryValueForCheckbox:mPrintBGImagesCheckbox],
|
NSPrintPanelAccessorySummaryItemNameKey,
|
||||||
NSPrintPanelAccessorySummaryItemDescriptionKey, nil],
|
[self headerSummaryValue],
|
||||||
[NSDictionary dictionaryWithObjectsAndKeys:[self localizedString:"summaryHeaderTitle"],
|
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
||||||
NSPrintPanelAccessorySummaryItemNameKey,
|
nil],
|
||||||
[self headerSummaryValue],
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
[self localizedString:"summaryFooterTitle"],
|
||||||
nil],
|
NSPrintPanelAccessorySummaryItemNameKey,
|
||||||
[NSDictionary dictionaryWithObjectsAndKeys:[self localizedString:"summaryFooterTitle"],
|
[self footerSummaryValue],
|
||||||
NSPrintPanelAccessorySummaryItemNameKey,
|
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
||||||
[self footerSummaryValue],
|
nil],
|
||||||
NSPrintPanelAccessorySummaryItemDescriptionKey,
|
|
||||||
nil],
|
|
||||||
nil];
|
nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -569,11 +607,13 @@ static const char sHeaderFooterTags[][4] = {"", "&T", "&U", "&D", "&P", "&PT"};
|
||||||
|
|
||||||
@implementation PrintPanelAccessoryController
|
@implementation PrintPanelAccessoryController
|
||||||
|
|
||||||
- (id)initWithSettings:(nsIPrintSettings*)aSettings haveSelection:(bool)aHaveSelection {
|
- (id)initWithSettings:(nsIPrintSettings*)aSettings
|
||||||
|
haveSelection:(bool)aHaveSelection {
|
||||||
[super initWithNibName:nil bundle:nil];
|
[super initWithNibName:nil bundle:nil];
|
||||||
|
|
||||||
NSView* accView = [[PrintPanelAccessoryView alloc] initWithSettings:aSettings
|
NSView* accView =
|
||||||
haveSelection:aHaveSelection];
|
[[PrintPanelAccessoryView alloc] initWithSettings:aSettings
|
||||||
|
haveSelection:aHaveSelection];
|
||||||
[self setView:accView];
|
[self setView:accView];
|
||||||
[accView release];
|
[accView release];
|
||||||
return self;
|
return self;
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue