Issue #1751 -- Remove cocoa and uikit widget support code
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Modified by Josh Aas of Mozilla Corporation.
|
||||
*/
|
||||
|
||||
#ifndef ComplexTextInputPanel_h_
|
||||
#define ComplexTextInputPanel_h_
|
||||
|
||||
#include "nsString.h"
|
||||
#include "npapi.h"
|
||||
|
||||
class ComplexTextInputPanel
|
||||
{
|
||||
public:
|
||||
static ComplexTextInputPanel* GetSharedComplexTextInputPanel();
|
||||
virtual void PlacePanel(int32_t x, int32_t y) = 0; // Bottom left coordinate of plugin in screen coords
|
||||
virtual void InterpretKeyEvent(void* aEvent, nsAString& aOutText) = 0;
|
||||
virtual bool IsInComposition() = 0;
|
||||
virtual void* GetInputContext() = 0;
|
||||
virtual void CancelComposition() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~ComplexTextInputPanel() {};
|
||||
};
|
||||
|
||||
#endif // ComplexTextInputPanel_h_
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Modified by Josh Aas of Mozilla Corporation.
|
||||
*/
|
||||
|
||||
#import "ComplexTextInputPanel.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsChildView.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
extern "C" OSStatus TSMProcessRawKeyEvent(EventRef anEvent);
|
||||
|
||||
#define kInputWindowHeight 20
|
||||
|
||||
@interface ComplexTextInputPanelImpl : NSPanel {
|
||||
NSTextView *mInputTextView;
|
||||
}
|
||||
|
||||
+ (ComplexTextInputPanelImpl*)sharedComplexTextInputPanelImpl;
|
||||
|
||||
- (NSTextInputContext*)inputContext;
|
||||
- (void)interpretKeyEvent:(NSEvent*)event string:(NSString**)string;
|
||||
- (void)cancelComposition;
|
||||
- (BOOL)inComposition;
|
||||
|
||||
// This places the text input panel fully onscreen and below the lower left
|
||||
// corner of the focused plugin.
|
||||
- (void)adjustTo:(NSPoint)point;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ComplexTextInputPanelImpl
|
||||
|
||||
+ (ComplexTextInputPanelImpl*)sharedComplexTextInputPanelImpl
|
||||
{
|
||||
static ComplexTextInputPanelImpl *sComplexTextInputPanelImpl;
|
||||
if (!sComplexTextInputPanelImpl)
|
||||
sComplexTextInputPanelImpl = [[ComplexTextInputPanelImpl alloc] init];
|
||||
return sComplexTextInputPanelImpl;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
// In the original Apple code the style mask is given by a function which is not open source.
|
||||
// What could possibly be worth hiding in that function, I do not know.
|
||||
// Courtesy of gdb: stylemask: 011000011111, 0x61f
|
||||
self = [super initWithContentRect:NSZeroRect styleMask:0x61f backing:NSBackingStoreBuffered defer:YES];
|
||||
if (!self)
|
||||
return nil;
|
||||
|
||||
// Set the frame size.
|
||||
NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame];
|
||||
NSRect frame = NSMakeRect(visibleFrame.origin.x, visibleFrame.origin.y, visibleFrame.size.width, kInputWindowHeight);
|
||||
|
||||
[self setFrame:frame display:NO];
|
||||
|
||||
mInputTextView = [[NSTextView alloc] initWithFrame:[self.contentView frame]];
|
||||
mInputTextView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable | NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin;
|
||||
|
||||
NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:[self.contentView frame]];
|
||||
scrollView.documentView = mInputTextView;
|
||||
self.contentView = scrollView;
|
||||
[scrollView release];
|
||||
|
||||
[self setFloatingPanel:YES];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(keyboardInputSourceChanged:)
|
||||
name:NSTextInputContextKeyboardSelectionDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
[mInputTextView release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)keyboardInputSourceChanged:(NSNotification *)notification
|
||||
{
|
||||
static int8_t sDoCancel = -1;
|
||||
if (!sDoCancel || ![self inComposition]) {
|
||||
return;
|
||||
}
|
||||
if (sDoCancel < 0) {
|
||||
bool cancelComposition = false;
|
||||
static const char* kPrefName =
|
||||
"ui.plugin.cancel_composition_at_input_source_changed";
|
||||
nsresult rv = Preferences::GetBool(kPrefName, &cancelComposition);
|
||||
NS_ENSURE_SUCCESS(rv, );
|
||||
sDoCancel = cancelComposition ? 1 : 0;
|
||||
}
|
||||
if (sDoCancel) {
|
||||
[self cancelComposition];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)interpretKeyEvent:(NSEvent*)event string:(NSString**)string
|
||||
{
|
||||
*string = nil;
|
||||
|
||||
if (![[mInputTextView inputContext] handleEvent:event]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ([mInputTextView hasMarkedText]) {
|
||||
// Don't show the input method window for dead keys
|
||||
if ([[event characters] length] > 0) {
|
||||
[self orderFront:nil];
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
[self orderOut:nil];
|
||||
|
||||
NSString *text = [[mInputTextView textStorage] string];
|
||||
if ([text length] > 0) {
|
||||
*string = [[text copy] autorelease];
|
||||
}
|
||||
}
|
||||
|
||||
[mInputTextView setString:@""];
|
||||
}
|
||||
|
||||
- (NSTextInputContext*)inputContext
|
||||
{
|
||||
return [mInputTextView inputContext];
|
||||
}
|
||||
|
||||
- (void)cancelComposition
|
||||
{
|
||||
[mInputTextView setString:@""];
|
||||
[self orderOut:nil];
|
||||
}
|
||||
|
||||
- (BOOL)inComposition
|
||||
{
|
||||
return [mInputTextView hasMarkedText];
|
||||
}
|
||||
|
||||
- (void)adjustTo:(NSPoint)point
|
||||
{
|
||||
NSRect selfRect = [self frame];
|
||||
NSRect rect = NSMakeRect(point.x,
|
||||
point.y - selfRect.size.height,
|
||||
500,
|
||||
selfRect.size.height);
|
||||
|
||||
// Adjust to screen.
|
||||
NSRect screenRect = [[NSScreen mainScreen] visibleFrame];
|
||||
if (rect.origin.x < screenRect.origin.x) {
|
||||
rect.origin.x = screenRect.origin.x;
|
||||
}
|
||||
if (rect.origin.y < screenRect.origin.y) {
|
||||
rect.origin.y = screenRect.origin.y;
|
||||
}
|
||||
CGFloat xMostOfScreen = screenRect.origin.x + screenRect.size.width;
|
||||
CGFloat yMostOfScreen = screenRect.origin.y + screenRect.size.height;
|
||||
CGFloat xMost = rect.origin.x + rect.size.width;
|
||||
CGFloat yMost = rect.origin.y + rect.size.height;
|
||||
if (xMostOfScreen < xMost) {
|
||||
rect.origin.x -= xMost - xMostOfScreen;
|
||||
}
|
||||
if (yMostOfScreen < yMost) {
|
||||
rect.origin.y -= yMost - yMostOfScreen;
|
||||
}
|
||||
|
||||
[self setFrame:rect display:[self isVisible]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
class ComplexTextInputPanelPrivate : public ComplexTextInputPanel
|
||||
{
|
||||
public:
|
||||
ComplexTextInputPanelPrivate();
|
||||
|
||||
virtual void InterpretKeyEvent(void* aEvent, nsAString& aOutText);
|
||||
virtual bool IsInComposition();
|
||||
virtual void PlacePanel(int32_t x, int32_t y);
|
||||
virtual void* GetInputContext() { return [mPanel inputContext]; }
|
||||
virtual void CancelComposition() { [mPanel cancelComposition]; }
|
||||
|
||||
private:
|
||||
~ComplexTextInputPanelPrivate();
|
||||
ComplexTextInputPanelImpl* mPanel;
|
||||
};
|
||||
|
||||
ComplexTextInputPanelPrivate::ComplexTextInputPanelPrivate()
|
||||
{
|
||||
mPanel = [[ComplexTextInputPanelImpl alloc] init];
|
||||
}
|
||||
|
||||
ComplexTextInputPanelPrivate::~ComplexTextInputPanelPrivate()
|
||||
{
|
||||
[mPanel release];
|
||||
}
|
||||
|
||||
ComplexTextInputPanel*
|
||||
ComplexTextInputPanel::GetSharedComplexTextInputPanel()
|
||||
{
|
||||
static ComplexTextInputPanelPrivate *sComplexTextInputPanelPrivate;
|
||||
if (!sComplexTextInputPanelPrivate) {
|
||||
sComplexTextInputPanelPrivate = new ComplexTextInputPanelPrivate();
|
||||
}
|
||||
return sComplexTextInputPanelPrivate;
|
||||
}
|
||||
|
||||
void
|
||||
ComplexTextInputPanelPrivate::InterpretKeyEvent(void* aEvent, nsAString& aOutText)
|
||||
{
|
||||
NSString* textString = nil;
|
||||
[mPanel interpretKeyEvent:(NSEvent*)aEvent string:&textString];
|
||||
|
||||
if (textString) {
|
||||
nsCocoaUtils::GetStringForNSString(textString, aOutText);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ComplexTextInputPanelPrivate::IsInComposition()
|
||||
{
|
||||
return !![mPanel inComposition];
|
||||
}
|
||||
|
||||
void
|
||||
ComplexTextInputPanelPrivate::PlacePanel(int32_t x, int32_t y)
|
||||
{
|
||||
[mPanel adjustTo:NSMakePoint(x, y)];
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* This file defines constants to be used in the "subtype" field of
|
||||
* NSApplicationDefined type NSEvents.
|
||||
*/
|
||||
|
||||
#ifndef WIDGET_COCOA_CUSTOMCOCOAEVENTS_H_
|
||||
#define WIDGET_COCOA_CUSTOMCOCOAEVENTS_H_
|
||||
|
||||
// Empty event, just used for prodding the event loop into responding.
|
||||
const short kEventSubtypeNone = 0;
|
||||
// Tracer event, used for timing the event loop responsiveness.
|
||||
const short kEventSubtypeTrace = 1;
|
||||
|
||||
#endif /* WIDGET_COCOA_CUSTOMCOCOAEVENTS_H_ */
|
||||
@@ -1,95 +0,0 @@
|
||||
/* vim: se cin sw=2 ts=2 et : */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __mozilla_widget_GfxInfo_h__
|
||||
#define __mozilla_widget_GfxInfo_h__
|
||||
|
||||
#include "GfxInfoBase.h"
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class GfxInfo : public GfxInfoBase
|
||||
{
|
||||
public:
|
||||
|
||||
GfxInfo();
|
||||
// We only declare the subset of nsIGfxInfo that we actually implement. The
|
||||
// rest is brought forward from GfxInfoBase.
|
||||
NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled) override;
|
||||
NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled) override;
|
||||
NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion) override;
|
||||
NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams) override;
|
||||
NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription) override;
|
||||
NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver) override;
|
||||
NS_IMETHOD GetAdapterVendorID(nsAString & aAdapterVendorID) override;
|
||||
NS_IMETHOD GetAdapterDeviceID(nsAString & aAdapterDeviceID) override;
|
||||
NS_IMETHOD GetAdapterSubsysID(nsAString & aAdapterSubsysID) override;
|
||||
NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM) override;
|
||||
NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) override;
|
||||
NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate) override;
|
||||
NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription) override;
|
||||
NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver) override;
|
||||
NS_IMETHOD GetAdapterVendorID2(nsAString & aAdapterVendorID) override;
|
||||
NS_IMETHOD GetAdapterDeviceID2(nsAString & aAdapterDeviceID) override;
|
||||
NS_IMETHOD GetAdapterSubsysID2(nsAString & aAdapterSubsysID) override;
|
||||
NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM) override;
|
||||
NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) override;
|
||||
NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate) override;
|
||||
NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active) override;
|
||||
|
||||
using GfxInfoBase::GetFeatureStatus;
|
||||
using GfxInfoBase::GetFeatureSuggestedDriverVersion;
|
||||
using GfxInfoBase::GetWebGLParameter;
|
||||
|
||||
virtual nsresult Init() override;
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIGFXINFODEBUG
|
||||
#endif
|
||||
|
||||
virtual uint32_t OperatingSystemVersion() override { return mOSXVersion; }
|
||||
|
||||
nsresult FindMonitors(JSContext* cx, JS::HandleObject array) override;
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~GfxInfo() {}
|
||||
|
||||
virtual nsresult GetFeatureStatusImpl(int32_t aFeature,
|
||||
int32_t *aStatus,
|
||||
nsAString & aSuggestedDriverVersion,
|
||||
const nsTArray<GfxDriverInfo>& aDriverInfo,
|
||||
nsACString &aFailureId,
|
||||
OperatingSystem* aOS = nullptr) override;
|
||||
virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
|
||||
|
||||
private:
|
||||
|
||||
void GetDeviceInfo();
|
||||
void GetSelectedCityInfo();
|
||||
void AddCrashReportAnnotations();
|
||||
|
||||
nsString mAdapterRAMString;
|
||||
nsString mDeviceID;
|
||||
nsString mDriverVersion;
|
||||
nsString mDriverDate;
|
||||
nsString mDeviceKey;
|
||||
|
||||
nsString mAdapterVendorID;
|
||||
nsString mAdapterDeviceID;
|
||||
|
||||
uint32_t mOSXVersion;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __mozilla_widget_GfxInfo_h__ */
|
||||
@@ -1,426 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/CGLRenderers.h>
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "GfxInfo.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include <algorithm>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <IOKit/IOKitLib.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
|
||||
#endif
|
||||
|
||||
GfxInfo::GfxInfo()
|
||||
{
|
||||
}
|
||||
|
||||
static OperatingSystem
|
||||
OSXVersionToOperatingSystem(uint32_t aOSXVersion) {
|
||||
switch (nsCocoaFeatures::ExtractMajorVersion(aOSXVersion)) {
|
||||
case 10:
|
||||
switch (nsCocoaFeatures::ExtractMinorVersion(aOSXVersion)) {
|
||||
case 6:
|
||||
return OperatingSystem::OSX10_6;
|
||||
case 7:
|
||||
return OperatingSystem::OSX10_7;
|
||||
case 8:
|
||||
return OperatingSystem::OSX10_8;
|
||||
case 9:
|
||||
return OperatingSystem::OSX10_9;
|
||||
case 10:
|
||||
return OperatingSystem::OSX10_10;
|
||||
case 11:
|
||||
return OperatingSystem::OSX10_11;
|
||||
case 12:
|
||||
return OperatingSystem::OSX10_12;
|
||||
case 13:
|
||||
return OperatingSystem::OSX10_13;
|
||||
case 14:
|
||||
return OperatingSystem::OSX10_14;
|
||||
case 15:
|
||||
return OperatingSystem::OSX10_15;
|
||||
case 16:
|
||||
// Depending on the SDK version, we either get 10.16 or 11.0.
|
||||
// Normalize this to 11.0.
|
||||
return OperatingSystem::OSX11_0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
switch (nsCocoaFeatures::ExtractMinorVersion(aOSXVersion)) {
|
||||
case 0:
|
||||
return OperatingSystem::OSX11_0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return OperatingSystem::Unknown;
|
||||
}
|
||||
// The following three functions are derived from Chromium code
|
||||
static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort,
|
||||
CFStringRef propertyName)
|
||||
{
|
||||
return IORegistryEntrySearchCFProperty(dspPort,
|
||||
kIOServicePlane,
|
||||
propertyName,
|
||||
kCFAllocatorDefault,
|
||||
kIORegistryIterateRecursively |
|
||||
kIORegistryIterateParents);
|
||||
}
|
||||
|
||||
static uint32_t IntValueOfCFData(CFDataRef d)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
|
||||
if (d) {
|
||||
const uint32_t *vp = reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(d));
|
||||
if (vp != NULL)
|
||||
value = *vp;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
GfxInfo::GetDeviceInfo()
|
||||
{
|
||||
io_registry_entry_t dsp_port = CGDisplayIOServicePort(kCGDirectMainDisplay);
|
||||
CFTypeRef vendor_id_ref = SearchPortForProperty(dsp_port, CFSTR("vendor-id"));
|
||||
if (vendor_id_ref) {
|
||||
mAdapterVendorID.AppendPrintf("0x%04x", IntValueOfCFData((CFDataRef)vendor_id_ref));
|
||||
CFRelease(vendor_id_ref);
|
||||
}
|
||||
CFTypeRef device_id_ref = SearchPortForProperty(dsp_port, CFSTR("device-id"));
|
||||
if (device_id_ref) {
|
||||
mAdapterDeviceID.AppendPrintf("0x%04x", IntValueOfCFData((CFDataRef)device_id_ref));
|
||||
CFRelease(device_id_ref);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GfxInfo::Init()
|
||||
{
|
||||
nsresult rv = GfxInfoBase::Init();
|
||||
|
||||
// Calling CGLQueryRendererInfo causes us to switch to the discrete GPU
|
||||
// even when we don't want to. We'll avoid doing so for now and just
|
||||
// use the device ids.
|
||||
|
||||
GetDeviceInfo();
|
||||
|
||||
AddCrashReportAnnotations();
|
||||
|
||||
mOSXVersion = nsCocoaFeatures::macOSVersion();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetD2DEnabled(bool *aEnabled)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetDWriteEnabled(bool *aEnabled)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString DWriteVersion; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString cleartypeParameters; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDescription; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
|
||||
{
|
||||
aAdapterDescription.AssignLiteral("");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDescription2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterRAM; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
|
||||
{
|
||||
aAdapterRAM = mAdapterRAMString;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterRAM2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDriver; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
|
||||
{
|
||||
aAdapterDriver.AssignLiteral("");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDriver2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDriverVersion; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
|
||||
{
|
||||
aAdapterDriverVersion.AssignLiteral("");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDriverVersion2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDriverDate; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
|
||||
{
|
||||
aAdapterDriverDate.AssignLiteral("");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDriverDate2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterVendorID; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID)
|
||||
{
|
||||
aAdapterVendorID = mAdapterVendorID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterVendorID2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDeviceID; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID)
|
||||
{
|
||||
aAdapterDeviceID = mAdapterDeviceID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterDeviceID2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterSubsysID; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterSubsysID(nsAString & aAdapterSubsysID)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute DOMString adapterSubsysID2; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterSubsysID2(nsAString & aAdapterSubsysID)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean isGPU2Active; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
GfxInfo::AddCrashReportAnnotations()
|
||||
{
|
||||
/*** STUB ***/
|
||||
}
|
||||
|
||||
// We don't support checking driver versions on Mac.
|
||||
#define IMPLEMENT_MAC_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn, ruleId) \
|
||||
APPEND_TO_DRIVER_BLOCKLIST(os, vendor, device, features, blockOn, \
|
||||
DRIVER_COMPARISON_IGNORED, V(0,0,0,0), ruleId, "")
|
||||
|
||||
|
||||
const nsTArray<GfxDriverInfo>&
|
||||
GfxInfo::GetGfxDriverInfo()
|
||||
{
|
||||
if (!mDriverInfo->Length()) {
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX,
|
||||
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices,
|
||||
nsIGfxInfo::FEATURE_WEBGL_MSAA, nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION, "FEATURE_FAILURE_MAC_ATI_NO_MSAA");
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX,
|
||||
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(RadeonX1000),
|
||||
nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_RADEONX1000_NO_TEXTURE2D");
|
||||
IMPLEMENT_MAC_DRIVER_BLOCKLIST(OperatingSystem::OSX,
|
||||
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(Geforce7300GT),
|
||||
nsIGfxInfo::FEATURE_WEBGL_OPENGL, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, "FEATURE_FAILURE_MAC_7300_NO_WEBGL");
|
||||
}
|
||||
return *mDriverInfo;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GfxInfo::GetFeatureStatusImpl(int32_t aFeature,
|
||||
int32_t* aStatus,
|
||||
nsAString& aSuggestedDriverVersion,
|
||||
const nsTArray<GfxDriverInfo>& aDriverInfo,
|
||||
nsACString& aFailureId,
|
||||
OperatingSystem* aOS /* = nullptr */)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aStatus);
|
||||
aSuggestedDriverVersion.SetIsVoid(true);
|
||||
*aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
|
||||
OperatingSystem os = OSXVersionToOperatingSystem(mOSXVersion);
|
||||
if (aOS)
|
||||
*aOS = os;
|
||||
|
||||
if (mShutdownOccurred) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Don't evaluate special cases when we're evaluating the downloaded blocklist.
|
||||
if (!aDriverInfo.Length()) {
|
||||
if (aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA) {
|
||||
// Blacklist all ATI cards on OSX, except for
|
||||
// 0x6760 and 0x9488
|
||||
if (mAdapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorATI), nsCaseInsensitiveStringComparator()) &&
|
||||
(mAdapterDeviceID.LowerCaseEqualsLiteral("0x6760") ||
|
||||
mAdapterDeviceID.LowerCaseEqualsLiteral("0x9488"))) {
|
||||
*aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
|
||||
// See bug 1249659
|
||||
switch(os) {
|
||||
case OperatingSystem::OSX10_5:
|
||||
case OperatingSystem::OSX10_6:
|
||||
case OperatingSystem::OSX10_7:
|
||||
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
|
||||
aFailureId = "FEATURE_FAILURE_CANVAS_OSX_VERSION";
|
||||
break;
|
||||
default:
|
||||
*aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GfxInfo::FindMonitors(JSContext* aCx, JS::HandleObject aOutArray)
|
||||
{
|
||||
// Getting the refresh rate is a little hard on OS X. We could use
|
||||
// CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little
|
||||
// involved. Ideally we could query it from vsync. For now, we leave it out.
|
||||
int32_t deviceCount = 0;
|
||||
for (NSScreen* screen in [NSScreen screens]) {
|
||||
NSRect rect = [screen frame];
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
|
||||
|
||||
JS::Rooted<JS::Value> screenWidth(aCx, JS::Int32Value((int)rect.size.width));
|
||||
JS_SetProperty(aCx, obj, "screenWidth", screenWidth);
|
||||
|
||||
JS::Rooted<JS::Value> screenHeight(aCx, JS::Int32Value((int)rect.size.height));
|
||||
JS_SetProperty(aCx, obj, "screenHeight", screenHeight);
|
||||
|
||||
JS::Rooted<JS::Value> scale(aCx, JS::NumberValue(nsCocoaUtils::GetBackingScaleFactor(screen)));
|
||||
JS_SetProperty(aCx, obj, "scale", scale);
|
||||
|
||||
JS::Rooted<JS::Value> element(aCx, JS::ObjectValue(*obj));
|
||||
JS_SetElement(aCx, aOutArray, deviceCount++, element);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
// Implement nsIGfxInfoDebug
|
||||
|
||||
/* void spoofVendorID (in DOMString aVendorID); */
|
||||
NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID)
|
||||
{
|
||||
mAdapterVendorID = aVendorID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void spoofDeviceID (in unsigned long aDeviceID); */
|
||||
NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString & aDeviceID)
|
||||
{
|
||||
mAdapterDeviceID = aDeviceID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void spoofDriverVersion (in DOMString aDriverVersion); */
|
||||
NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString & aDriverVersion)
|
||||
{
|
||||
mDriverVersion = aDriverVersion;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void spoofOSVersion (in unsigned long aVersion); */
|
||||
NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion)
|
||||
{
|
||||
mOSXVersion = aVersion;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_widget_NativeKeyBindings_h_
|
||||
#define mozilla_widget_NativeKeyBindings_h_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIWidget.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
typedef nsDataHashtable<nsPtrHashKey<struct objc_selector>, CommandInt>
|
||||
SelectorCommandHashtable;
|
||||
|
||||
class NativeKeyBindings final
|
||||
{
|
||||
typedef nsIWidget::NativeKeyBindingsType NativeKeyBindingsType;
|
||||
typedef nsIWidget::DoCommandCallback DoCommandCallback;
|
||||
|
||||
public:
|
||||
static NativeKeyBindings* GetInstance(NativeKeyBindingsType aType);
|
||||
static void Shutdown();
|
||||
|
||||
void Init(NativeKeyBindingsType aType);
|
||||
|
||||
bool Execute(const WidgetKeyboardEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
private:
|
||||
NativeKeyBindings();
|
||||
|
||||
SelectorCommandHashtable mSelectorToCommand;
|
||||
|
||||
static NativeKeyBindings* sInstanceForSingleLineEditor;
|
||||
static NativeKeyBindings* sInstanceForMultiLineEditor;
|
||||
}; // NativeKeyBindings
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_widget_NativeKeyBindings_h_
|
||||
@@ -1,292 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "NativeKeyBindings.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
PRLogModuleInfo* gNativeKeyBindingsLog = nullptr;
|
||||
|
||||
NativeKeyBindings* NativeKeyBindings::sInstanceForSingleLineEditor = nullptr;
|
||||
NativeKeyBindings* NativeKeyBindings::sInstanceForMultiLineEditor = nullptr;
|
||||
|
||||
// static
|
||||
NativeKeyBindings*
|
||||
NativeKeyBindings::GetInstance(NativeKeyBindingsType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case nsIWidget::NativeKeyBindingsForSingleLineEditor:
|
||||
if (!sInstanceForSingleLineEditor) {
|
||||
sInstanceForSingleLineEditor = new NativeKeyBindings();
|
||||
sInstanceForSingleLineEditor->Init(aType);
|
||||
}
|
||||
return sInstanceForSingleLineEditor;
|
||||
case nsIWidget::NativeKeyBindingsForMultiLineEditor:
|
||||
case nsIWidget::NativeKeyBindingsForRichTextEditor:
|
||||
if (!sInstanceForMultiLineEditor) {
|
||||
sInstanceForMultiLineEditor = new NativeKeyBindings();
|
||||
sInstanceForMultiLineEditor->Init(aType);
|
||||
}
|
||||
return sInstanceForMultiLineEditor;
|
||||
default:
|
||||
MOZ_CRASH("Not implemented");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
NativeKeyBindings::Shutdown()
|
||||
{
|
||||
delete sInstanceForSingleLineEditor;
|
||||
sInstanceForSingleLineEditor = nullptr;
|
||||
delete sInstanceForMultiLineEditor;
|
||||
sInstanceForMultiLineEditor = nullptr;
|
||||
}
|
||||
|
||||
NativeKeyBindings::NativeKeyBindings()
|
||||
{
|
||||
}
|
||||
|
||||
#define SEL_TO_COMMAND(aSel, aCommand) \
|
||||
mSelectorToCommand.Put( \
|
||||
reinterpret_cast<struct objc_selector *>(@selector(aSel)), aCommand)
|
||||
|
||||
void
|
||||
NativeKeyBindings::Init(NativeKeyBindingsType aType)
|
||||
{
|
||||
if (!gNativeKeyBindingsLog) {
|
||||
gNativeKeyBindingsLog = PR_NewLogModule("NativeKeyBindings");
|
||||
}
|
||||
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::Init", this));
|
||||
|
||||
// Many selectors have a one-to-one mapping to a Gecko command. Those mappings
|
||||
// are registered in mSelectorToCommand.
|
||||
|
||||
// Selectors from NSResponder's "Responding to Action Messages" section and
|
||||
// from NSText's "Action Methods for Editing" section
|
||||
|
||||
// TODO: Improves correctness of left / right meaning
|
||||
// TODO: Add real paragraph motions
|
||||
|
||||
// SEL_TO_COMMAND(cancelOperation:, );
|
||||
// SEL_TO_COMMAND(capitalizeWord:, );
|
||||
// SEL_TO_COMMAND(centerSelectionInVisibleArea:, );
|
||||
// SEL_TO_COMMAND(changeCaseOfLetter:, );
|
||||
// SEL_TO_COMMAND(complete:, );
|
||||
SEL_TO_COMMAND(copy:, CommandCopy);
|
||||
// SEL_TO_COMMAND(copyFont:, );
|
||||
// SEL_TO_COMMAND(copyRuler:, );
|
||||
SEL_TO_COMMAND(cut:, CommandCut);
|
||||
SEL_TO_COMMAND(delete:, CommandDelete);
|
||||
SEL_TO_COMMAND(deleteBackward:, CommandDeleteCharBackward);
|
||||
// SEL_TO_COMMAND(deleteBackwardByDecomposingPreviousCharacter:, );
|
||||
SEL_TO_COMMAND(deleteForward:, CommandDeleteCharForward);
|
||||
|
||||
// TODO: deleteTo* selectors are also supposed to add text to a kill buffer
|
||||
SEL_TO_COMMAND(deleteToBeginningOfLine:, CommandDeleteToBeginningOfLine);
|
||||
SEL_TO_COMMAND(deleteToBeginningOfParagraph:, CommandDeleteToBeginningOfLine);
|
||||
SEL_TO_COMMAND(deleteToEndOfLine:, CommandDeleteToEndOfLine);
|
||||
SEL_TO_COMMAND(deleteToEndOfParagraph:, CommandDeleteToEndOfLine);
|
||||
// SEL_TO_COMMAND(deleteToMark:, );
|
||||
|
||||
SEL_TO_COMMAND(deleteWordBackward:, CommandDeleteWordBackward);
|
||||
SEL_TO_COMMAND(deleteWordForward:, CommandDeleteWordForward);
|
||||
// SEL_TO_COMMAND(indent:, );
|
||||
// SEL_TO_COMMAND(insertBacktab:, );
|
||||
// SEL_TO_COMMAND(insertContainerBreak:, );
|
||||
// SEL_TO_COMMAND(insertLineBreak:, );
|
||||
// SEL_TO_COMMAND(insertNewline:, );
|
||||
// SEL_TO_COMMAND(insertNewlineIgnoringFieldEditor:, );
|
||||
// SEL_TO_COMMAND(insertParagraphSeparator:, );
|
||||
// SEL_TO_COMMAND(insertTab:, );
|
||||
// SEL_TO_COMMAND(insertTabIgnoringFieldEditor:, );
|
||||
// SEL_TO_COMMAND(insertDoubleQuoteIgnoringSubstitution:, );
|
||||
// SEL_TO_COMMAND(insertSingleQuoteIgnoringSubstitution:, );
|
||||
// SEL_TO_COMMAND(lowercaseWord:, );
|
||||
SEL_TO_COMMAND(moveBackward:, CommandCharPrevious);
|
||||
SEL_TO_COMMAND(moveBackwardAndModifySelection:, CommandSelectCharPrevious);
|
||||
if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
|
||||
SEL_TO_COMMAND(moveDown:, CommandEndLine);
|
||||
} else {
|
||||
SEL_TO_COMMAND(moveDown:, CommandLineNext);
|
||||
}
|
||||
SEL_TO_COMMAND(moveDownAndModifySelection:, CommandSelectLineNext);
|
||||
SEL_TO_COMMAND(moveForward:, CommandCharNext);
|
||||
SEL_TO_COMMAND(moveForwardAndModifySelection:, CommandSelectCharNext);
|
||||
SEL_TO_COMMAND(moveLeft:, CommandCharPrevious);
|
||||
SEL_TO_COMMAND(moveLeftAndModifySelection:, CommandSelectCharPrevious);
|
||||
SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
|
||||
CommandSelectBeginLine);
|
||||
SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, CommandSelectEndLine);
|
||||
SEL_TO_COMMAND(moveRight:, CommandCharNext);
|
||||
SEL_TO_COMMAND(moveRightAndModifySelection:, CommandSelectCharNext);
|
||||
SEL_TO_COMMAND(moveToBeginningOfDocument:, CommandMoveTop);
|
||||
SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:,
|
||||
CommandSelectTop);
|
||||
SEL_TO_COMMAND(moveToBeginningOfLine:, CommandBeginLine);
|
||||
SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
|
||||
CommandSelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToBeginningOfParagraph:, CommandBeginLine);
|
||||
SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:,
|
||||
CommandSelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToEndOfDocument:, CommandMoveBottom);
|
||||
SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, CommandSelectBottom);
|
||||
SEL_TO_COMMAND(moveToEndOfLine:, CommandEndLine);
|
||||
SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, CommandSelectEndLine);
|
||||
SEL_TO_COMMAND(moveToEndOfParagraph:, CommandEndLine);
|
||||
SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, CommandSelectEndLine);
|
||||
SEL_TO_COMMAND(moveToLeftEndOfLine:, CommandBeginLine);
|
||||
SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:,
|
||||
CommandSelectBeginLine);
|
||||
SEL_TO_COMMAND(moveToRightEndOfLine:, CommandEndLine);
|
||||
SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, CommandSelectEndLine);
|
||||
if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
|
||||
SEL_TO_COMMAND(moveUp:, CommandBeginLine);
|
||||
} else {
|
||||
SEL_TO_COMMAND(moveUp:, CommandLinePrevious);
|
||||
}
|
||||
SEL_TO_COMMAND(moveUpAndModifySelection:, CommandSelectLinePrevious);
|
||||
SEL_TO_COMMAND(moveWordBackward:, CommandWordPrevious);
|
||||
SEL_TO_COMMAND(moveWordBackwardAndModifySelection:,
|
||||
CommandSelectWordPrevious);
|
||||
SEL_TO_COMMAND(moveWordForward:, CommandWordNext);
|
||||
SEL_TO_COMMAND(moveWordForwardAndModifySelection:, CommandSelectWordNext);
|
||||
SEL_TO_COMMAND(moveWordLeft:, CommandWordPrevious);
|
||||
SEL_TO_COMMAND(moveWordLeftAndModifySelection:, CommandSelectWordPrevious);
|
||||
SEL_TO_COMMAND(moveWordRight:, CommandWordNext);
|
||||
SEL_TO_COMMAND(moveWordRightAndModifySelection:, CommandSelectWordNext);
|
||||
SEL_TO_COMMAND(pageDown:, CommandMovePageDown);
|
||||
SEL_TO_COMMAND(pageDownAndModifySelection:, CommandSelectPageDown);
|
||||
SEL_TO_COMMAND(pageUp:, CommandMovePageUp);
|
||||
SEL_TO_COMMAND(pageUpAndModifySelection:, CommandSelectPageUp);
|
||||
SEL_TO_COMMAND(paste:, CommandPaste);
|
||||
// SEL_TO_COMMAND(pasteFont:, );
|
||||
// SEL_TO_COMMAND(pasteRuler:, );
|
||||
SEL_TO_COMMAND(scrollLineDown:, CommandScrollLineDown);
|
||||
SEL_TO_COMMAND(scrollLineUp:, CommandScrollLineUp);
|
||||
SEL_TO_COMMAND(scrollPageDown:, CommandScrollPageDown);
|
||||
SEL_TO_COMMAND(scrollPageUp:, CommandScrollPageUp);
|
||||
SEL_TO_COMMAND(scrollToBeginningOfDocument:, CommandScrollTop);
|
||||
SEL_TO_COMMAND(scrollToEndOfDocument:, CommandScrollBottom);
|
||||
SEL_TO_COMMAND(selectAll:, CommandSelectAll);
|
||||
// selectLine: is complex, see KeyDown
|
||||
if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
|
||||
SEL_TO_COMMAND(selectParagraph:, CommandSelectAll);
|
||||
}
|
||||
// SEL_TO_COMMAND(selectToMark:, );
|
||||
// selectWord: is complex, see KeyDown
|
||||
// SEL_TO_COMMAND(setMark:, );
|
||||
// SEL_TO_COMMAND(showContextHelp:, );
|
||||
// SEL_TO_COMMAND(supplementalTargetForAction:sender:, );
|
||||
// SEL_TO_COMMAND(swapWithMark:, );
|
||||
// SEL_TO_COMMAND(transpose:, );
|
||||
// SEL_TO_COMMAND(transposeWords:, );
|
||||
// SEL_TO_COMMAND(uppercaseWord:, );
|
||||
// SEL_TO_COMMAND(yank:, );
|
||||
}
|
||||
|
||||
#undef SEL_TO_COMMAND
|
||||
|
||||
bool
|
||||
NativeKeyBindings::Execute(const WidgetKeyboardEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void* aCallbackData)
|
||||
{
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::KeyPress", this));
|
||||
|
||||
// Recover the current event, which should always be the key down we are
|
||||
// responding to.
|
||||
|
||||
NSEvent* cocoaEvent = reinterpret_cast<NSEvent*>(aEvent.mNativeKeyEvent);
|
||||
|
||||
if (!cocoaEvent || [cocoaEvent type] != NSKeyDown) {
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::KeyPress, no Cocoa key down event", this));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::KeyPress, interpreting", this));
|
||||
|
||||
AutoTArray<KeyBindingsCommand, 2> bindingCommands;
|
||||
nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands);
|
||||
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::KeyPress, bindingCommands=%u",
|
||||
this, bindingCommands.Length()));
|
||||
|
||||
AutoTArray<Command, 4> geckoCommands;
|
||||
|
||||
for (uint32_t i = 0; i < bindingCommands.Length(); i++) {
|
||||
SEL selector = bindingCommands[i].selector;
|
||||
|
||||
if (MOZ_LOG_TEST(gNativeKeyBindingsLog, LogLevel::Info)) {
|
||||
NSString* selectorString = NSStringFromSelector(selector);
|
||||
nsAutoString nsSelectorString;
|
||||
nsCocoaUtils::GetStringForNSString(selectorString, nsSelectorString);
|
||||
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::KeyPress, selector=%s",
|
||||
this, NS_LossyConvertUTF16toASCII(nsSelectorString).get()));
|
||||
}
|
||||
|
||||
// Try to find a simple mapping in the hashtable
|
||||
Command geckoCommand = static_cast<Command>(mSelectorToCommand.Get(
|
||||
reinterpret_cast<struct objc_selector*>(selector)));
|
||||
|
||||
if (geckoCommand) {
|
||||
geckoCommands.AppendElement(geckoCommand);
|
||||
} else if (selector == @selector(selectLine:)) {
|
||||
// This is functional, but Cocoa's version is direction-less in that
|
||||
// selection direction is not determined until some future directed action
|
||||
// is taken. See bug 282097, comment 79 for more details.
|
||||
geckoCommands.AppendElement(CommandBeginLine);
|
||||
geckoCommands.AppendElement(CommandSelectEndLine);
|
||||
} else if (selector == @selector(selectWord:)) {
|
||||
// This is functional, but Cocoa's version is direction-less in that
|
||||
// selection direction is not determined until some future directed action
|
||||
// is taken. See bug 282097, comment 79 for more details.
|
||||
geckoCommands.AppendElement(CommandWordPrevious);
|
||||
geckoCommands.AppendElement(CommandSelectWordNext);
|
||||
}
|
||||
}
|
||||
|
||||
if (geckoCommands.IsEmpty()) {
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::KeyPress, handled=false", this));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < geckoCommands.Length(); i++) {
|
||||
Command geckoCommand = geckoCommands[i];
|
||||
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::KeyPress, command=%s",
|
||||
this, WidgetKeyboardEvent::GetCommandStr(geckoCommand)));
|
||||
|
||||
// Execute the Gecko command
|
||||
aCallback(geckoCommand, aCallbackData);
|
||||
}
|
||||
|
||||
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
||||
("%p NativeKeyBindings::KeyPress, handled=true", this));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
@@ -1,55 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef OSXNotificationCenter_h
|
||||
#define OSXNotificationCenter_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "nsIAlertsService.h"
|
||||
#include "imgINotificationObserver.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
@class mozNotificationCenterDelegate;
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_8) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8)
|
||||
typedef NSInteger NSUserNotificationActivationType;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class OSXNotificationInfo;
|
||||
|
||||
class OSXNotificationCenter : public nsIAlertsService,
|
||||
public nsIAlertsIconData,
|
||||
public nsIAlertNotificationImageListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIALERTSSERVICE
|
||||
NS_DECL_NSIALERTSICONDATA
|
||||
NS_DECL_NSIALERTNOTIFICATIONIMAGELISTENER
|
||||
|
||||
OSXNotificationCenter();
|
||||
|
||||
nsresult Init();
|
||||
void CloseAlertCocoaString(NSString *aAlertName);
|
||||
void OnActivate(NSString *aAlertName, NSUserNotificationActivationType aActivationType,
|
||||
unsigned long long aAdditionalActionIndex);
|
||||
void ShowPendingNotification(OSXNotificationInfo *osxni);
|
||||
|
||||
protected:
|
||||
virtual ~OSXNotificationCenter();
|
||||
|
||||
private:
|
||||
mozNotificationCenterDelegate *mDelegate;
|
||||
nsTArray<RefPtr<OSXNotificationInfo> > mActiveAlerts;
|
||||
nsTArray<RefPtr<OSXNotificationInfo> > mPendingAlerts;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // OSXNotificationCenter_h
|
||||
@@ -1,589 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "OSXNotificationCenter.h"
|
||||
#import <AppKit/AppKit.h>
|
||||
#include "imgIRequest.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsNetUtil.h"
|
||||
#import "nsCocoaUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#define MAX_NOTIFICATION_NAME_LEN 5000
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_8) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8)
|
||||
@protocol NSUserNotificationCenterDelegate
|
||||
@end
|
||||
static NSString * const NSUserNotificationDefaultSoundName = @"DefaultSoundName";
|
||||
enum {
|
||||
NSUserNotificationActivationTypeNone = 0,
|
||||
NSUserNotificationActivationTypeContentsClicked = 1,
|
||||
NSUserNotificationActivationTypeActionButtonClicked = 2,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_9) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9)
|
||||
enum {
|
||||
NSUserNotificationActivationTypeReplied = 3,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_10) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10)
|
||||
enum {
|
||||
NSUserNotificationActivationTypeAdditionalActionClicked = 4
|
||||
};
|
||||
#endif
|
||||
|
||||
@protocol FakeNSUserNotification <NSObject>
|
||||
@property (copy) NSString* title;
|
||||
@property (copy) NSString* subtitle;
|
||||
@property (copy) NSString* informativeText;
|
||||
@property (copy) NSString* actionButtonTitle;
|
||||
@property (copy) NSDictionary* userInfo;
|
||||
@property (copy) NSDate* deliveryDate;
|
||||
@property (copy) NSTimeZone* deliveryTimeZone;
|
||||
@property (copy) NSDateComponents* deliveryRepeatInterval;
|
||||
@property (readonly) NSDate* actualDeliveryDate;
|
||||
@property (readonly, getter=isPresented) BOOL presented;
|
||||
@property (readonly, getter=isRemote) BOOL remote;
|
||||
@property (copy) NSString* soundName;
|
||||
@property BOOL hasActionButton;
|
||||
@property (readonly) NSUserNotificationActivationType activationType;
|
||||
@property (copy) NSString *otherButtonTitle;
|
||||
@property (copy) NSImage *contentImage;
|
||||
@end
|
||||
|
||||
@protocol FakeNSUserNotificationCenter <NSObject>
|
||||
+ (id<FakeNSUserNotificationCenter>)defaultUserNotificationCenter;
|
||||
@property (assign) id <NSUserNotificationCenterDelegate> delegate;
|
||||
@property (copy) NSArray *scheduledNotifications;
|
||||
- (void)scheduleNotification:(id<FakeNSUserNotification>)notification;
|
||||
- (void)removeScheduledNotification:(id<FakeNSUserNotification>)notification;
|
||||
@property (readonly) NSArray *deliveredNotifications;
|
||||
- (void)deliverNotification:(id<FakeNSUserNotification>)notification;
|
||||
- (void)removeDeliveredNotification:(id<FakeNSUserNotification>)notification;
|
||||
- (void)removeAllDeliveredNotifications;
|
||||
- (void)_removeAllDisplayedNotifications;
|
||||
- (void)_removeDisplayedNotification:(id<FakeNSUserNotification>)notification;
|
||||
@end
|
||||
|
||||
@interface mozNotificationCenterDelegate : NSObject <NSUserNotificationCenterDelegate>
|
||||
{
|
||||
OSXNotificationCenter *mOSXNC;
|
||||
}
|
||||
- (id)initWithOSXNC:(OSXNotificationCenter*)osxnc;
|
||||
@end
|
||||
|
||||
@implementation mozNotificationCenterDelegate
|
||||
|
||||
- (id)initWithOSXNC:(OSXNotificationCenter*)osxnc
|
||||
{
|
||||
[super init];
|
||||
// We should *never* outlive this OSXNotificationCenter.
|
||||
mOSXNC = osxnc;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
||||
didDeliverNotification:(id<FakeNSUserNotification>)notification
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
||||
didActivateNotification:(id<FakeNSUserNotification>)notification
|
||||
{
|
||||
unsigned long long additionalActionIndex = ULLONG_MAX;
|
||||
if ([notification respondsToSelector:@selector(_alternateActionIndex)]) {
|
||||
NSNumber *alternateActionIndex = [(NSObject*)notification valueForKey:@"_alternateActionIndex"];
|
||||
additionalActionIndex = [alternateActionIndex unsignedLongLongValue];
|
||||
}
|
||||
mOSXNC->OnActivate([[notification userInfo] valueForKey:@"name"],
|
||||
notification.activationType,
|
||||
additionalActionIndex);
|
||||
}
|
||||
|
||||
- (BOOL)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
||||
shouldPresentNotification:(id<FakeNSUserNotification>)notification
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
// This is an undocumented method that we need for parity with Safari.
|
||||
// Apple bug #15440664.
|
||||
- (void)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
||||
didRemoveDeliveredNotifications:(NSArray *)notifications
|
||||
{
|
||||
for (id<FakeNSUserNotification> notification in notifications) {
|
||||
NSString *name = [[notification userInfo] valueForKey:@"name"];
|
||||
mOSXNC->CloseAlertCocoaString(name);
|
||||
}
|
||||
}
|
||||
|
||||
// This is an undocumented method that we need to be notified if a user clicks the close button.
|
||||
- (void)userNotificationCenter:(id<FakeNSUserNotificationCenter>)center
|
||||
didDismissAlert:(id<FakeNSUserNotification>)notification
|
||||
{
|
||||
NSString *name = [[notification userInfo] valueForKey:@"name"];
|
||||
mOSXNC->CloseAlertCocoaString(name);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum {
|
||||
OSXNotificationActionDisable = 0,
|
||||
OSXNotificationActionSettings = 1,
|
||||
};
|
||||
|
||||
class OSXNotificationInfo final : public nsISupports {
|
||||
private:
|
||||
virtual ~OSXNotificationInfo();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
OSXNotificationInfo(NSString *name, nsIObserver *observer,
|
||||
const nsAString & alertCookie);
|
||||
|
||||
NSString *mName;
|
||||
nsCOMPtr<nsIObserver> mObserver;
|
||||
nsString mCookie;
|
||||
RefPtr<nsICancelable> mIconRequest;
|
||||
id<FakeNSUserNotification> mPendingNotifiction;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(OSXNotificationInfo)
|
||||
|
||||
OSXNotificationInfo::OSXNotificationInfo(NSString *name, nsIObserver *observer,
|
||||
const nsAString & alertCookie)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
NS_ASSERTION(name, "Cannot create OSXNotificationInfo without a name!");
|
||||
mName = [name retain];
|
||||
mObserver = observer;
|
||||
mCookie = alertCookie;
|
||||
mPendingNotifiction = nil;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
OSXNotificationInfo::~OSXNotificationInfo()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
[mName release];
|
||||
[mPendingNotifiction release];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
static id<FakeNSUserNotificationCenter> GetNotificationCenter() {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
Class c = NSClassFromString(@"NSUserNotificationCenter");
|
||||
return [c performSelector:@selector(defaultUserNotificationCenter)];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
OSXNotificationCenter::OSXNotificationCenter()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
mDelegate = [[mozNotificationCenterDelegate alloc] initWithOSXNC:this];
|
||||
GetNotificationCenter().delegate = mDelegate;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
OSXNotificationCenter::~OSXNotificationCenter()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
[GetNotificationCenter() removeAllDeliveredNotifications];
|
||||
[mDelegate release];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(OSXNotificationCenter, nsIAlertsService, nsIAlertsIconData,
|
||||
nsIAlertNotificationImageListener)
|
||||
|
||||
nsresult OSXNotificationCenter::Init()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
return (!!NSClassFromString(@"NSUserNotification")) ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const nsAString & aAlertTitle,
|
||||
const nsAString & aAlertText, bool aAlertTextClickable,
|
||||
const nsAString & aAlertCookie,
|
||||
nsIObserver * aAlertListener,
|
||||
const nsAString & aAlertName,
|
||||
const nsAString & aBidi,
|
||||
const nsAString & aLang,
|
||||
const nsAString & aData,
|
||||
nsIPrincipal * aPrincipal,
|
||||
bool aInPrivateBrowsing,
|
||||
bool aRequireInteraction)
|
||||
{
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
|
||||
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
|
||||
aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aBidi, aLang, aData,
|
||||
aPrincipal, aInPrivateBrowsing,
|
||||
aRequireInteraction);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return ShowAlert(alert, aAlertListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowPersistentNotification(const nsAString& aPersistentData,
|
||||
nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener)
|
||||
{
|
||||
return ShowAlert(aAlert, aAlertListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener)
|
||||
{
|
||||
return ShowAlertWithIconData(aAlert, aAlertListener, 0, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowAlertWithIconData(nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener,
|
||||
uint32_t aIconSize,
|
||||
const uint8_t* aIconData)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
NS_ENSURE_ARG(aAlert);
|
||||
|
||||
Class unClass = NSClassFromString(@"NSUserNotification");
|
||||
id<FakeNSUserNotification> notification = [[unClass alloc] init];
|
||||
|
||||
nsAutoString title;
|
||||
nsresult rv = aAlert->GetTitle(title);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
notification.title = nsCocoaUtils::ToNSString(title);
|
||||
|
||||
nsAutoString hostPort;
|
||||
rv = aAlert->GetSource(hostPort);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle));
|
||||
|
||||
if (!hostPort.IsEmpty() && bundle) {
|
||||
const char16_t* formatStrings[] = { hostPort.get() };
|
||||
nsXPIDLString notificationSource;
|
||||
bundle->FormatStringFromName(u"source.label",
|
||||
formatStrings,
|
||||
ArrayLength(formatStrings),
|
||||
getter_Copies(notificationSource));
|
||||
notification.subtitle = nsCocoaUtils::ToNSString(notificationSource);
|
||||
}
|
||||
|
||||
nsAutoString text;
|
||||
rv = aAlert->GetText(text);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
notification.informativeText = nsCocoaUtils::ToNSString(text);
|
||||
|
||||
notification.soundName = NSUserNotificationDefaultSoundName;
|
||||
notification.hasActionButton = NO;
|
||||
|
||||
// If this is not an application/extension alert, show additional actions dealing with permissions.
|
||||
bool isActionable;
|
||||
if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) && isActionable) {
|
||||
nsXPIDLString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle;
|
||||
bundle->GetStringFromName(u"closeButton.title",
|
||||
getter_Copies(closeButtonTitle));
|
||||
bundle->GetStringFromName(u"actionButton.label",
|
||||
getter_Copies(actionButtonTitle));
|
||||
if (!hostPort.IsEmpty()) {
|
||||
const char16_t* formatStrings[] = { hostPort.get() };
|
||||
bundle->FormatStringFromName(u"webActions.disableForOrigin.label",
|
||||
formatStrings,
|
||||
ArrayLength(formatStrings),
|
||||
getter_Copies(disableButtonTitle));
|
||||
}
|
||||
bundle->GetStringFromName(u"webActions.settings.label",
|
||||
getter_Copies(settingsButtonTitle));
|
||||
|
||||
notification.otherButtonTitle = nsCocoaUtils::ToNSString(closeButtonTitle);
|
||||
|
||||
// OS X 10.8 only shows action buttons if the "Alerts" style is set in
|
||||
// Notification Center preferences, and doesn't support the alternate
|
||||
// action menu.
|
||||
if ([notification respondsToSelector:@selector(set_showsButtons:)] &&
|
||||
[notification respondsToSelector:@selector(set_alwaysShowAlternateActionMenu:)] &&
|
||||
[notification respondsToSelector:@selector(set_alternateActionButtonTitles:)]) {
|
||||
|
||||
notification.hasActionButton = YES;
|
||||
notification.actionButtonTitle = nsCocoaUtils::ToNSString(actionButtonTitle);
|
||||
|
||||
[(NSObject*)notification setValue:@(YES) forKey:@"_showsButtons"];
|
||||
[(NSObject*)notification setValue:@(YES) forKey:@"_alwaysShowAlternateActionMenu"];
|
||||
[(NSObject*)notification setValue:@[
|
||||
nsCocoaUtils::ToNSString(disableButtonTitle),
|
||||
nsCocoaUtils::ToNSString(settingsButtonTitle)
|
||||
]
|
||||
forKey:@"_alternateActionButtonTitles"];
|
||||
}
|
||||
}
|
||||
nsAutoString name;
|
||||
rv = aAlert->GetName(name);
|
||||
// Don't let an alert name be more than MAX_NOTIFICATION_NAME_LEN characters.
|
||||
// More than that shouldn't be necessary and userInfo (assigned to below) has
|
||||
// a length limit of 16k on OS X 10.11. Exception thrown if limit exceeded.
|
||||
if (name.Length() > MAX_NOTIFICATION_NAME_LEN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NSString *alertName = nsCocoaUtils::ToNSString(name);
|
||||
if (!alertName) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
notification.userInfo = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil]
|
||||
forKeys:[NSArray arrayWithObjects:@"name", nil]];
|
||||
|
||||
nsAutoString cookie;
|
||||
rv = aAlert->GetCookie(cookie);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
OSXNotificationInfo *osxni = new OSXNotificationInfo(alertName, aAlertListener, cookie);
|
||||
|
||||
// Show the favicon if supported on this version of OS X.
|
||||
if (aIconSize > 0 &&
|
||||
[notification respondsToSelector:@selector(set_identityImage:)] &&
|
||||
[notification respondsToSelector:@selector(set_identityImageHasBorder:)]) {
|
||||
|
||||
NSData *iconData = [NSData dataWithBytes:aIconData length:aIconSize];
|
||||
NSImage *icon = [[[NSImage alloc] initWithData:iconData] autorelease];
|
||||
|
||||
[(NSObject*)notification setValue:icon forKey:@"_identityImage"];
|
||||
[(NSObject*)notification setValue:@(NO) forKey:@"_identityImageHasBorder"];
|
||||
}
|
||||
|
||||
bool inPrivateBrowsing;
|
||||
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Show the notification without waiting for an image if there is no icon URL or
|
||||
// notification icons are not supported on this version of OS X.
|
||||
if (![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
|
||||
CloseAlertCocoaString(alertName);
|
||||
mActiveAlerts.AppendElement(osxni);
|
||||
[GetNotificationCenter() deliverNotification:notification];
|
||||
[notification release];
|
||||
if (aAlertListener) {
|
||||
aAlertListener->Observe(nullptr, "alertshow", cookie.get());
|
||||
}
|
||||
} else {
|
||||
mPendingAlerts.AppendElement(osxni);
|
||||
osxni->mPendingNotifiction = notification;
|
||||
// Wait six seconds for the image to load.
|
||||
rv = aAlert->LoadImage(6000, this, osxni,
|
||||
getter_AddRefs(osxni->mIconRequest));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ShowPendingNotification(osxni);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::CloseAlert(const nsAString& aAlertName,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
NSString *alertName = nsCocoaUtils::ToNSString(aAlertName);
|
||||
CloseAlertCocoaString(alertName);
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
void
|
||||
OSXNotificationCenter::CloseAlertCocoaString(NSString *aAlertName)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (!aAlertName) {
|
||||
return; // Can't do anything without a name
|
||||
}
|
||||
|
||||
NSArray *notifications = [GetNotificationCenter() deliveredNotifications];
|
||||
for (id<FakeNSUserNotification> notification in notifications) {
|
||||
NSString *name = [[notification userInfo] valueForKey:@"name"];
|
||||
if ([name isEqualToString:aAlertName]) {
|
||||
[GetNotificationCenter() removeDeliveredNotification:notification];
|
||||
[GetNotificationCenter() _removeDisplayedNotification:notification];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mActiveAlerts.Length(); i++) {
|
||||
OSXNotificationInfo *osxni = mActiveAlerts[i];
|
||||
if ([aAlertName isEqualToString:osxni->mName]) {
|
||||
if (osxni->mObserver) {
|
||||
osxni->mObserver->Observe(nullptr, "alertfinished", osxni->mCookie.get());
|
||||
}
|
||||
if (osxni->mIconRequest) {
|
||||
osxni->mIconRequest->Cancel(NS_BINDING_ABORTED);
|
||||
osxni->mIconRequest = nullptr;
|
||||
}
|
||||
mActiveAlerts.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
void
|
||||
OSXNotificationCenter::OnActivate(NSString *aAlertName,
|
||||
NSUserNotificationActivationType aActivationType,
|
||||
unsigned long long aAdditionalActionIndex)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (!aAlertName) {
|
||||
return; // Can't do anything without a name
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mActiveAlerts.Length(); i++) {
|
||||
OSXNotificationInfo *osxni = mActiveAlerts[i];
|
||||
if ([aAlertName isEqualToString:osxni->mName]) {
|
||||
if (osxni->mObserver) {
|
||||
switch ((int)aActivationType) {
|
||||
case NSUserNotificationActivationTypeAdditionalActionClicked:
|
||||
case NSUserNotificationActivationTypeActionButtonClicked:
|
||||
switch (aAdditionalActionIndex) {
|
||||
case OSXNotificationActionDisable:
|
||||
osxni->mObserver->Observe(nullptr, "alertdisablecallback", osxni->mCookie.get());
|
||||
break;
|
||||
case OSXNotificationActionSettings:
|
||||
osxni->mObserver->Observe(nullptr, "alertsettingscallback", osxni->mCookie.get());
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unknown NSUserNotification additional action clicked");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
osxni->mObserver->Observe(nullptr, "alertclickcallback", osxni->mCookie.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
void
|
||||
OSXNotificationCenter::ShowPendingNotification(OSXNotificationInfo *osxni)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (osxni->mIconRequest) {
|
||||
osxni->mIconRequest->Cancel(NS_BINDING_ABORTED);
|
||||
osxni->mIconRequest = nullptr;
|
||||
}
|
||||
|
||||
CloseAlertCocoaString(osxni->mName);
|
||||
|
||||
for (unsigned int i = 0; i < mPendingAlerts.Length(); i++) {
|
||||
if (mPendingAlerts[i] == osxni) {
|
||||
mActiveAlerts.AppendElement(osxni);
|
||||
mPendingAlerts.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[GetNotificationCenter() deliverNotification:osxni->mPendingNotifiction];
|
||||
|
||||
if (osxni->mObserver) {
|
||||
osxni->mObserver->Observe(nullptr, "alertshow", osxni->mCookie.get());
|
||||
}
|
||||
|
||||
[osxni->mPendingNotifiction release];
|
||||
osxni->mPendingNotifiction = nil;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::OnImageMissing(nsISupports* aUserData)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
OSXNotificationInfo *osxni = static_cast<OSXNotificationInfo*>(aUserData);
|
||||
if (osxni->mPendingNotifiction) {
|
||||
// If there was an error getting the image, or the request timed out, show
|
||||
// the notification without a content image.
|
||||
ShowPendingNotification(osxni);
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::OnImageReady(nsISupports* aUserData,
|
||||
imgIRequest* aRequest)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
nsresult rv = aRequest->GetImage(getter_AddRefs(image));
|
||||
if (NS_WARN_IF(NS_FAILED(rv) || !image)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
OSXNotificationInfo *osxni = static_cast<OSXNotificationInfo*>(aUserData);
|
||||
if (!osxni->mPendingNotifiction) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NSImage *cocoaImage = nil;
|
||||
nsCocoaUtils::CreateNSImageFromImageContainer(image, imgIContainer::FRAME_FIRST, &cocoaImage, 1.0f);
|
||||
(osxni->mPendingNotifiction).contentImage = cocoaImage;
|
||||
[cocoaImage release];
|
||||
ShowPendingNotification(osxni);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,80 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef RectTextureImage_h_
|
||||
#define RectTextureImage_h_
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class MacIOSurface;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
} // namespace gl
|
||||
|
||||
namespace widget {
|
||||
|
||||
// Manages a texture which can resize dynamically, binds to the
|
||||
// LOCAL_GL_TEXTURE_RECTANGLE_ARB texture target and is automatically backed
|
||||
// by a power-of-two size GL texture. The latter two features are used for
|
||||
// compatibility with older Mac hardware which we block GL layers on.
|
||||
// RectTextureImages are used both for accelerated GL layers drawing and for
|
||||
// OMTC BasicLayers drawing.
|
||||
class RectTextureImage {
|
||||
public:
|
||||
RectTextureImage();
|
||||
|
||||
virtual ~RectTextureImage();
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
BeginUpdate(const LayoutDeviceIntSize& aNewSize,
|
||||
const LayoutDeviceIntRegion& aDirtyRegion =
|
||||
LayoutDeviceIntRegion());
|
||||
void EndUpdate();
|
||||
|
||||
void UpdateIfNeeded(const LayoutDeviceIntSize& aNewSize,
|
||||
const LayoutDeviceIntRegion& aDirtyRegion,
|
||||
void (^aCallback)(gfx::DrawTarget*,
|
||||
const LayoutDeviceIntRegion&))
|
||||
{
|
||||
RefPtr<gfx::DrawTarget> drawTarget = BeginUpdate(aNewSize, aDirtyRegion);
|
||||
if (drawTarget) {
|
||||
aCallback(drawTarget, GetUpdateRegion());
|
||||
EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFromCGContext(const LayoutDeviceIntSize& aNewSize,
|
||||
const LayoutDeviceIntRegion& aDirtyRegion,
|
||||
CGContextRef aCGContext);
|
||||
|
||||
LayoutDeviceIntRegion GetUpdateRegion() {
|
||||
MOZ_ASSERT(mInUpdate, "update region only valid during update");
|
||||
return mUpdateRegion;
|
||||
}
|
||||
|
||||
void Draw(mozilla::layers::GLManager* aManager,
|
||||
const LayoutDeviceIntPoint& aLocation,
|
||||
const gfx::Matrix4x4& aTransform = gfx::Matrix4x4());
|
||||
|
||||
|
||||
protected:
|
||||
void DeleteTexture();
|
||||
void BindIOSurfaceToTexture(gl::GLContext* aGL);
|
||||
|
||||
RefPtr<MacIOSurface> mIOSurface;
|
||||
gl::GLContext* mGLContext;
|
||||
LayoutDeviceIntRegion mUpdateRegion;
|
||||
LayoutDeviceIntSize mBufferSize;
|
||||
GLuint mTexture;
|
||||
bool mInUpdate;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // RectTextureImage_h_
|
||||
@@ -1,171 +0,0 @@
|
||||
/* -*- Mode: objc; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "RectTextureImage.h"
|
||||
|
||||
#include "gfxUtils.h"
|
||||
#include "GLContextCGL.h"
|
||||
#include "mozilla/layers/GLManager.h"
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#include "OGLShaderProgram.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
RectTextureImage::RectTextureImage()
|
||||
: mGLContext(nullptr)
|
||||
, mTexture(0)
|
||||
, mInUpdate(false)
|
||||
{
|
||||
}
|
||||
|
||||
RectTextureImage::~RectTextureImage()
|
||||
{
|
||||
DeleteTexture();
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
RectTextureImage::BeginUpdate(const LayoutDeviceIntSize& aNewSize,
|
||||
const LayoutDeviceIntRegion& aDirtyRegion)
|
||||
{
|
||||
MOZ_ASSERT(!mInUpdate, "Beginning update during update!");
|
||||
mUpdateRegion = aDirtyRegion;
|
||||
bool needRecreate = false;
|
||||
if (aNewSize != mBufferSize) {
|
||||
mBufferSize = aNewSize;
|
||||
mUpdateRegion =
|
||||
LayoutDeviceIntRect(LayoutDeviceIntPoint(0, 0), aNewSize);
|
||||
needRecreate = true;
|
||||
}
|
||||
|
||||
if (mUpdateRegion.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mIOSurface || needRecreate) {
|
||||
DeleteTexture();
|
||||
mIOSurface = MacIOSurface::CreateIOSurface(mBufferSize.width,
|
||||
mBufferSize.height);
|
||||
|
||||
if (!mIOSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mInUpdate = true;
|
||||
|
||||
mIOSurface->Lock(false);
|
||||
unsigned char* ioData = (unsigned char*)mIOSurface->GetBaseAddress();
|
||||
gfx::IntSize size(mBufferSize.width, mBufferSize.height);
|
||||
int32_t stride = mIOSurface->GetBytesPerRow();
|
||||
gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
RefPtr<gfx::DrawTarget> drawTarget =
|
||||
gfx::Factory::CreateDrawTargetForData(gfx::BackendType::SKIA,
|
||||
ioData, size,
|
||||
stride, format);
|
||||
return drawTarget.forget();
|
||||
}
|
||||
|
||||
void
|
||||
RectTextureImage::EndUpdate()
|
||||
{
|
||||
MOZ_ASSERT(mInUpdate, "Ending update while not in update");
|
||||
mIOSurface->Unlock(false);
|
||||
mInUpdate = false;
|
||||
}
|
||||
|
||||
void
|
||||
RectTextureImage::UpdateFromCGContext(const LayoutDeviceIntSize& aNewSize,
|
||||
const LayoutDeviceIntRegion& aDirtyRegion,
|
||||
CGContextRef aCGContext)
|
||||
{
|
||||
gfx::IntSize size = gfx::IntSize(CGBitmapContextGetWidth(aCGContext),
|
||||
CGBitmapContextGetHeight(aCGContext));
|
||||
RefPtr<gfx::DrawTarget> dt = BeginUpdate(aNewSize, aDirtyRegion);
|
||||
if (dt) {
|
||||
gfx::Rect rect(0, 0, size.width, size.height);
|
||||
gfxUtils::ClipToRegion(dt, GetUpdateRegion().ToUnknownRegion());
|
||||
RefPtr<gfx::SourceSurface> sourceSurface =
|
||||
dt->CreateSourceSurfaceFromData(static_cast<uint8_t *>(CGBitmapContextGetData(aCGContext)),
|
||||
size,
|
||||
CGBitmapContextGetBytesPerRow(aCGContext),
|
||||
gfx::SurfaceFormat::B8G8R8A8);
|
||||
dt->DrawSurface(sourceSurface, rect, rect,
|
||||
gfx::DrawSurfaceOptions(),
|
||||
gfx::DrawOptions(1.0, gfx::CompositionOp::OP_SOURCE));
|
||||
dt->PopClip();
|
||||
EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RectTextureImage::Draw(layers::GLManager* aManager,
|
||||
const LayoutDeviceIntPoint& aLocation,
|
||||
const gfx::Matrix4x4& aTransform)
|
||||
{
|
||||
gl::GLContext* gl = aManager->gl();
|
||||
|
||||
BindIOSurfaceToTexture(gl);
|
||||
|
||||
layers::ShaderProgramOGL* program =
|
||||
aManager->GetProgram(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
gfx::SurfaceFormat::R8G8B8A8);
|
||||
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl::ScopedBindTexture texture(gl, mTexture, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
||||
|
||||
aManager->ActivateProgram(program);
|
||||
program->SetProjectionMatrix(aManager->GetProjMatrix());
|
||||
program->SetLayerTransform(gfx::Matrix4x4(aTransform).PostTranslate(aLocation.x, aLocation.y, 0));
|
||||
program->SetTextureTransform(gfx::Matrix4x4());
|
||||
program->SetRenderOffset(nsIntPoint(0, 0));
|
||||
program->SetTexCoordMultiplier(mBufferSize.width, mBufferSize.height);
|
||||
program->SetTextureUnit(0);
|
||||
|
||||
aManager->BindAndDrawQuad(program,
|
||||
gfx::Rect(0.0, 0.0, mBufferSize.width, mBufferSize.height),
|
||||
gfx::Rect(0.0, 0.0, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
void
|
||||
RectTextureImage::DeleteTexture()
|
||||
{
|
||||
if (mTexture) {
|
||||
MOZ_ASSERT(mGLContext);
|
||||
mGLContext->MakeCurrent();
|
||||
mGLContext->fDeleteTextures(1, &mTexture);
|
||||
mTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RectTextureImage::BindIOSurfaceToTexture(gl::GLContext* aGL)
|
||||
{
|
||||
if (!mTexture) {
|
||||
MOZ_ASSERT(aGL);
|
||||
aGL->fGenTextures(1, &mTexture);
|
||||
aGL->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl::ScopedBindTexture texture(aGL, mTexture, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_TEXTURE_MIN_FILTER,
|
||||
LOCAL_GL_LINEAR);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_TEXTURE_MAG_FILTER,
|
||||
LOCAL_GL_LINEAR);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_TEXTURE_WRAP_T,
|
||||
LOCAL_GL_CLAMP_TO_EDGE);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_TEXTURE_WRAP_S,
|
||||
LOCAL_GL_CLAMP_TO_EDGE);
|
||||
|
||||
mIOSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(aGL)->GetCGLContext());
|
||||
mGLContext = aGL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
@@ -1,95 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef SwipeTracker_h
|
||||
#define SwipeTracker_h
|
||||
|
||||
#include "EventForwards.h"
|
||||
#include "mozilla/layers/AxisPhysicsMSDModel.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "Units.h"
|
||||
|
||||
class nsIPresShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class PanGestureInput;
|
||||
|
||||
/**
|
||||
* SwipeTracker turns PanGestureInput events into swipe events
|
||||
* (WidgetSimpleGestureEvent) and dispatches them into Gecko.
|
||||
* The swiping behavior mirrors the behavior of the Cocoa API
|
||||
* -[NSEvent trackSwipeEventWithOptions:dampenAmountThresholdMin:max:usingHandler:].
|
||||
* The advantage of using this class over the Cocoa API is that this class
|
||||
* properly supports submitting queued up events to it, and that it hopefully
|
||||
* doesn't intermittently break scrolling the way the Cocoa API does (bug 927702).
|
||||
*
|
||||
* The swipe direction is either left or right. It is determined before the
|
||||
* SwipeTracker is created and stays fixed during the swipe.
|
||||
* During the swipe, the swipe has a current "value" which is between 0 and the
|
||||
* target value. The target value is either 1 (swiping left) or -1 (swiping
|
||||
* right) - see SwipeSuccessTargetValue().
|
||||
* A swipe can either succeed or fail. If it succeeds, the swipe animation
|
||||
* animates towards the success target value; if it fails, it animates back to
|
||||
* a value of 0. A swipe can only succeed if the user is swiping in an allowed
|
||||
* direction. (Since both the allowed directions and the swipe direction are
|
||||
* known at swipe start time, it's clear from the beginning whether a swipe is
|
||||
* doomed to fail. In that case, the purpose of the SwipeTracker is to simulate
|
||||
* a bounce-back animation.)
|
||||
*/
|
||||
class SwipeTracker final : public nsARefreshObserver {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(SwipeTracker, override)
|
||||
|
||||
SwipeTracker(nsChildView& aWidget,
|
||||
const PanGestureInput& aSwipeStartEvent,
|
||||
uint32_t aAllowedDirections,
|
||||
uint32_t aSwipeDirection);
|
||||
|
||||
void Destroy();
|
||||
|
||||
nsEventStatus ProcessEvent(const PanGestureInput& aEvent);
|
||||
void CancelSwipe();
|
||||
|
||||
static WidgetSimpleGestureEvent
|
||||
CreateSwipeGestureEvent(EventMessage aMsg, nsIWidget* aWidget,
|
||||
const LayoutDeviceIntPoint& aPosition);
|
||||
|
||||
|
||||
// nsARefreshObserver
|
||||
void WillRefresh(mozilla::TimeStamp aTime) override;
|
||||
|
||||
protected:
|
||||
~SwipeTracker();
|
||||
|
||||
bool SwipingInAllowedDirection() const { return mAllowedDirections & mSwipeDirection; }
|
||||
double SwipeSuccessTargetValue() const;
|
||||
double ClampToAllowedRange(double aGestureAmount) const;
|
||||
bool ComputeSwipeSuccess() const;
|
||||
void StartAnimating(double aTargetValue);
|
||||
void SwipeFinished();
|
||||
void UnregisterFromRefreshDriver();
|
||||
bool SendSwipeEvent(EventMessage aMsg, uint32_t aDirection, double aDelta);
|
||||
|
||||
nsChildView& mWidget;
|
||||
RefPtr<nsRefreshDriver> mRefreshDriver;
|
||||
layers::AxisPhysicsMSDModel mAxis;
|
||||
const LayoutDeviceIntPoint mEventPosition;
|
||||
TimeStamp mLastEventTimeStamp;
|
||||
TimeStamp mLastAnimationFrameTime;
|
||||
const uint32_t mAllowedDirections;
|
||||
const uint32_t mSwipeDirection;
|
||||
double mGestureAmount;
|
||||
double mCurrentVelocity;
|
||||
bool mEventsAreControllingSwipe;
|
||||
bool mEventsHaveStartedNewGesture;
|
||||
bool mRegisteredWithRefreshDriver;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // SwipeTracker_h
|
||||
@@ -1,219 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SwipeTracker.h"
|
||||
|
||||
#include "InputData.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/TouchEvents.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsChildView.h"
|
||||
#include "UnitTransforms.h"
|
||||
|
||||
// These values were tweaked to make the physics feel similar to the native swipe.
|
||||
static const double kSpringForce = 250.0;
|
||||
static const double kVelocityTwitchTolerance = 0.0000001;
|
||||
static const double kWholePagePixelSize = 1000.0;
|
||||
static const double kRubberBandResistanceFactor = 4.0;
|
||||
static const double kSwipeSuccessThreshold = 0.25;
|
||||
static const double kSwipeSuccessVelocityContribution = 0.3;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static already_AddRefed<nsRefreshDriver>
|
||||
GetRefreshDriver(nsIWidget& aWidget)
|
||||
{
|
||||
nsIWidgetListener* widgetListener = aWidget.GetWidgetListener();
|
||||
nsIPresShell* presShell = widgetListener ? widgetListener->GetPresShell() : nullptr;
|
||||
nsPresContext* presContext = presShell ? presShell->GetPresContext() : nullptr;
|
||||
RefPtr<nsRefreshDriver> refreshDriver = presContext ? presContext->RefreshDriver() : nullptr;
|
||||
return refreshDriver.forget();
|
||||
}
|
||||
|
||||
SwipeTracker::SwipeTracker(nsChildView& aWidget,
|
||||
const PanGestureInput& aSwipeStartEvent,
|
||||
uint32_t aAllowedDirections,
|
||||
uint32_t aSwipeDirection)
|
||||
: mWidget(aWidget)
|
||||
, mRefreshDriver(GetRefreshDriver(mWidget))
|
||||
, mAxis(0.0, 0.0, 0.0, kSpringForce, 1.0)
|
||||
, mEventPosition(RoundedToInt(ViewAs<LayoutDevicePixel>(aSwipeStartEvent.mPanStartPoint,
|
||||
PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent)))
|
||||
, mLastEventTimeStamp(aSwipeStartEvent.mTimeStamp)
|
||||
, mAllowedDirections(aAllowedDirections)
|
||||
, mSwipeDirection(aSwipeDirection)
|
||||
, mGestureAmount(0.0)
|
||||
, mCurrentVelocity(0.0)
|
||||
, mEventsAreControllingSwipe(true)
|
||||
, mEventsHaveStartedNewGesture(false)
|
||||
, mRegisteredWithRefreshDriver(false)
|
||||
{
|
||||
SendSwipeEvent(eSwipeGestureStart, 0, 0.0);
|
||||
ProcessEvent(aSwipeStartEvent);
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::Destroy()
|
||||
{
|
||||
UnregisterFromRefreshDriver();
|
||||
}
|
||||
|
||||
SwipeTracker::~SwipeTracker()
|
||||
{
|
||||
MOZ_ASSERT(!mRegisteredWithRefreshDriver, "Destroy needs to be called before deallocating");
|
||||
}
|
||||
|
||||
double
|
||||
SwipeTracker::SwipeSuccessTargetValue() const
|
||||
{
|
||||
return (mSwipeDirection == nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
double
|
||||
SwipeTracker::ClampToAllowedRange(double aGestureAmount) const
|
||||
{
|
||||
// gestureAmount needs to stay between -1 and 0 when swiping right and
|
||||
// between 0 and 1 when swiping left.
|
||||
double min = (mSwipeDirection == nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? -1.0 : 0.0;
|
||||
double max = (mSwipeDirection == nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ? 1.0 : 0.0;
|
||||
return clamped(aGestureAmount, min, max);
|
||||
}
|
||||
|
||||
bool
|
||||
SwipeTracker::ComputeSwipeSuccess() const
|
||||
{
|
||||
double targetValue = SwipeSuccessTargetValue();
|
||||
|
||||
// If the fingers were moving away from the target direction when they were
|
||||
// lifted from the touchpad, abort the swipe.
|
||||
if (mCurrentVelocity * targetValue < -kVelocityTwitchTolerance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (mGestureAmount * targetValue +
|
||||
mCurrentVelocity * targetValue * kSwipeSuccessVelocityContribution) >= kSwipeSuccessThreshold;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
SwipeTracker::ProcessEvent(const PanGestureInput& aEvent)
|
||||
{
|
||||
// If the fingers have already been lifted, don't process this event for swiping.
|
||||
if (!mEventsAreControllingSwipe) {
|
||||
// Return nsEventStatus_eConsumeNoDefault for events from the swipe gesture
|
||||
// and nsEventStatus_eIgnore for events of subsequent scroll gestures.
|
||||
if (aEvent.mType == PanGestureInput::PANGESTURE_MAYSTART ||
|
||||
aEvent.mType == PanGestureInput::PANGESTURE_START) {
|
||||
mEventsHaveStartedNewGesture = true;
|
||||
}
|
||||
return mEventsHaveStartedNewGesture ? nsEventStatus_eIgnore : nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
double delta = -aEvent.mPanDisplacement.x / mWidget.BackingScaleFactor() / kWholePagePixelSize;
|
||||
if (!SwipingInAllowedDirection()) {
|
||||
delta /= kRubberBandResistanceFactor;
|
||||
}
|
||||
mGestureAmount = ClampToAllowedRange(mGestureAmount + delta);
|
||||
SendSwipeEvent(eSwipeGestureUpdate, 0, mGestureAmount);
|
||||
|
||||
if (aEvent.mType != PanGestureInput::PANGESTURE_END) {
|
||||
double elapsedSeconds = std::max(0.008, (aEvent.mTimeStamp - mLastEventTimeStamp).ToSeconds());
|
||||
mCurrentVelocity = delta / elapsedSeconds;
|
||||
mLastEventTimeStamp = aEvent.mTimeStamp;
|
||||
} else {
|
||||
mEventsAreControllingSwipe = false;
|
||||
bool didSwipeSucceed = SwipingInAllowedDirection() && ComputeSwipeSuccess();
|
||||
double targetValue = 0.0;
|
||||
if (didSwipeSucceed) {
|
||||
SendSwipeEvent(eSwipeGesture, mSwipeDirection, 0.0);
|
||||
targetValue = SwipeSuccessTargetValue();
|
||||
}
|
||||
StartAnimating(targetValue);
|
||||
}
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::StartAnimating(double aTargetValue)
|
||||
{
|
||||
mAxis.SetPosition(mGestureAmount);
|
||||
mAxis.SetDestination(aTargetValue);
|
||||
mAxis.SetVelocity(mCurrentVelocity);
|
||||
|
||||
mLastAnimationFrameTime = TimeStamp::Now();
|
||||
|
||||
// Add ourselves as a refresh driver observer. The refresh driver
|
||||
// will call WillRefresh for each animation frame until we
|
||||
// unregister ourselves.
|
||||
MOZ_ASSERT(!mRegisteredWithRefreshDriver);
|
||||
if (mRefreshDriver) {
|
||||
mRefreshDriver->AddRefreshObserver(this, Flush_Style);
|
||||
mRegisteredWithRefreshDriver = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
mAxis.Simulate(now - mLastAnimationFrameTime);
|
||||
mLastAnimationFrameTime = now;
|
||||
|
||||
bool isFinished = mAxis.IsFinished(1.0 / kWholePagePixelSize);
|
||||
mGestureAmount = (isFinished ? mAxis.GetDestination() : mAxis.GetPosition());
|
||||
SendSwipeEvent(eSwipeGestureUpdate, 0, mGestureAmount);
|
||||
|
||||
if (isFinished) {
|
||||
UnregisterFromRefreshDriver();
|
||||
SwipeFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::CancelSwipe()
|
||||
{
|
||||
SendSwipeEvent(eSwipeGestureEnd, 0, 0.0);
|
||||
}
|
||||
|
||||
void SwipeTracker::SwipeFinished()
|
||||
{
|
||||
SendSwipeEvent(eSwipeGestureEnd, 0, 0.0);
|
||||
mWidget.SwipeFinished();
|
||||
}
|
||||
|
||||
void
|
||||
SwipeTracker::UnregisterFromRefreshDriver()
|
||||
{
|
||||
if (mRegisteredWithRefreshDriver) {
|
||||
MOZ_ASSERT(mRefreshDriver, "How were we able to register, then?");
|
||||
mRefreshDriver->RemoveRefreshObserver(this, Flush_Style);
|
||||
}
|
||||
mRegisteredWithRefreshDriver = false;
|
||||
}
|
||||
|
||||
/* static */ WidgetSimpleGestureEvent
|
||||
SwipeTracker::CreateSwipeGestureEvent(EventMessage aMsg, nsIWidget* aWidget,
|
||||
const LayoutDeviceIntPoint& aPosition)
|
||||
{
|
||||
WidgetSimpleGestureEvent geckoEvent(true, aMsg, aWidget);
|
||||
geckoEvent.mModifiers = 0;
|
||||
geckoEvent.mTimeStamp = TimeStamp::Now();
|
||||
geckoEvent.mRefPoint = aPosition;
|
||||
geckoEvent.buttons = 0;
|
||||
return geckoEvent;
|
||||
}
|
||||
|
||||
bool
|
||||
SwipeTracker::SendSwipeEvent(EventMessage aMsg, uint32_t aDirection, double aDelta)
|
||||
{
|
||||
WidgetSimpleGestureEvent geckoEvent =
|
||||
CreateSwipeGestureEvent(aMsg, &mWidget, mEventPosition);
|
||||
geckoEvent.mDirection = aDirection;
|
||||
geckoEvent.mDelta = aDelta;
|
||||
geckoEvent.mAllowedDirections = mAllowedDirections;
|
||||
return mWidget.DispatchWindowEvent(geckoEvent);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,120 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef VibrancyManager_h
|
||||
#define VibrancyManager_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsTArray.h"
|
||||
#include "ViewRegion.h"
|
||||
|
||||
#import <Foundation/NSGeometry.h>
|
||||
|
||||
@class NSColor;
|
||||
@class NSView;
|
||||
class nsChildView;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum class VibrancyType {
|
||||
LIGHT,
|
||||
DARK,
|
||||
TOOLTIP,
|
||||
MENU,
|
||||
HIGHLIGHTED_MENUITEM,
|
||||
SHEET,
|
||||
SOURCE_LIST,
|
||||
SOURCE_LIST_SELECTION,
|
||||
ACTIVE_SOURCE_LIST_SELECTION
|
||||
};
|
||||
|
||||
/**
|
||||
* VibrancyManager takes care of updating the vibrant regions of a window.
|
||||
* Vibrancy is a visual look that was introduced on OS X starting with 10.10.
|
||||
* An app declares vibrant window regions to the window server, and the window
|
||||
* server will display a blurred rendering of the screen contents from behind
|
||||
* the window in these areas, behind the actual window contents. Consequently,
|
||||
* the effect is only visible in areas where the window contents are not
|
||||
* completely opaque. Usually this is achieved by clearing the background of
|
||||
* the window prior to drawing in the vibrant areas. This is possible even if
|
||||
* the window is declared as opaque.
|
||||
*/
|
||||
class VibrancyManager {
|
||||
public:
|
||||
/**
|
||||
* Create a new VibrancyManager instance and provide it with an NSView
|
||||
* to attach NSVisualEffectViews to.
|
||||
*
|
||||
* @param aCoordinateConverter The nsChildView to use for converting
|
||||
* nsIntRect device pixel coordinates into Cocoa NSRect coordinates. Must
|
||||
* outlive this VibrancyManager instance.
|
||||
* @param aContainerView The view that's going to be the superview of the
|
||||
* NSVisualEffectViews which will be created for vibrant regions.
|
||||
*/
|
||||
VibrancyManager(const nsChildView& aCoordinateConverter,
|
||||
NSView* aContainerView)
|
||||
: mCoordinateConverter(aCoordinateConverter)
|
||||
, mContainerView(aContainerView)
|
||||
{
|
||||
MOZ_ASSERT(SystemSupportsVibrancy(),
|
||||
"Don't instantiate this if !SystemSupportsVibrancy()");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the placement of the NSVisualEffectViews inside the container
|
||||
* NSView so that they cover aRegion, and create new NSVisualEffectViews
|
||||
* or remove existing ones as needed.
|
||||
* @param aType The vibrancy type to use in the region.
|
||||
* @param aRegion The vibrant area, in device pixels.
|
||||
*/
|
||||
void UpdateVibrantRegion(VibrancyType aType,
|
||||
const LayoutDeviceIntRegion& aRegion);
|
||||
|
||||
bool HasVibrantRegions() { return !mVibrantRegions.IsEmpty(); }
|
||||
|
||||
/**
|
||||
* Return the fill color that should be drawn on top of the cleared window
|
||||
* parts. Usually this would be drawn by -[NSVisualEffectView drawRect:].
|
||||
* The returned color is opaque if the system-wide "Reduce transparency"
|
||||
* preference is set.
|
||||
*/
|
||||
NSColor* VibrancyFillColorForType(VibrancyType aType);
|
||||
|
||||
/**
|
||||
* Return the font smoothing background color that should be used for text
|
||||
* drawn on top of the vibrant window parts.
|
||||
*/
|
||||
NSColor* VibrancyFontSmoothingBackgroundColorForType(VibrancyType aType);
|
||||
|
||||
/**
|
||||
* Check whether the operating system supports vibrancy at all.
|
||||
* You may only create a VibrancyManager instance if this returns true.
|
||||
* @return Whether VibrancyManager can be used on this OS.
|
||||
*/
|
||||
static bool SystemSupportsVibrancy();
|
||||
|
||||
/**
|
||||
* Create an NSVisualEffectView for the specified vibrancy type. The return
|
||||
* value is not autoreleased. We return an object of type NSView* because we
|
||||
* compile with an SDK that does not contain a definition for
|
||||
* NSVisualEffectView.
|
||||
* @param aIsContainer Whether this NSView will have child views. This value
|
||||
* affects hit testing: Container views will pass through
|
||||
* hit testing requests to their children, and leaf views
|
||||
* will be transparent to hit testing.
|
||||
*/
|
||||
static NSView* CreateEffectView(VibrancyType aType, BOOL aIsContainer = NO);
|
||||
|
||||
protected:
|
||||
const nsChildView& mCoordinateConverter;
|
||||
NSView* mContainerView;
|
||||
nsClassHashtable<nsUint32HashKey, ViewRegion> mVibrantRegions;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // VibrancyManager_h
|
||||
@@ -1,244 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "VibrancyManager.h"
|
||||
#include "nsChildView.h"
|
||||
#import <objc/message.h>
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
void
|
||||
VibrancyManager::UpdateVibrantRegion(VibrancyType aType,
|
||||
const LayoutDeviceIntRegion& aRegion)
|
||||
{
|
||||
if (aRegion.IsEmpty()) {
|
||||
mVibrantRegions.Remove(uint32_t(aType));
|
||||
return;
|
||||
}
|
||||
auto& vr = *mVibrantRegions.LookupOrAdd(uint32_t(aType));
|
||||
vr.UpdateRegion(aRegion, mCoordinateConverter, mContainerView, ^() {
|
||||
return this->CreateEffectView(aType);
|
||||
});
|
||||
}
|
||||
|
||||
@interface NSView(CurrentFillColor)
|
||||
- (NSColor*)_currentFillColor;
|
||||
@end
|
||||
|
||||
static NSColor*
|
||||
AdjustedColor(NSColor* aFillColor, VibrancyType aType)
|
||||
{
|
||||
if (aType == VibrancyType::MENU && [aFillColor alphaComponent] == 1.0) {
|
||||
// The opaque fill color that's used for the menu background when "Reduce
|
||||
// vibrancy" is checked in the system accessibility prefs is too dark.
|
||||
// This is probably because we're not using the right material for menus,
|
||||
// see VibrancyManager::CreateEffectView.
|
||||
return [NSColor colorWithDeviceWhite:0.96 alpha:1.0];
|
||||
}
|
||||
return aFillColor;
|
||||
}
|
||||
|
||||
NSColor*
|
||||
VibrancyManager::VibrancyFillColorForType(VibrancyType aType)
|
||||
{
|
||||
NSView* view = mVibrantRegions.LookupOrAdd(uint32_t(aType))->GetAnyView();
|
||||
|
||||
if (view && [view respondsToSelector:@selector(_currentFillColor)]) {
|
||||
// -[NSVisualEffectView _currentFillColor] is the color that the view
|
||||
// draws in its drawRect implementation.
|
||||
return AdjustedColor([view _currentFillColor], aType);
|
||||
}
|
||||
return [NSColor whiteColor];
|
||||
}
|
||||
|
||||
@interface NSView(FontSmoothingBackgroundColor)
|
||||
- (NSColor*)fontSmoothingBackgroundColor;
|
||||
@end
|
||||
|
||||
NSColor*
|
||||
VibrancyManager::VibrancyFontSmoothingBackgroundColorForType(VibrancyType aType)
|
||||
{
|
||||
NSView* view = mVibrantRegions.LookupOrAdd(uint32_t(aType))->GetAnyView();
|
||||
|
||||
if (view && [view respondsToSelector:@selector(fontSmoothingBackgroundColor)]) {
|
||||
return [view fontSmoothingBackgroundColor];
|
||||
}
|
||||
return [NSColor clearColor];
|
||||
}
|
||||
|
||||
static NSView*
|
||||
HitTestNil(id self, SEL _cmd, NSPoint aPoint)
|
||||
{
|
||||
// This view must be transparent to mouse events.
|
||||
return nil;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
AllowsVibrancyYes(id self, SEL _cmd)
|
||||
{
|
||||
// Means that the foreground is blended using a vibrant blend mode.
|
||||
return YES;
|
||||
}
|
||||
|
||||
static Class
|
||||
CreateEffectViewClass(BOOL aForegroundVibrancy, BOOL aIsContainer)
|
||||
{
|
||||
// Create a class that inherits from NSVisualEffectView and overrides the
|
||||
// methods -[NSView hitTest:] and -[NSVisualEffectView allowsVibrancy].
|
||||
Class NSVisualEffectViewClass = NSClassFromString(@"NSVisualEffectView");
|
||||
const char* className = aForegroundVibrancy
|
||||
? "EffectViewWithForegroundVibrancy" : "EffectViewWithoutForegroundVibrancy";
|
||||
Class EffectViewClass = objc_allocateClassPair(NSVisualEffectViewClass, className, 0);
|
||||
if (!aIsContainer) {
|
||||
class_addMethod(EffectViewClass, @selector(hitTest:), (IMP)HitTestNil,
|
||||
"@@:{CGPoint=dd}");
|
||||
}
|
||||
if (aForegroundVibrancy) {
|
||||
// Override the -[NSView allowsVibrancy] method to return YES.
|
||||
class_addMethod(EffectViewClass, @selector(allowsVibrancy), (IMP)AllowsVibrancyYes, "I@:");
|
||||
}
|
||||
return EffectViewClass;
|
||||
}
|
||||
|
||||
static id
|
||||
AppearanceForVibrancyType(VibrancyType aType)
|
||||
{
|
||||
Class NSAppearanceClass = NSClassFromString(@"NSAppearance");
|
||||
switch (aType) {
|
||||
case VibrancyType::LIGHT:
|
||||
case VibrancyType::TOOLTIP:
|
||||
case VibrancyType::MENU:
|
||||
case VibrancyType::HIGHLIGHTED_MENUITEM:
|
||||
case VibrancyType::SHEET:
|
||||
case VibrancyType::SOURCE_LIST:
|
||||
case VibrancyType::SOURCE_LIST_SELECTION:
|
||||
case VibrancyType::ACTIVE_SOURCE_LIST_SELECTION:
|
||||
return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
|
||||
withObject:@"NSAppearanceNameVibrantLight"];
|
||||
case VibrancyType::DARK:
|
||||
return [NSAppearanceClass performSelector:@selector(appearanceNamed:)
|
||||
withObject:@"NSAppearanceNameVibrantDark"];
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_10) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
|
||||
enum {
|
||||
NSVisualEffectStateFollowsWindowActiveState,
|
||||
NSVisualEffectStateActive,
|
||||
NSVisualEffectStateInactive
|
||||
};
|
||||
|
||||
enum {
|
||||
NSVisualEffectMaterialTitlebar = 3
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_11) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
|
||||
enum {
|
||||
NSVisualEffectMaterialMenu = 5,
|
||||
NSVisualEffectMaterialSidebar = 7
|
||||
};
|
||||
#endif
|
||||
|
||||
static NSUInteger
|
||||
VisualEffectStateForVibrancyType(VibrancyType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case VibrancyType::TOOLTIP:
|
||||
case VibrancyType::MENU:
|
||||
case VibrancyType::HIGHLIGHTED_MENUITEM:
|
||||
case VibrancyType::SHEET:
|
||||
// Tooltip and menu windows are never "key" and sheets always looks
|
||||
// active, so we need to tell the vibrancy effect to look active
|
||||
// regardless of window state.
|
||||
return NSVisualEffectStateActive;
|
||||
default:
|
||||
return NSVisualEffectStateFollowsWindowActiveState;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL
|
||||
HasVibrantForeground(VibrancyType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case VibrancyType::MENU:
|
||||
return YES;
|
||||
default:
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
|
||||
enum {
|
||||
NSVisualEffectMaterialSelection = 4
|
||||
};
|
||||
#endif
|
||||
|
||||
@interface NSView(NSVisualEffectViewMethods)
|
||||
- (void)setState:(NSUInteger)state;
|
||||
- (void)setMaterial:(NSUInteger)material;
|
||||
- (void)setEmphasized:(BOOL)emphasized;
|
||||
@end
|
||||
|
||||
NSView*
|
||||
VibrancyManager::CreateEffectView(VibrancyType aType, BOOL aIsContainer)
|
||||
{
|
||||
static Class EffectViewWithoutForegroundVibrancy = CreateEffectViewClass(NO, NO);
|
||||
static Class EffectViewWithForegroundVibrancy = CreateEffectViewClass(YES, NO);
|
||||
static Class EffectViewContainer = CreateEffectViewClass(NO, YES);
|
||||
|
||||
// Pick the right NSVisualEffectView subclass for the desired vibrancy mode.
|
||||
// For "container" views, never use foreground vibrancy, because returning
|
||||
// YES from allowsVibrancy forces on foreground vibrancy for all descendant
|
||||
// views which can have unintended effects.
|
||||
Class EffectViewClass = aIsContainer
|
||||
? EffectViewContainer
|
||||
: (HasVibrantForeground(aType) ? EffectViewWithForegroundVibrancy
|
||||
: EffectViewWithoutForegroundVibrancy);
|
||||
NSView* effectView = [[EffectViewClass alloc] initWithFrame:NSZeroRect];
|
||||
[effectView performSelector:@selector(setAppearance:)
|
||||
withObject:AppearanceForVibrancyType(aType)];
|
||||
[effectView setState:VisualEffectStateForVibrancyType(aType)];
|
||||
|
||||
BOOL canUseElCapitanMaterials = nsCocoaFeatures::OnElCapitanOrLater();
|
||||
if (aType == VibrancyType::MENU) {
|
||||
// Before 10.11 there is no material that perfectly matches the menu
|
||||
// look. Of all available material types, NSVisualEffectMaterialTitlebar
|
||||
// is the one that comes closest.
|
||||
[effectView setMaterial:canUseElCapitanMaterials ? NSVisualEffectMaterialMenu
|
||||
: NSVisualEffectMaterialTitlebar];
|
||||
} else if (aType == VibrancyType::SOURCE_LIST && canUseElCapitanMaterials) {
|
||||
[effectView setMaterial:NSVisualEffectMaterialSidebar];
|
||||
} else if (aType == VibrancyType::HIGHLIGHTED_MENUITEM ||
|
||||
aType == VibrancyType::SOURCE_LIST_SELECTION ||
|
||||
aType == VibrancyType::ACTIVE_SOURCE_LIST_SELECTION) {
|
||||
[effectView setMaterial:NSVisualEffectMaterialSelection];
|
||||
if ([effectView respondsToSelector:@selector(setEmphasized:)] &&
|
||||
aType != VibrancyType::SOURCE_LIST_SELECTION) {
|
||||
[effectView setEmphasized:YES];
|
||||
}
|
||||
}
|
||||
|
||||
return effectView;
|
||||
}
|
||||
|
||||
static bool
|
||||
ComputeSystemSupportsVibrancy()
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
return NSClassFromString(@"NSAppearance") &&
|
||||
NSClassFromString(@"NSVisualEffectView");
|
||||
#else
|
||||
// objc_allocateClassPair doesn't work in 32 bit mode, so turn off vibrancy.
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
VibrancyManager::SystemSupportsVibrancy()
|
||||
{
|
||||
static bool supportsVibrancy = ComputeSystemSupportsVibrancy();
|
||||
return supportsVibrancy;
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ViewRegion_h
|
||||
#define ViewRegion_h
|
||||
|
||||
#include "Units.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
@class NSView;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Manages a set of NSViews to cover a LayoutDeviceIntRegion.
|
||||
*/
|
||||
class ViewRegion {
|
||||
public:
|
||||
~ViewRegion();
|
||||
|
||||
mozilla::LayoutDeviceIntRegion Region() { return mRegion; }
|
||||
|
||||
/**
|
||||
* Update the region.
|
||||
* @param aRegion The new region.
|
||||
* @param aCoordinateConverter The nsChildView to use for converting
|
||||
* LayoutDeviceIntRect device pixel coordinates into Cocoa NSRect coordinates.
|
||||
* @param aContainerView The view that's going to be the superview of the
|
||||
* NSViews which will be created for this region.
|
||||
* @param aViewCreationCallback A block that instantiates new NSViews.
|
||||
* @return Whether or not the region changed.
|
||||
*/
|
||||
bool UpdateRegion(const mozilla::LayoutDeviceIntRegion& aRegion,
|
||||
const nsChildView& aCoordinateConverter,
|
||||
NSView* aContainerView,
|
||||
NSView* (^aViewCreationCallback)());
|
||||
|
||||
/**
|
||||
* Return an NSView from the region, if there is any.
|
||||
*/
|
||||
NSView* GetAnyView() { return mViews.Length() > 0 ? mViews[0] : nil; }
|
||||
|
||||
private:
|
||||
mozilla::LayoutDeviceIntRegion mRegion;
|
||||
nsTArray<NSView*> mViews;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ViewRegion_h
|
||||
@@ -1,70 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ViewRegion.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
ViewRegion::~ViewRegion()
|
||||
{
|
||||
for (size_t i = 0; i < mViews.Length(); i++) {
|
||||
[mViews[i] removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ViewRegion::UpdateRegion(const LayoutDeviceIntRegion& aRegion,
|
||||
const nsChildView& aCoordinateConverter,
|
||||
NSView* aContainerView,
|
||||
NSView* (^aViewCreationCallback)())
|
||||
{
|
||||
if (mRegion == aRegion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to construct the required region using as many EffectViews
|
||||
// as necessary. We try to update the geometry of existing views if
|
||||
// possible, or create new ones or remove old ones if the number of
|
||||
// rects in the region has changed.
|
||||
|
||||
nsTArray<NSView*> viewsToRecycle;
|
||||
mViews.SwapElements(viewsToRecycle);
|
||||
// The mViews array is now empty.
|
||||
|
||||
size_t i = 0;
|
||||
for (auto iter = aRegion.RectIter();
|
||||
!iter.Done() || i < viewsToRecycle.Length();
|
||||
i++) {
|
||||
if (!iter.Done()) {
|
||||
NSView* view = nil;
|
||||
NSRect rect = aCoordinateConverter.DevPixelsToCocoaPoints(iter.Get());
|
||||
if (i < viewsToRecycle.Length()) {
|
||||
view = viewsToRecycle[i];
|
||||
} else {
|
||||
view = aViewCreationCallback();
|
||||
[aContainerView addSubview:view];
|
||||
|
||||
// Now that the view is in the view hierarchy, it'll be kept alive by
|
||||
// its superview, so we can drop our reference.
|
||||
[view release];
|
||||
}
|
||||
if (!NSEqualRects(rect, [view frame])) {
|
||||
[view setFrame:rect];
|
||||
}
|
||||
[view setNeedsDisplay:YES];
|
||||
mViews.AppendElement(view);
|
||||
iter.Next();
|
||||
} else {
|
||||
// Our new region is made of fewer rects than the old region, so we can
|
||||
// remove this view. We only have a weak reference to it, so removing it
|
||||
// from the view hierarchy will release it.
|
||||
[viewsToRecycle[i] removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
mRegion = aRegion;
|
||||
return true;
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include "CustomCocoaEvents.h"
|
||||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#include <mozilla/CondVar.h>
|
||||
#include <mozilla/Mutex.h>
|
||||
#include "mozilla/WidgetTraceEvent.h"
|
||||
|
||||
using mozilla::CondVar;
|
||||
using mozilla::Mutex;
|
||||
using mozilla::MutexAutoLock;
|
||||
|
||||
namespace {
|
||||
|
||||
Mutex* sMutex = NULL;
|
||||
CondVar* sCondVar = NULL;
|
||||
bool sTracerProcessed = false;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool InitWidgetTracing()
|
||||
{
|
||||
sMutex = new Mutex("Event tracer thread mutex");
|
||||
sCondVar = new CondVar(*sMutex, "Event tracer thread condvar");
|
||||
return sMutex && sCondVar;
|
||||
}
|
||||
|
||||
void CleanUpWidgetTracing()
|
||||
{
|
||||
delete sMutex;
|
||||
delete sCondVar;
|
||||
sMutex = NULL;
|
||||
sCondVar = NULL;
|
||||
}
|
||||
|
||||
// This function is called from the main (UI) thread.
|
||||
void SignalTracerThread()
|
||||
{
|
||||
if (!sMutex || !sCondVar)
|
||||
return;
|
||||
MutexAutoLock lock(*sMutex);
|
||||
if (!sTracerProcessed) {
|
||||
sTracerProcessed = true;
|
||||
sCondVar->Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called from the background tracer thread.
|
||||
bool FireAndWaitForTracerEvent()
|
||||
{
|
||||
MOZ_ASSERT(sMutex && sCondVar, "Tracing not initialized!");
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
MutexAutoLock lock(*sMutex);
|
||||
if (sTracerProcessed) {
|
||||
// Things are out of sync. This is likely because we're in
|
||||
// the middle of shutting down. Just return false and hope the
|
||||
// tracer thread is quitting anyway.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Post an application-defined event to the main thread's event queue
|
||||
// and wait for it to get processed.
|
||||
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
|
||||
location:NSMakePoint(0,0)
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:NULL
|
||||
subtype:kEventSubtypeTrace
|
||||
data1:0
|
||||
data2:0]
|
||||
atStart:NO];
|
||||
while (!sTracerProcessed)
|
||||
sCondVar->Wait();
|
||||
sTracerProcessed = false;
|
||||
[pool release];
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,39 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
document.body.style.position = "fixed"
|
||||
|
||||
setTimeout(boom2, 1);
|
||||
}
|
||||
|
||||
function boom2()
|
||||
{
|
||||
lappy = document.getElementById("lappy");
|
||||
lappy.style.display = "none"
|
||||
|
||||
setTimeout(boom3, 200);
|
||||
}
|
||||
|
||||
function boom3()
|
||||
{
|
||||
dump("Reloading\n");
|
||||
location.reload();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body bgcolor="black" onload="boom()">
|
||||
|
||||
<span style="overflow: scroll; display: -moz-box;"></span>
|
||||
|
||||
<embed id="lappy" src="" width=550 height=400 TYPE="application/x-shockwave-flash" ></embed>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +0,0 @@
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
setTimeout('document.documentElement.className = ""', 1000);
|
||||
</script>
|
||||
<body>
|
||||
<iframe src="373122-1-inner.html"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<button style="width: 8205em;"></button>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,10 +0,0 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
class="reftest-wait"
|
||||
style="margin: 12em; padding: 20px 10em; opacity: 0.2; font-size: 11.2px; -moz-appearance: toolbar; white-space: nowrap;"><body
|
||||
style="position: absolute;"
|
||||
onload="setTimeout(function() { document.body.removeChild(document.getElementById('tr')); document.documentElement.removeAttribute('class'); }, 30);">
|
||||
|
||||
xxx
|
||||
yyy
|
||||
|
||||
<tr id="tr">300</tr></body></html>
|
||||
@@ -1,8 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div><span style="-moz-appearance: radio; padding: 15000px;"></span></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,8 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="min-width: -moz-max-content;"><div style="-moz-appearance: button;"><div style="margin: 0 100%;"></div></div></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +0,0 @@
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<hbox><button width="7788025414616">S</button></hbox>
|
||||
</window>
|
||||
@@ -1,6 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<div style="padding: 10px;"><input type="button" value="Go" style="letter-spacing: 331989pt;"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +0,0 @@
|
||||
<html>
|
||||
<head></head>
|
||||
<body><div style="display: -moz-box; word-spacing: 549755813889px;"><button>T </button></div></body>
|
||||
</html>
|
||||
@@ -1,4 +0,0 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head></head>
|
||||
<body><div><mstyle xmlns="http://www.w3.org/1998/Math/MathML" style="-moz-appearance: button;"/></div></body>
|
||||
</html>
|
||||
@@ -1,2 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head></head><body><div style="display: table; padding: 625203mm; -moz-appearance: menulist;"></div></body></html>
|
||||
@@ -1,20 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
var o2 = document.createElement("option");
|
||||
document.getElementById("o1").appendChild(o2);
|
||||
o2.style.padding = "131072cm";
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();">
|
||||
|
||||
<select><option id="o1" style="height: 0cm;"></option></select>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,11 +0,0 @@
|
||||
skip-if(!cocoaWidget) load 373122-1.html # bug 1300017
|
||||
load 397209-1.html
|
||||
load 403296-1.xhtml
|
||||
load 419737-1.html
|
||||
load 435223-1.html
|
||||
load 444260-1.xul
|
||||
load 444864-1.html
|
||||
load 449111-1.html
|
||||
load 460349-1.xhtml
|
||||
load 460387-1.html
|
||||
load 464589-1.html
|
||||
|
Before Width: | Height: | Size: 256 B |
|
Before Width: | Height: | Size: 655 B |
|
Before Width: | Height: | Size: 256 B |
|
Before Width: | Height: | Size: 649 B |
|
Before Width: | Height: | Size: 268 B |
|
Before Width: | Height: | Size: 647 B |
|
Before Width: | Height: | Size: 321 B |
|
Before Width: | Height: | Size: 836 B |
|
Before Width: | Height: | Size: 723 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 284 B |
|
Before Width: | Height: | Size: 621 B |
|
Before Width: | Height: | Size: 331 B |
|
Before Width: | Height: | Size: 852 B |
|
Before Width: | Height: | Size: 279 B |
|
Before Width: | Height: | Size: 794 B |
|
Before Width: | Height: | Size: 300 B |
|
Before Width: | Height: | Size: 975 B |
|
Before Width: | Height: | Size: 282 B |
|
Before Width: | Height: | Size: 660 B |
|
Before Width: | Height: | Size: 278 B |
|
Before Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 295 B |
|
Before Width: | Height: | Size: 976 B |
|
Before Width: | Height: | Size: 270 B |
|
Before Width: | Height: | Size: 802 B |
|
Before Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 806 B |
|
Before Width: | Height: | Size: 120 B |
|
Before Width: | Height: | Size: 336 B |
|
Before Width: | Height: | Size: 655 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 650 B |
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,140 +0,0 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsPIWidgetCocoa.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'widget_cocoa'
|
||||
|
||||
EXPORTS += [
|
||||
'mozView.h',
|
||||
'nsBidiKeyboard.h',
|
||||
'nsChangeObserver.h',
|
||||
'nsCocoaDebugUtils.h',
|
||||
'nsCocoaFeatures.h',
|
||||
'nsCocoaUtils.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'ComplexTextInputPanel.mm',
|
||||
'GfxInfo.mm',
|
||||
'NativeKeyBindings.mm',
|
||||
'nsAppShell.mm',
|
||||
'nsBidiKeyboard.mm',
|
||||
'nsCocoaFeatures.mm',
|
||||
'nsCocoaUtils.mm',
|
||||
'nsCocoaWindow.mm',
|
||||
'nsColorPicker.mm',
|
||||
'nsCursorManager.mm',
|
||||
'nsDeviceContextSpecX.mm',
|
||||
'nsFilePicker.mm',
|
||||
'nsIdleServiceX.mm',
|
||||
'nsLookAndFeel.mm',
|
||||
'nsMacCursor.mm',
|
||||
'nsMacDockSupport.mm',
|
||||
'nsMacWebAppUtils.mm',
|
||||
'nsMenuBarX.mm',
|
||||
'nsMenuGroupOwnerX.mm',
|
||||
'nsMenuItemIconX.mm',
|
||||
'nsMenuItemX.mm',
|
||||
'nsMenuUtilsX.mm',
|
||||
'nsMenuX.mm',
|
||||
'nsPrintDialogX.mm',
|
||||
'nsPrintOptionsX.mm',
|
||||
'nsPrintSettingsX.mm',
|
||||
'nsScreenCocoa.mm',
|
||||
'nsScreenManagerCocoa.mm',
|
||||
'nsSound.mm',
|
||||
'nsStandaloneNativeMenu.mm',
|
||||
'nsSystemStatusBarCocoa.mm',
|
||||
'nsToolkit.mm',
|
||||
'nsWidgetFactory.mm',
|
||||
'nsWindowMap.mm',
|
||||
'OSXNotificationCenter.mm',
|
||||
'RectTextureImage.mm',
|
||||
'SwipeTracker.mm',
|
||||
'TextInputHandler.mm',
|
||||
'VibrancyManager.mm',
|
||||
'ViewRegion.mm',
|
||||
'WidgetTraceEvent.mm',
|
||||
]
|
||||
|
||||
# These files cannot be built in unified mode because they cause symbol conflicts
|
||||
SOURCES += [
|
||||
'nsChildView.mm',
|
||||
'nsClipboard.mm',
|
||||
'nsCocoaDebugUtils.mm',
|
||||
'nsDragService.mm',
|
||||
'nsNativeThemeCocoa.mm',
|
||||
]
|
||||
|
||||
if not CONFIG['RELEASE_OR_BETA'] or CONFIG['MOZ_DEBUG']:
|
||||
SOURCES += [
|
||||
'nsSandboxViolationSink.mm',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# XXX: We should fix these warnings.
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'/layout/forms',
|
||||
'/layout/generic',
|
||||
'/layout/style',
|
||||
'/layout/xul',
|
||||
'/widget',
|
||||
]
|
||||
|
||||
RESOURCE_FILES.cursors += [
|
||||
'cursors/arrowN.png',
|
||||
'cursors/arrowN@2x.png',
|
||||
'cursors/arrowS.png',
|
||||
'cursors/arrowS@2x.png',
|
||||
'cursors/cell.png',
|
||||
'cursors/cell@2x.png',
|
||||
'cursors/colResize.png',
|
||||
'cursors/colResize@2x.png',
|
||||
'cursors/help.png',
|
||||
'cursors/help@2x.png',
|
||||
'cursors/move.png',
|
||||
'cursors/move@2x.png',
|
||||
'cursors/rowResize.png',
|
||||
'cursors/rowResize@2x.png',
|
||||
'cursors/sizeNE.png',
|
||||
'cursors/sizeNE@2x.png',
|
||||
'cursors/sizeNESW.png',
|
||||
'cursors/sizeNESW@2x.png',
|
||||
'cursors/sizeNS.png',
|
||||
'cursors/sizeNS@2x.png',
|
||||
'cursors/sizeNW.png',
|
||||
'cursors/sizeNW@2x.png',
|
||||
'cursors/sizeNWSE.png',
|
||||
'cursors/sizeNWSE@2x.png',
|
||||
'cursors/sizeSE.png',
|
||||
'cursors/sizeSE@2x.png',
|
||||
'cursors/sizeSW.png',
|
||||
'cursors/sizeSW@2x.png',
|
||||
'cursors/vtIBeam.png',
|
||||
'cursors/vtIBeam@2x.png',
|
||||
'cursors/zoomIn.png',
|
||||
'cursors/zoomIn@2x.png',
|
||||
'cursors/zoomOut.png',
|
||||
'cursors/zoomOut@2x.png',
|
||||
]
|
||||
|
||||
# These resources go in $(DIST)/bin/res/MainMenu.nib, but we can't use a magic
|
||||
# RESOURCE_FILES.MainMenu.nib attribute, since that would put the files in
|
||||
# $(DIST)/bin/res/MainMenu/nib. Instead, we call __setattr__ directly to create
|
||||
# an attribute with the correct name.
|
||||
RESOURCE_FILES.__setattr__('MainMenu.nib', [
|
||||
'resources/MainMenu.nib/classes.nib',
|
||||
'resources/MainMenu.nib/info.nib',
|
||||
'resources/MainMenu.nib/keyedobjects.nib',
|
||||
])
|
||||
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
@@ -1,62 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozView_h_
|
||||
#define mozView_h_
|
||||
|
||||
#undef DARWIN
|
||||
#import <Cocoa/Cocoa.h>
|
||||
class nsIWidget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget{
|
||||
class TextInputHandler;
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
// A protocol listing all the methods that an object which wants
|
||||
// to live in gecko's widget hierarchy must implement. |nsChildView|
|
||||
// makes assumptions that any NSView with which it comes in contact will
|
||||
// implement this protocol.
|
||||
@protocol mozView
|
||||
|
||||
// aHandler is Gecko's default text input handler: It implements the
|
||||
// NSTextInput protocol to handle key events. Don't make aHandler a
|
||||
// strong reference -- that causes a memory leak.
|
||||
- (void)installTextInputHandler:(mozilla::widget::TextInputHandler*)aHandler;
|
||||
- (void)uninstallTextInputHandler;
|
||||
|
||||
// access the nsIWidget associated with this view. DOES NOT ADDREF.
|
||||
- (nsIWidget*)widget;
|
||||
|
||||
// return a context menu for this view
|
||||
- (NSMenu*)contextMenu;
|
||||
|
||||
// called when our corresponding Gecko view goes away
|
||||
- (void)widgetDestroyed;
|
||||
|
||||
- (BOOL)isDragInProgress;
|
||||
|
||||
// Checks whether the view is first responder or not
|
||||
- (BOOL)isFirstResponder;
|
||||
|
||||
// Call when you dispatch an event which may cause to open context menu.
|
||||
- (void)maybeInitContextMenuTracking;
|
||||
|
||||
@end
|
||||
|
||||
// An informal protocol implemented by the NSWindow of the host application.
|
||||
//
|
||||
// It's used to prevent re-entrant calls to -makeKeyAndOrderFront: when gecko
|
||||
// focus/activate events propagate out to the embedder's
|
||||
// nsIEmbeddingSiteWindow::SetFocus implementation.
|
||||
@interface NSObject(mozWindow)
|
||||
|
||||
- (BOOL)suppressMakeKeyFront;
|
||||
- (void)setSuppressMakeKeyFront:(BOOL)inSuppress;
|
||||
|
||||
@end
|
||||
|
||||
#endif // mozView_h_
|
||||
@@ -1,71 +0,0 @@
|
||||
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* Runs the main native Cocoa run loop, interrupting it as needed to process
|
||||
* Gecko events.
|
||||
*/
|
||||
|
||||
#ifndef nsAppShell_h_
|
||||
#define nsAppShell_h_
|
||||
|
||||
#include "nsBaseAppShell.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
// GeckoNSApplication
|
||||
//
|
||||
// Subclass of NSApplication for filtering out certain events.
|
||||
@interface GeckoNSApplication : NSApplication
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
@class AppShellDelegate;
|
||||
|
||||
class nsAppShell : public nsBaseAppShell
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD ResumeNative(void);
|
||||
|
||||
nsAppShell();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
NS_IMETHOD Run(void);
|
||||
NS_IMETHOD Exit(void);
|
||||
NS_IMETHOD OnProcessNextEvent(nsIThreadInternal *aThread, bool aMayWait);
|
||||
NS_IMETHOD AfterProcessNextEvent(nsIThreadInternal *aThread,
|
||||
bool aEventWasProcessed);
|
||||
|
||||
// public only to be visible to Objective-C code that must call it
|
||||
void WillTerminate();
|
||||
|
||||
protected:
|
||||
virtual ~nsAppShell();
|
||||
|
||||
virtual void ScheduleNativeEventCallback();
|
||||
virtual bool ProcessNextNativeEvent(bool aMayWait);
|
||||
|
||||
static void ProcessGeckoEvents(void* aInfo);
|
||||
|
||||
protected:
|
||||
CFMutableArrayRef mAutoreleasePools;
|
||||
|
||||
AppShellDelegate* mDelegate;
|
||||
CFRunLoopRef mCFRunLoop;
|
||||
CFRunLoopSourceRef mCFRunLoopSource;
|
||||
|
||||
bool mRunningEventLoop;
|
||||
bool mStarted;
|
||||
bool mTerminated;
|
||||
bool mSkippedNativeCallback;
|
||||
bool mRunningCocoaEmbedded;
|
||||
|
||||
int32_t mNativeEventCallbackDepth;
|
||||
// Can be set from different threads, so must be modified atomically
|
||||
int32_t mNativeEventScheduledDepth;
|
||||
};
|
||||
|
||||
#endif // nsAppShell_h_
|
||||
@@ -1,907 +0,0 @@
|
||||
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* Runs the main native Cocoa run loop, interrupting it as needed to process
|
||||
* Gecko events.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "CustomCocoaEvents.h"
|
||||
#include "mozilla/WidgetTraceEvent.h"
|
||||
#include "nsAppShell.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIRollupListener.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIWebBrowserChrome.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsChildView.h"
|
||||
#include "nsToolkit.h"
|
||||
#include "TextInputHandler.h"
|
||||
#include "mozilla/HangMonitor.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "pratom.h"
|
||||
#if !defined(RELEASE_OR_BETA) || defined(DEBUG)
|
||||
#include "nsSandboxViolationSink.h"
|
||||
#endif
|
||||
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#include "nsIDOMWakeLockListener.h"
|
||||
#include "nsIPowerManagerService.h"
|
||||
|
||||
using namespace mozilla::widget;
|
||||
|
||||
// A wake lock listener that disables screen saver when requested by
|
||||
// Gecko. For example when we're playing video in a foreground tab we
|
||||
// don't want the screen saver to turn on.
|
||||
|
||||
class MacWakeLockListener final : public nsIDOMMozWakeLockListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS;
|
||||
|
||||
private:
|
||||
~MacWakeLockListener() {}
|
||||
|
||||
IOPMAssertionID mAssertionID = kIOPMNullAssertionID;
|
||||
|
||||
NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) override {
|
||||
if (!aTopic.EqualsASCII("screen")) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Note the wake lock code ensures that we're not sent duplicate
|
||||
// "locked-foreground" notifications when multiple wake locks are held.
|
||||
if (aState.EqualsASCII("locked-foreground")) {
|
||||
// Prevent screen saver.
|
||||
CFStringRef cf_topic =
|
||||
::CFStringCreateWithCharacters(kCFAllocatorDefault,
|
||||
reinterpret_cast<const UniChar*>
|
||||
(aTopic.Data()),
|
||||
aTopic.Length());
|
||||
IOReturn success =
|
||||
::IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
|
||||
kIOPMAssertionLevelOn,
|
||||
cf_topic,
|
||||
&mAssertionID);
|
||||
CFRelease(cf_topic);
|
||||
if (success != kIOReturnSuccess) {
|
||||
NS_WARNING("failed to disable screensaver");
|
||||
}
|
||||
} else {
|
||||
// Re-enable screen saver.
|
||||
NS_WARNING("Releasing screensaver");
|
||||
if (mAssertionID != kIOPMNullAssertionID) {
|
||||
IOReturn result = ::IOPMAssertionRelease(mAssertionID);
|
||||
if (result != kIOReturnSuccess) {
|
||||
NS_WARNING("failed to release screensaver");
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}; // MacWakeLockListener
|
||||
|
||||
// defined in nsCocoaWindow.mm
|
||||
extern int32_t gXULModalLevel;
|
||||
|
||||
static bool gAppShellMethodsSwizzled = false;
|
||||
|
||||
@implementation GeckoNSApplication
|
||||
|
||||
- (void)sendEvent:(NSEvent *)anEvent
|
||||
{
|
||||
mozilla::HangMonitor::NotifyActivity();
|
||||
if ([anEvent type] == NSApplicationDefined &&
|
||||
[anEvent subtype] == kEventSubtypeTrace) {
|
||||
mozilla::SignalTracerThread();
|
||||
return;
|
||||
}
|
||||
[super sendEvent:anEvent];
|
||||
}
|
||||
|
||||
#if defined(MAC_OS_X_VERSION_10_12) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 && \
|
||||
__LP64__
|
||||
// 10.12 changed `mask` to NSEventMask (unsigned long long) for x86_64 builds.
|
||||
- (NSEvent*)nextEventMatchingMask:(NSEventMask)mask
|
||||
#else
|
||||
- (NSEvent*)nextEventMatchingMask:(NSUInteger)mask
|
||||
#endif
|
||||
untilDate:(NSDate*)expiration
|
||||
inMode:(NSString*)mode
|
||||
dequeue:(BOOL)flag
|
||||
{
|
||||
if (expiration) {
|
||||
mozilla::HangMonitor::Suspend();
|
||||
}
|
||||
NSEvent* nextEvent = [super nextEventMatchingMask:mask
|
||||
untilDate:expiration inMode:mode dequeue:flag];
|
||||
if (expiration) {
|
||||
mozilla::HangMonitor::NotifyActivity();
|
||||
}
|
||||
return nextEvent;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// AppShellDelegate
|
||||
//
|
||||
// Cocoa bridge class. An object of this class is registered to receive
|
||||
// notifications.
|
||||
//
|
||||
@interface AppShellDelegate : NSObject
|
||||
{
|
||||
@private
|
||||
nsAppShell* mAppShell;
|
||||
}
|
||||
|
||||
- (id)initWithAppShell:(nsAppShell*)aAppShell;
|
||||
- (void)applicationWillTerminate:(NSNotification*)aNotification;
|
||||
- (void)beginMenuTracking:(NSNotification*)aNotification;
|
||||
@end
|
||||
|
||||
// nsAppShell implementation
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::ResumeNative(void)
|
||||
{
|
||||
nsresult retval = nsBaseAppShell::ResumeNative();
|
||||
if (NS_SUCCEEDED(retval) && (mSuspendNativeCount == 0) &&
|
||||
mSkippedNativeCallback)
|
||||
{
|
||||
mSkippedNativeCallback = false;
|
||||
ScheduleNativeEventCallback();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
nsAppShell::nsAppShell()
|
||||
: mAutoreleasePools(nullptr)
|
||||
, mDelegate(nullptr)
|
||||
, mCFRunLoop(NULL)
|
||||
, mCFRunLoopSource(NULL)
|
||||
, mRunningEventLoop(false)
|
||||
, mStarted(false)
|
||||
, mTerminated(false)
|
||||
, mSkippedNativeCallback(false)
|
||||
, mNativeEventCallbackDepth(0)
|
||||
, mNativeEventScheduledDepth(0)
|
||||
{
|
||||
// A Cocoa event loop is running here if (and only if) we've been embedded
|
||||
// by a Cocoa app.
|
||||
mRunningCocoaEmbedded = [NSApp isRunning] ? true : false;
|
||||
}
|
||||
|
||||
nsAppShell::~nsAppShell()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (mCFRunLoop) {
|
||||
if (mCFRunLoopSource) {
|
||||
::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource,
|
||||
kCFRunLoopCommonModes);
|
||||
::CFRelease(mCFRunLoopSource);
|
||||
}
|
||||
::CFRelease(mCFRunLoop);
|
||||
}
|
||||
|
||||
if (mAutoreleasePools) {
|
||||
NS_ASSERTION(::CFArrayGetCount(mAutoreleasePools) == 0,
|
||||
"nsAppShell destroyed without popping all autorelease pools");
|
||||
::CFRelease(mAutoreleasePools);
|
||||
}
|
||||
|
||||
[mDelegate release];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(MacWakeLockListener, nsIDOMMozWakeLockListener)
|
||||
mozilla::StaticRefPtr<MacWakeLockListener> sWakeLockListener;
|
||||
|
||||
static void
|
||||
AddScreenWakeLockListener()
|
||||
{
|
||||
nsCOMPtr<nsIPowerManagerService> sPowerManagerService = do_GetService(
|
||||
POWERMANAGERSERVICE_CONTRACTID);
|
||||
if (sPowerManagerService) {
|
||||
sWakeLockListener = new MacWakeLockListener();
|
||||
sPowerManagerService->AddWakeLockListener(sWakeLockListener);
|
||||
} else {
|
||||
NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
RemoveScreenWakeLockListener()
|
||||
{
|
||||
nsCOMPtr<nsIPowerManagerService> sPowerManagerService = do_GetService(
|
||||
POWERMANAGERSERVICE_CONTRACTID);
|
||||
if (sPowerManagerService) {
|
||||
sPowerManagerService->RemoveWakeLockListener(sWakeLockListener);
|
||||
sPowerManagerService = nullptr;
|
||||
sWakeLockListener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// An undocumented CoreGraphics framework method, present in the same form
|
||||
// since at least OS X 10.5.
|
||||
extern "C" CGError CGSSetDebugOptions(int options);
|
||||
|
||||
// Init
|
||||
//
|
||||
// Loads the nib (see bug 316076c21) and sets up the CFRunLoopSource used to
|
||||
// interrupt the main native run loop.
|
||||
//
|
||||
// public
|
||||
nsresult
|
||||
nsAppShell::Init()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
// No event loop is running yet (unless an embedding app that uses
|
||||
// NSApplicationMain() is running).
|
||||
NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// mAutoreleasePools is used as a stack of NSAutoreleasePool objects created
|
||||
// by |this|. CFArray is used instead of NSArray because NSArray wants to
|
||||
// retain each object you add to it, and you can't retain an
|
||||
// NSAutoreleasePool.
|
||||
mAutoreleasePools = ::CFArrayCreateMutable(nullptr, 0, nullptr);
|
||||
NS_ENSURE_STATE(mAutoreleasePools);
|
||||
|
||||
// Get the path of the nib file, which lives in the GRE location
|
||||
nsCOMPtr<nsIFile> nibFile;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(nibFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nibFile->AppendNative(NS_LITERAL_CSTRING("res"));
|
||||
nibFile->AppendNative(NS_LITERAL_CSTRING("MainMenu.nib"));
|
||||
|
||||
nsAutoCString nibPath;
|
||||
rv = nibFile->GetNativePath(nibPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This call initializes NSApplication unless:
|
||||
// 1) we're using xre -- NSApp's already been initialized by
|
||||
// MacApplicationDelegate.mm's EnsureUseCocoaDockAPI().
|
||||
// 2) an embedding app that uses NSApplicationMain() is running -- NSApp's
|
||||
// already been initialized and its main run loop is already running.
|
||||
[NSBundle loadNibFile:
|
||||
[NSString stringWithUTF8String:(const char*)nibPath.get()]
|
||||
externalNameTable:
|
||||
[NSDictionary dictionaryWithObject:[GeckoNSApplication sharedApplication]
|
||||
forKey:@"NSOwner"]
|
||||
withZone:NSDefaultMallocZone()];
|
||||
|
||||
mDelegate = [[AppShellDelegate alloc] initWithAppShell:this];
|
||||
NS_ENSURE_STATE(mDelegate);
|
||||
|
||||
// Add a CFRunLoopSource to the main native run loop. The source is
|
||||
// responsible for interrupting the run loop when Gecko events are ready.
|
||||
|
||||
mCFRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
|
||||
NS_ENSURE_STATE(mCFRunLoop);
|
||||
::CFRetain(mCFRunLoop);
|
||||
|
||||
CFRunLoopSourceContext context;
|
||||
bzero(&context, sizeof(context));
|
||||
// context.version = 0;
|
||||
context.info = this;
|
||||
context.perform = ProcessGeckoEvents;
|
||||
|
||||
mCFRunLoopSource = ::CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
|
||||
NS_ENSURE_STATE(mCFRunLoopSource);
|
||||
|
||||
::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
|
||||
|
||||
rv = nsBaseAppShell::Init();
|
||||
|
||||
if (!gAppShellMethodsSwizzled) {
|
||||
// We should only replace the original terminate: method if we're not
|
||||
// running in a Cocoa embedder. See bug 604901.
|
||||
if (!mRunningCocoaEmbedded) {
|
||||
nsToolkit::SwizzleMethods([NSApplication class], @selector(terminate:),
|
||||
@selector(nsAppShell_NSApplication_terminate:));
|
||||
}
|
||||
gAppShellMethodsSwizzled = true;
|
||||
}
|
||||
|
||||
if (nsCocoaFeatures::OnYosemiteOrLater()) {
|
||||
// Explicitly turn off CGEvent logging. This works around bug 1092855.
|
||||
// If there are already CGEvents in the log, turning off logging also
|
||||
// causes those events to be written to disk. But at this point no
|
||||
// CGEvents have yet been processed. CGEvents are events (usually
|
||||
// input events) pulled from the WindowServer. An option of 0x80000008
|
||||
// turns on CGEvent logging.
|
||||
CGSSetDebugOptions(0x80000007);
|
||||
}
|
||||
|
||||
#if !defined(RELEASE_OR_BETA) || defined(DEBUG)
|
||||
if (Preferences::GetBool("security.sandbox.mac.track.violations", false)) {
|
||||
nsSandboxViolationSink::Start();
|
||||
}
|
||||
#endif
|
||||
|
||||
[localPool release];
|
||||
|
||||
return rv;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
// ProcessGeckoEvents
|
||||
//
|
||||
// The "perform" target of mCFRunLoop, called when mCFRunLoopSource is
|
||||
// signalled from ScheduleNativeEventCallback.
|
||||
//
|
||||
// Arrange for Gecko events to be processed on demand (in response to a call
|
||||
// to ScheduleNativeEventCallback(), if processing of Gecko events via "native
|
||||
// methods" hasn't been suspended). This happens in NativeEventCallback().
|
||||
//
|
||||
// protected static
|
||||
void
|
||||
nsAppShell::ProcessGeckoEvents(void* aInfo)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
PROFILER_LABEL("Events", "ProcessGeckoEvents",
|
||||
js::ProfileEntry::Category::EVENTS);
|
||||
|
||||
nsAppShell* self = static_cast<nsAppShell*> (aInfo);
|
||||
|
||||
if (self->mRunningEventLoop) {
|
||||
self->mRunningEventLoop = false;
|
||||
|
||||
// The run loop may be sleeping -- [NSRunLoop runMode:...]
|
||||
// won't return until it's given a reason to wake up. Awaken it by
|
||||
// posting a bogus event. There's no need to make the event
|
||||
// presentable.
|
||||
//
|
||||
// But _don't_ set windowNumber to '-1' -- that can lead to nasty
|
||||
// weirdness like bmo bug 397039 (a crash in [NSApp sendEvent:] on one of
|
||||
// these fake events, because the -1 has gotten changed into the number
|
||||
// of an actual NSWindow object, and that NSWindow object has just been
|
||||
// destroyed). Setting windowNumber to '0' seems to work fine -- this
|
||||
// seems to prevent the OS from ever trying to associate our bogus event
|
||||
// with a particular NSWindow object.
|
||||
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
|
||||
location:NSMakePoint(0,0)
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:NULL
|
||||
subtype:kEventSubtypeNone
|
||||
data1:0
|
||||
data2:0]
|
||||
atStart:NO];
|
||||
}
|
||||
|
||||
if (self->mSuspendNativeCount <= 0) {
|
||||
++self->mNativeEventCallbackDepth;
|
||||
self->NativeEventCallback();
|
||||
--self->mNativeEventCallbackDepth;
|
||||
} else {
|
||||
self->mSkippedNativeCallback = true;
|
||||
}
|
||||
|
||||
// Still needed to avoid crashes on quit in most Mochitests.
|
||||
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
|
||||
location:NSMakePoint(0,0)
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:NULL
|
||||
subtype:kEventSubtypeNone
|
||||
data1:0
|
||||
data2:0]
|
||||
atStart:NO];
|
||||
|
||||
// Normally every call to ScheduleNativeEventCallback() results in
|
||||
// exactly one call to ProcessGeckoEvents(). So each Release() here
|
||||
// normally balances exactly one AddRef() in ScheduleNativeEventCallback().
|
||||
// But if Exit() is called just after ScheduleNativeEventCallback(), the
|
||||
// corresponding call to ProcessGeckoEvents() will never happen. We check
|
||||
// for this possibility in two different places -- here and in Exit()
|
||||
// itself. If we find here that Exit() has been called (that mTerminated
|
||||
// is true), it's because we've been called recursively, that Exit() was
|
||||
// called from self->NativeEventCallback() above, and that we're unwinding
|
||||
// the recursion. In this case we'll never be called again, and we balance
|
||||
// here any extra calls to ScheduleNativeEventCallback().
|
||||
//
|
||||
// When ProcessGeckoEvents() is called recursively, it's because of a
|
||||
// call to ScheduleNativeEventCallback() from NativeEventCallback(). We
|
||||
// balance the "extra" AddRefs here (rather than always in Exit()) in order
|
||||
// to ensure that 'self' stays alive until the end of this method. We also
|
||||
// make sure not to finish the balancing until all the recursion has been
|
||||
// unwound.
|
||||
if (self->mTerminated) {
|
||||
int32_t releaseCount = 0;
|
||||
if (self->mNativeEventScheduledDepth > self->mNativeEventCallbackDepth) {
|
||||
releaseCount = PR_ATOMIC_SET(&self->mNativeEventScheduledDepth,
|
||||
self->mNativeEventCallbackDepth);
|
||||
}
|
||||
while (releaseCount-- > self->mNativeEventCallbackDepth)
|
||||
self->Release();
|
||||
} else {
|
||||
// As best we can tell, every call to ProcessGeckoEvents() is triggered
|
||||
// by a call to ScheduleNativeEventCallback(). But we've seen a few
|
||||
// (non-reproducible) cases of double-frees that *might* have been caused
|
||||
// by spontaneous calls (from the OS) to ProcessGeckoEvents(). So we
|
||||
// deal with that possibility here.
|
||||
if (PR_ATOMIC_DECREMENT(&self->mNativeEventScheduledDepth) < 0) {
|
||||
PR_ATOMIC_SET(&self->mNativeEventScheduledDepth, 0);
|
||||
NS_WARNING("Spontaneous call to ProcessGeckoEvents()!");
|
||||
} else {
|
||||
self->Release();
|
||||
}
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
// WillTerminate
|
||||
//
|
||||
// Called by the AppShellDelegate when an NSApplicationWillTerminate
|
||||
// notification is posted. After this method is called, native events should
|
||||
// no longer be processed. The NSApplicationWillTerminate notification is
|
||||
// only posted when [NSApp terminate:] is called, which doesn't happen on a
|
||||
// "normal" application quit.
|
||||
//
|
||||
// public
|
||||
void
|
||||
nsAppShell::WillTerminate()
|
||||
{
|
||||
if (mTerminated)
|
||||
return;
|
||||
|
||||
// Make sure that the nsAppExitEvent posted by nsAppStartup::Quit() (called
|
||||
// from [MacApplicationDelegate applicationShouldTerminate:]) gets run.
|
||||
NS_ProcessPendingEvents(NS_GetCurrentThread());
|
||||
|
||||
mTerminated = true;
|
||||
}
|
||||
|
||||
// ScheduleNativeEventCallback
|
||||
//
|
||||
// Called (possibly on a non-main thread) when Gecko has an event that
|
||||
// needs to be processed. The Gecko event needs to be processed on the
|
||||
// main thread, so the native run loop must be interrupted.
|
||||
//
|
||||
// In nsBaseAppShell.cpp, the mNativeEventPending variable is used to
|
||||
// ensure that ScheduleNativeEventCallback() is called no more than once
|
||||
// per call to NativeEventCallback(). ProcessGeckoEvents() can skip its
|
||||
// call to NativeEventCallback() if processing of Gecko events by native
|
||||
// means is suspended (using nsIAppShell::SuspendNative()), which will
|
||||
// suspend calls from nsBaseAppShell::OnDispatchedEvent() to
|
||||
// ScheduleNativeEventCallback(). But when Gecko event processing by
|
||||
// native means is resumed (in ResumeNative()), an extra call is made to
|
||||
// ScheduleNativeEventCallback() (from ResumeNative()). This triggers
|
||||
// another call to ProcessGeckoEvents(), which calls NativeEventCallback(),
|
||||
// and nsBaseAppShell::OnDispatchedEvent() resumes calling
|
||||
// ScheduleNativeEventCallback().
|
||||
//
|
||||
// protected virtual
|
||||
void
|
||||
nsAppShell::ScheduleNativeEventCallback()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (mTerminated)
|
||||
return;
|
||||
|
||||
// Each AddRef() here is normally balanced by exactly one Release() in
|
||||
// ProcessGeckoEvents(). But there are exceptions, for which see
|
||||
// ProcessGeckoEvents() and Exit().
|
||||
NS_ADDREF_THIS();
|
||||
PR_ATOMIC_INCREMENT(&mNativeEventScheduledDepth);
|
||||
|
||||
// This will invoke ProcessGeckoEvents on the main thread.
|
||||
::CFRunLoopSourceSignal(mCFRunLoopSource);
|
||||
::CFRunLoopWakeUp(mCFRunLoop);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
// Undocumented Cocoa Event Manager function, present in the same form since
|
||||
// at least OS X 10.6.
|
||||
extern "C" EventAttributes GetEventAttributes(EventRef inEvent);
|
||||
|
||||
// ProcessNextNativeEvent
|
||||
//
|
||||
// If aMayWait is false, process a single native event. If it is true, run
|
||||
// the native run loop until stopped by ProcessGeckoEvents.
|
||||
//
|
||||
// Returns true if more events are waiting in the native event queue.
|
||||
//
|
||||
// protected virtual
|
||||
bool
|
||||
nsAppShell::ProcessNextNativeEvent(bool aMayWait)
|
||||
{
|
||||
bool moreEvents = false;
|
||||
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
bool eventProcessed = false;
|
||||
NSString* currentMode = nil;
|
||||
|
||||
if (mTerminated)
|
||||
return false;
|
||||
|
||||
bool wasRunningEventLoop = mRunningEventLoop;
|
||||
mRunningEventLoop = aMayWait;
|
||||
NSDate* waitUntil = nil;
|
||||
if (aMayWait)
|
||||
waitUntil = [NSDate distantFuture];
|
||||
|
||||
NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
|
||||
|
||||
EventQueueRef currentEventQueue = GetCurrentEventQueue();
|
||||
EventTargetRef eventDispatcherTarget = GetEventDispatcherTarget();
|
||||
|
||||
if (aMayWait) {
|
||||
mozilla::HangMonitor::Suspend();
|
||||
}
|
||||
|
||||
// Only call -[NSApp sendEvent:] (and indirectly send user-input events to
|
||||
// Gecko) if aMayWait is true. Tbis ensures most calls to -[NSApp
|
||||
// sendEvent:] happen under nsAppShell::Run(), at the lowest level of
|
||||
// recursion -- thereby making it less likely Gecko will process user-input
|
||||
// events in the wrong order or skip some of them. It also avoids eating
|
||||
// too much CPU in nsBaseAppShell::OnProcessNextEvent() (which calls
|
||||
// us) -- thereby avoiding the starvation of nsIRunnable events in
|
||||
// nsThread::ProcessNextEvent(). For more information see bug 996848.
|
||||
do {
|
||||
// No autorelease pool is provided here, because OnProcessNextEvent
|
||||
// and AfterProcessNextEvent are responsible for maintaining it.
|
||||
NS_ASSERTION(mAutoreleasePools && ::CFArrayGetCount(mAutoreleasePools),
|
||||
"No autorelease pool for native event");
|
||||
|
||||
if (aMayWait) {
|
||||
currentMode = [currentRunLoop currentMode];
|
||||
if (!currentMode)
|
||||
currentMode = NSDefaultRunLoopMode;
|
||||
NSEvent *nextEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
|
||||
untilDate:waitUntil
|
||||
inMode:currentMode
|
||||
dequeue:YES];
|
||||
if (nextEvent) {
|
||||
mozilla::HangMonitor::NotifyActivity();
|
||||
[NSApp sendEvent:nextEvent];
|
||||
eventProcessed = true;
|
||||
}
|
||||
} else {
|
||||
// AcquireFirstMatchingEventInQueue() doesn't spin the (native) event
|
||||
// loop, though it does queue up any newly available events from the
|
||||
// window server.
|
||||
EventRef currentEvent = AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
|
||||
kEventQueueOptionsNone);
|
||||
if (!currentEvent) {
|
||||
continue;
|
||||
}
|
||||
EventAttributes attrs = GetEventAttributes(currentEvent);
|
||||
UInt32 eventKind = GetEventKind(currentEvent);
|
||||
UInt32 eventClass = GetEventClass(currentEvent);
|
||||
bool osCocoaEvent =
|
||||
((eventClass == 'appl') || (eventClass == kEventClassAppleEvent) ||
|
||||
((eventClass == 'cgs ') && (eventKind != NSApplicationDefined)));
|
||||
// If attrs is kEventAttributeUserEvent or kEventAttributeMonitored
|
||||
// (i.e. a user input event), we shouldn't process it here while
|
||||
// aMayWait is false. Likewise if currentEvent will eventually be
|
||||
// turned into an OS-defined Cocoa event, or otherwise needs AppKit
|
||||
// processing. Doing otherwise risks doing too much work here, and
|
||||
// preventing the event from being properly processed by the AppKit
|
||||
// framework.
|
||||
if ((attrs != kEventAttributeNone) || osCocoaEvent) {
|
||||
// Since we can't process the next event here (while aMayWait is false),
|
||||
// we want moreEvents to be false on return.
|
||||
eventProcessed = false;
|
||||
// This call to ReleaseEvent() matches a call to RetainEvent() in
|
||||
// AcquireFirstMatchingEventInQueue() above.
|
||||
ReleaseEvent(currentEvent);
|
||||
break;
|
||||
}
|
||||
// This call to RetainEvent() matches a call to ReleaseEvent() in
|
||||
// RemoveEventFromQueue() below.
|
||||
RetainEvent(currentEvent);
|
||||
RemoveEventFromQueue(currentEventQueue, currentEvent);
|
||||
SendEventToEventTarget(currentEvent, eventDispatcherTarget);
|
||||
// This call to ReleaseEvent() matches a call to RetainEvent() in
|
||||
// AcquireFirstMatchingEventInQueue() above.
|
||||
ReleaseEvent(currentEvent);
|
||||
eventProcessed = true;
|
||||
}
|
||||
} while (mRunningEventLoop);
|
||||
|
||||
if (eventProcessed) {
|
||||
moreEvents =
|
||||
(AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
|
||||
kEventQueueOptionsNone) != NULL);
|
||||
}
|
||||
|
||||
mRunningEventLoop = wasRunningEventLoop;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
|
||||
if (!moreEvents) {
|
||||
nsChildView::UpdateCurrentInputEventCount();
|
||||
}
|
||||
|
||||
return moreEvents;
|
||||
}
|
||||
|
||||
// Run
|
||||
//
|
||||
// Overrides the base class's Run() method to call [NSApp run] (which spins
|
||||
// the native run loop until the application quits). Since (unlike the base
|
||||
// class's Run() method) we don't process any Gecko events here, they need
|
||||
// to be processed elsewhere (in NativeEventCallback(), called from
|
||||
// ProcessGeckoEvents()).
|
||||
//
|
||||
// Camino called [NSApp run] on its own (via NSApplicationMain()), and so
|
||||
// didn't call nsAppShell::Run().
|
||||
//
|
||||
// public
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::Run(void)
|
||||
{
|
||||
NS_ASSERTION(!mStarted, "nsAppShell::Run() called multiple times");
|
||||
if (mStarted || mTerminated)
|
||||
return NS_OK;
|
||||
|
||||
mStarted = true;
|
||||
|
||||
AddScreenWakeLockListener();
|
||||
|
||||
NS_OBJC_TRY_ABORT([NSApp run]);
|
||||
|
||||
RemoveScreenWakeLockListener();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::Exit(void)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
// This method is currently called more than once -- from (according to
|
||||
// mento) an nsAppExitEvent dispatched by nsAppStartup::Quit() and from an
|
||||
// XPCOM shutdown notification that nsBaseAppShell has registered to
|
||||
// receive. So we need to ensure that multiple calls won't break anything.
|
||||
// But we should also complain about it (since it isn't quite kosher).
|
||||
if (mTerminated) {
|
||||
NS_WARNING("nsAppShell::Exit() called redundantly");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mTerminated = true;
|
||||
|
||||
#if !defined(RELEASE_OR_BETA) || defined(DEBUG)
|
||||
nsSandboxViolationSink::Stop();
|
||||
#endif
|
||||
|
||||
// Quoting from Apple's doc on the [NSApplication stop:] method (from their
|
||||
// doc on the NSApplication class): "If this method is invoked during a
|
||||
// modal event loop, it will break that loop but not the main event loop."
|
||||
// nsAppShell::Exit() shouldn't be called from a modal event loop. So if
|
||||
// it is we complain about it (to users of debug builds) and call [NSApp
|
||||
// stop:] one extra time. (I'm not sure if modal event loops can be nested
|
||||
// -- Apple's docs don't say one way or the other. But the return value
|
||||
// of [NSApp _isRunningModal] doesn't change immediately after a call to
|
||||
// [NSApp stop:], so we have to assume that one extra call to [NSApp stop:]
|
||||
// will do the job.)
|
||||
BOOL cocoaModal = [NSApp _isRunningModal];
|
||||
NS_ASSERTION(!cocoaModal,
|
||||
"Don't call nsAppShell::Exit() from a modal event loop!");
|
||||
if (cocoaModal)
|
||||
[NSApp stop:nullptr];
|
||||
[NSApp stop:nullptr];
|
||||
|
||||
// A call to Exit() just after a call to ScheduleNativeEventCallback()
|
||||
// prevents the (normally) matching call to ProcessGeckoEvents() from
|
||||
// happening. If we've been called from ProcessGeckoEvents() (as usually
|
||||
// happens), we take care of it there. But if we have an unbalanced call
|
||||
// to ScheduleNativeEventCallback() and ProcessGeckoEvents() isn't on the
|
||||
// stack, we need to take care of the problem here.
|
||||
if (!mNativeEventCallbackDepth && mNativeEventScheduledDepth) {
|
||||
int32_t releaseCount = PR_ATOMIC_SET(&mNativeEventScheduledDepth, 0);
|
||||
while (releaseCount-- > 0)
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
|
||||
return nsBaseAppShell::Exit();
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
// OnProcessNextEvent
|
||||
//
|
||||
// This nsIThreadObserver method is called prior to processing an event.
|
||||
// Set up an autorelease pool that will service any autoreleased Cocoa
|
||||
// objects during this event. This includes native events processed by
|
||||
// ProcessNextNativeEvent. The autorelease pool will be popped by
|
||||
// AfterProcessNextEvent, it is important for these two methods to be
|
||||
// tightly coupled.
|
||||
//
|
||||
// public
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::OnProcessNextEvent(nsIThreadInternal *aThread, bool aMayWait)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
NS_ASSERTION(mAutoreleasePools,
|
||||
"No stack on which to store autorelease pool");
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
::CFArrayAppendValue(mAutoreleasePools, pool);
|
||||
|
||||
return nsBaseAppShell::OnProcessNextEvent(aThread, aMayWait);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
// AfterProcessNextEvent
|
||||
//
|
||||
// This nsIThreadObserver method is called after event processing is complete.
|
||||
// The Cocoa implementation cleans up the autorelease pool create by the
|
||||
// previous OnProcessNextEvent call.
|
||||
//
|
||||
// public
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::AfterProcessNextEvent(nsIThreadInternal *aThread,
|
||||
bool aEventWasProcessed)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
CFIndex count = ::CFArrayGetCount(mAutoreleasePools);
|
||||
|
||||
NS_ASSERTION(mAutoreleasePools && count,
|
||||
"Processed an event, but there's no autorelease pool?");
|
||||
|
||||
const NSAutoreleasePool* pool = static_cast<const NSAutoreleasePool*>
|
||||
(::CFArrayGetValueAtIndex(mAutoreleasePools, count - 1));
|
||||
::CFArrayRemoveValueAtIndex(mAutoreleasePools, count - 1);
|
||||
[pool release];
|
||||
|
||||
return nsBaseAppShell::AfterProcessNextEvent(aThread, aEventWasProcessed);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
|
||||
// AppShellDelegate implementation
|
||||
|
||||
|
||||
@implementation AppShellDelegate
|
||||
// initWithAppShell:
|
||||
//
|
||||
// Constructs the AppShellDelegate object
|
||||
- (id)initWithAppShell:(nsAppShell*)aAppShell
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
if ((self = [self init])) {
|
||||
mAppShell = aAppShell;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification
|
||||
object:NSApp];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationDidBecomeActive:)
|
||||
name:NSApplicationDidBecomeActiveNotification
|
||||
object:NSApp];
|
||||
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(beginMenuTracking:)
|
||||
name:@"com.apple.HIToolbox.beginMenuTrackingNotification"
|
||||
object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
|
||||
[super dealloc];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
// applicationWillTerminate:
|
||||
//
|
||||
// Notify the nsAppShell that native event processing should be discontinued.
|
||||
- (void)applicationWillTerminate:(NSNotification*)aNotification
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
mAppShell->WillTerminate();
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
// applicationDidBecomeActive
|
||||
//
|
||||
// Make sure TextInputHandler::sLastModifierState is updated when we become
|
||||
// active (since we won't have received [ChildView flagsChanged:] messages
|
||||
// while inactive).
|
||||
- (void)applicationDidBecomeActive:(NSNotification*)aNotification
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
// [NSEvent modifierFlags] is valid on every kind of event, so we don't need
|
||||
// to worry about getting an NSInternalInconsistencyException here.
|
||||
NSEvent* currentEvent = [NSApp currentEvent];
|
||||
if (currentEvent) {
|
||||
TextInputHandler::sLastModifierState =
|
||||
[currentEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
// beginMenuTracking
|
||||
//
|
||||
// Roll up our context menu (if any) when some other app (or the OS) opens
|
||||
// any sort of menu. But make sure we don't do this for notifications we
|
||||
// send ourselves (whose 'sender' will be @"org.mozilla.gecko.PopupWindow").
|
||||
- (void)beginMenuTracking:(NSNotification*)aNotification
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
NSString *sender = [aNotification object];
|
||||
if (!sender || ![sender isEqualToString:@"org.mozilla.gecko.PopupWindow"]) {
|
||||
nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
|
||||
nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
|
||||
if (rollupWidget)
|
||||
rollupListener->Rollup(0, true, nullptr, nullptr);
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// We hook terminate: in order to make OS-initiated termination work nicely
|
||||
// with Gecko's shutdown sequence. (Two ways to trigger OS-initiated
|
||||
// termination: 1) Quit from the Dock menu; 2) Log out from (or shut down)
|
||||
// your computer while the browser is active.)
|
||||
@interface NSApplication (MethodSwizzling)
|
||||
- (void)nsAppShell_NSApplication_terminate:(id)sender;
|
||||
@end
|
||||
|
||||
@implementation NSApplication (MethodSwizzling)
|
||||
|
||||
// Called by the OS after [MacApplicationDelegate applicationShouldTerminate:]
|
||||
// has returned NSTerminateNow. This method "subclasses" and replaces the
|
||||
// OS's original implementation. The only thing the orginal method does which
|
||||
// we need is that it posts NSApplicationWillTerminateNotification. Everything
|
||||
// else is unneeded (because it's handled elsewhere), or actively interferes
|
||||
// with Gecko's shutdown sequence. For example the original terminate: method
|
||||
// causes the app to exit() inside [NSApp run] (called from nsAppShell::Run()
|
||||
// above), which means that nothing runs after the call to nsAppStartup::Run()
|
||||
// in XRE_Main(), which in particular means that ScopedXPCOMStartup's destructor
|
||||
// and NS_ShutdownXPCOM() never get called.
|
||||
- (void)nsAppShell_NSApplication_terminate:(id)sender
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification
|
||||
object:NSApp];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,24 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsBidiKeyboard_h_
|
||||
#define nsBidiKeyboard_h_
|
||||
|
||||
#include "nsIBidiKeyboard.h"
|
||||
|
||||
class nsBidiKeyboard : public nsIBidiKeyboard
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIBIDIKEYBOARD
|
||||
|
||||
nsBidiKeyboard();
|
||||
|
||||
protected:
|
||||
virtual ~nsBidiKeyboard();
|
||||
};
|
||||
|
||||
#endif // nsBidiKeyboard_h_
|
||||
@@ -1,42 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsBidiKeyboard.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "TextInputHandler.h"
|
||||
|
||||
// This must be the last include:
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
using namespace mozilla::widget;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBidiKeyboard, nsIBidiKeyboard)
|
||||
|
||||
nsBidiKeyboard::nsBidiKeyboard() : nsIBidiKeyboard()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
nsBidiKeyboard::~nsBidiKeyboard()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBidiKeyboard::Reset()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(bool *aIsRTL)
|
||||
{
|
||||
*aIsRTL = TISInputSourceWrapper::CurrentInputSource().IsForRTLLanguage();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBidiKeyboard::GetHaveBidiKeyboards(bool* aResult)
|
||||
{
|
||||
// not implemented yet
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsChangeObserver_h_
|
||||
#define nsChangeObserver_h_
|
||||
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIAtom;
|
||||
|
||||
#define NS_DECL_CHANGEOBSERVER \
|
||||
void ObserveAttributeChanged(nsIDocument *aDocument, nsIContent *aContent, nsIAtom *aAttribute) override; \
|
||||
void ObserveContentRemoved(nsIDocument *aDocument, nsIContent *aChild, int32_t aIndexInContainer) override; \
|
||||
void ObserveContentInserted(nsIDocument *aDocument, nsIContent* aContainer, nsIContent *aChild) override;
|
||||
|
||||
// Something that wants to be alerted to changes in attributes or changes in
|
||||
// its corresponding content object.
|
||||
//
|
||||
// This interface is used by our menu code so we only have to have one
|
||||
// nsIDocumentObserver.
|
||||
//
|
||||
// Any class that implements this interface must take care to unregister itself
|
||||
// on deletion.
|
||||
class nsChangeObserver
|
||||
{
|
||||
public:
|
||||
// XXX use dom::Element
|
||||
virtual void ObserveAttributeChanged(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
nsIAtom* aAttribute)=0;
|
||||
|
||||
virtual void ObserveContentRemoved(nsIDocument* aDocument,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)=0;
|
||||
|
||||
virtual void ObserveContentInserted(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild)=0;
|
||||
};
|
||||
|
||||
#endif // nsChangeObserver_h_
|
||||
@@ -1,666 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsChildView_h_
|
||||
#define nsChildView_h_
|
||||
|
||||
// formal protocols
|
||||
#include "mozView.h"
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "mozilla/a11y/Accessible.h"
|
||||
#include "mozAccessibleProtocol.h"
|
||||
#endif
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsBaseWidget.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "TextInputHandler.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "gfxQuartzSurface.h"
|
||||
#include "GLContextTypes.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsRegion.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIDragService.h"
|
||||
#include "ViewRegion.h"
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <AppKit/NSOpenGL.h>
|
||||
|
||||
class nsChildView;
|
||||
class nsCocoaWindow;
|
||||
|
||||
namespace {
|
||||
class GLPresenter;
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
class InputData;
|
||||
class PanGestureInput;
|
||||
class SwipeTracker;
|
||||
struct SwipeEventQueue;
|
||||
class VibrancyManager;
|
||||
namespace layers {
|
||||
class GLManager;
|
||||
class IAPZCTreeManager;
|
||||
} // namespace layers
|
||||
namespace widget {
|
||||
class RectTextureImage;
|
||||
class WidgetRenderingContext;
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
@class PixelHostingView;
|
||||
|
||||
@interface NSEvent (Undocumented)
|
||||
|
||||
// Return Cocoa event's corresponding Carbon event. Not initialized (on
|
||||
// synthetic events) until the OS actually "sends" the event. This method
|
||||
// has been present in the same form since at least OS X 10.2.8.
|
||||
- (EventRef)_eventRef;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSView (Undocumented)
|
||||
|
||||
// Draws the title string of a window.
|
||||
// Present on NSThemeFrame since at least 10.6.
|
||||
// _drawTitleBar is somewhat complex, and has changed over the years
|
||||
// since OS X 10.6. But in that time it's never done anything that
|
||||
// would break when called outside of -[NSView drawRect:] (which we
|
||||
// sometimes do), or whose output can't be redirected to a
|
||||
// CGContextRef object (which we also sometimes do). This is likely
|
||||
// to remain true for the indefinite future. However we should
|
||||
// check _drawTitleBar in each new major version of OS X. For more
|
||||
// information see bug 877767.
|
||||
- (void)_drawTitleBar:(NSRect)aRect;
|
||||
|
||||
// Returns an NSRect that is the bounding box for all an NSView's dirty
|
||||
// rectangles (ones that need to be redrawn). The full list of dirty
|
||||
// rectangles can be obtained by calling -[NSView _dirtyRegion] and then
|
||||
// calling -[NSRegion getRects:count:] on what it returns. Both these
|
||||
// methods have been present in the same form since at least OS X 10.5.
|
||||
// Unlike -[NSView getRectsBeingDrawn:count:], these methods can be called
|
||||
// outside a call to -[NSView drawRect:].
|
||||
- (NSRect)_dirtyRect;
|
||||
|
||||
// Undocumented method of one or more of NSFrameView's subclasses. Called
|
||||
// when one or more of the titlebar buttons needs to be repositioned, to
|
||||
// disappear, or to reappear (say if the window's style changes). If
|
||||
// 'redisplay' is true, the entire titlebar (the window's top 22 pixels) is
|
||||
// marked as needing redisplay. This method has been present in the same
|
||||
// format since at least OS X 10.5.
|
||||
- (void)_tileTitlebarAndRedisplay:(BOOL)redisplay;
|
||||
|
||||
// The following undocumented methods are used to work around bug 1069658,
|
||||
// which is an Apple bug or design flaw that effects Yosemite. None of them
|
||||
// were present prior to Yosemite (OS X 10.10).
|
||||
- (NSView *)titlebarView; // Method of NSThemeFrame
|
||||
- (NSView *)titlebarContainerView; // Method of NSThemeFrame
|
||||
- (BOOL)transparent; // Method of NSTitlebarView and NSTitlebarContainerView
|
||||
- (void)setTransparent:(BOOL)transparent; // Method of NSTitlebarView and
|
||||
// NSTitlebarContainerView
|
||||
|
||||
@end
|
||||
|
||||
@interface ChildView : NSView<
|
||||
#ifdef ACCESSIBILITY
|
||||
mozAccessible,
|
||||
#endif
|
||||
mozView, NSTextInputClient>
|
||||
{
|
||||
@private
|
||||
// the nsChildView that created the view. It retains this NSView, so
|
||||
// the link back to it must be weak.
|
||||
nsChildView* mGeckoChild;
|
||||
|
||||
// Text input handler for mGeckoChild and us. Note that this is a weak
|
||||
// reference. Ideally, this should be a strong reference but a ChildView
|
||||
// object can live longer than the mGeckoChild that owns it. And if
|
||||
// mTextInputHandler were a strong reference, this would make it difficult
|
||||
// for Gecko's leak detector to detect leaked TextInputHandler objects.
|
||||
// This is initialized by [mozView installTextInputHandler:aHandler] and
|
||||
// cleared by [mozView uninstallTextInputHandler].
|
||||
mozilla::widget::TextInputHandler* mTextInputHandler; // [WEAK]
|
||||
|
||||
// when mouseDown: is called, we store its event here (strong)
|
||||
NSEvent* mLastMouseDownEvent;
|
||||
|
||||
// Needed for IME support in e10s mode. Strong.
|
||||
NSEvent* mLastKeyDownEvent;
|
||||
|
||||
// Whether the last mouse down event was blocked from Gecko.
|
||||
BOOL mBlockedLastMouseDown;
|
||||
|
||||
// when acceptsFirstMouse: is called, we store the event here (strong)
|
||||
NSEvent* mClickThroughMouseDownEvent;
|
||||
|
||||
// WheelStart/Stop events should always come in pairs. This BOOL records the
|
||||
// last received event so that, when we receive one of the events, we make sure
|
||||
// to send its pair event first, in case we didn't yet for any reason.
|
||||
BOOL mExpectingWheelStop;
|
||||
|
||||
// Set to YES when our GL surface has been updated and we need to call
|
||||
// updateGLContext before we composite.
|
||||
BOOL mNeedsGLUpdate;
|
||||
|
||||
// Holds our drag service across multiple drag calls. The reference to the
|
||||
// service is obtained when the mouse enters the view and is released when
|
||||
// the mouse exits or there is a drop. This prevents us from having to
|
||||
// re-establish the connection to the service manager many times per second
|
||||
// when handling |draggingUpdated:| messages.
|
||||
nsIDragService* mDragService;
|
||||
|
||||
NSOpenGLContext *mGLContext;
|
||||
|
||||
// Simple gestures support
|
||||
//
|
||||
// mGestureState is used to detect when Cocoa has called both
|
||||
// magnifyWithEvent and rotateWithEvent within the same
|
||||
// beginGestureWithEvent and endGestureWithEvent sequence. We
|
||||
// discard the spurious gesture event so as not to confuse Gecko.
|
||||
//
|
||||
// mCumulativeMagnification keeps track of the total amount of
|
||||
// magnification peformed during a magnify gesture so that we can
|
||||
// send that value with the final MozMagnifyGesture event.
|
||||
//
|
||||
// mCumulativeRotation keeps track of the total amount of rotation
|
||||
// performed during a rotate gesture so we can send that value with
|
||||
// the final MozRotateGesture event.
|
||||
enum {
|
||||
eGestureState_None,
|
||||
eGestureState_StartGesture,
|
||||
eGestureState_MagnifyGesture,
|
||||
eGestureState_RotateGesture
|
||||
} mGestureState;
|
||||
float mCumulativeMagnification;
|
||||
float mCumulativeRotation;
|
||||
|
||||
#ifdef __LP64__
|
||||
// Support for fluid swipe tracking.
|
||||
BOOL* mCancelSwipeAnimation;
|
||||
#endif
|
||||
|
||||
// Whether this uses off-main-thread compositing.
|
||||
BOOL mUsingOMTCompositor;
|
||||
|
||||
// The mask image that's used when painting into the titlebar using basic
|
||||
// CGContext painting (i.e. non-accelerated).
|
||||
CGImageRef mTopLeftCornerMask;
|
||||
|
||||
// Subviews of self, which act as container views for vibrancy views and
|
||||
// non-draggable views.
|
||||
NSView* mVibrancyViewsContainer; // [STRONG]
|
||||
NSView* mNonDraggableViewsContainer; // [STRONG]
|
||||
|
||||
// The view that does our drawing. This is a subview of self so that it can
|
||||
// be ordered on top of mVibrancyViewsContainer.
|
||||
PixelHostingView* mPixelHostingView;
|
||||
}
|
||||
|
||||
// class initialization
|
||||
+ (void)initialize;
|
||||
|
||||
+ (void)registerViewForDraggedTypes:(NSView*)aView;
|
||||
|
||||
// these are sent to the first responder when the window key status changes
|
||||
- (void)viewsWindowDidBecomeKey;
|
||||
- (void)viewsWindowDidResignKey;
|
||||
|
||||
// Stop NSView hierarchy being changed during [ChildView drawRect:]
|
||||
- (void)delayedTearDown;
|
||||
|
||||
- (void)sendFocusEvent:(mozilla::EventMessage)eventMessage;
|
||||
|
||||
- (void)handleMouseMoved:(NSEvent*)aEvent;
|
||||
|
||||
- (void)sendMouseEnterOrExitEvent:(NSEvent*)aEvent
|
||||
enter:(BOOL)aEnter
|
||||
exitFrom:(mozilla::WidgetMouseEvent::ExitFrom)aExitFrom;
|
||||
|
||||
- (void)updateGLContext;
|
||||
- (void)_surfaceNeedsUpdate:(NSNotification*)notification;
|
||||
|
||||
- (bool)preRender:(NSOpenGLContext *)aGLContext;
|
||||
- (void)postRender:(NSOpenGLContext *)aGLContext;
|
||||
|
||||
- (NSView*)vibrancyViewsContainer;
|
||||
- (NSView*)nonDraggableViewsContainer;
|
||||
- (NSView*)pixelHostingView;
|
||||
|
||||
- (BOOL)isCoveringTitlebar;
|
||||
|
||||
- (void)viewWillStartLiveResize;
|
||||
- (void)viewDidEndLiveResize;
|
||||
|
||||
- (NSColor*)vibrancyFillColorForThemeGeometryType:(nsITheme::ThemeGeometryType)aThemeGeometryType;
|
||||
- (NSColor*)vibrancyFontSmoothingBackgroundColorForThemeGeometryType:(nsITheme::ThemeGeometryType)aThemeGeometryType;
|
||||
|
||||
// Simple gestures support
|
||||
//
|
||||
// XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
|
||||
// rotateWithEvent, and endGestureWithEvent methods are part of a
|
||||
// PRIVATE interface exported by nsResponder and reverse-engineering
|
||||
// was necessary to obtain the methods' prototypes. Thus, Apple may
|
||||
// change the interface in the future without notice.
|
||||
//
|
||||
// The prototypes were obtained from the following link:
|
||||
// http://cocoadex.com/2008/02/nsevent-modifications-swipe-ro.html
|
||||
- (void)swipeWithEvent:(NSEvent *)anEvent;
|
||||
- (void)beginGestureWithEvent:(NSEvent *)anEvent;
|
||||
- (void)magnifyWithEvent:(NSEvent *)anEvent;
|
||||
- (void)smartMagnifyWithEvent:(NSEvent *)anEvent;
|
||||
- (void)rotateWithEvent:(NSEvent *)anEvent;
|
||||
- (void)endGestureWithEvent:(NSEvent *)anEvent;
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)anEvent;
|
||||
|
||||
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC;
|
||||
|
||||
- (NSEvent*)lastKeyDownEvent;
|
||||
@end
|
||||
|
||||
class ChildViewMouseTracker {
|
||||
|
||||
public:
|
||||
|
||||
static void MouseMoved(NSEvent* aEvent);
|
||||
static void MouseScrolled(NSEvent* aEvent);
|
||||
static void OnDestroyView(ChildView* aView);
|
||||
static void OnDestroyWindow(NSWindow* aWindow);
|
||||
static BOOL WindowAcceptsEvent(NSWindow* aWindow, NSEvent* aEvent,
|
||||
ChildView* aView, BOOL isClickThrough = NO);
|
||||
static void MouseExitedWindow(NSEvent* aEvent);
|
||||
static void MouseEnteredWindow(NSEvent* aEvent);
|
||||
static void ReEvaluateMouseEnterState(NSEvent* aEvent = nil, ChildView* aOldView = nil);
|
||||
static void ResendLastMouseMoveEvent();
|
||||
static ChildView* ViewForEvent(NSEvent* aEvent);
|
||||
|
||||
static ChildView* sLastMouseEventView;
|
||||
static NSEvent* sLastMouseMoveEvent;
|
||||
static NSWindow* sWindowUnderMouse;
|
||||
static NSPoint sLastScrollEventScreenLocation;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// nsChildView
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class nsChildView : public nsBaseWidget
|
||||
{
|
||||
private:
|
||||
typedef nsBaseWidget Inherited;
|
||||
typedef mozilla::layers::IAPZCTreeManager IAPZCTreeManager;
|
||||
|
||||
public:
|
||||
nsChildView();
|
||||
|
||||
// nsIWidget interface
|
||||
virtual MOZ_MUST_USE nsresult Create(nsIWidget* aParent,
|
||||
nsNativeWidget aNativeParent,
|
||||
const LayoutDeviceIntRect& aRect,
|
||||
nsWidgetInitData* aInitData = nullptr)
|
||||
override;
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
||||
NS_IMETHOD Show(bool aState) override;
|
||||
virtual bool IsVisible() const override;
|
||||
|
||||
NS_IMETHOD SetParent(nsIWidget* aNewParent) override;
|
||||
virtual nsIWidget* GetParent(void) override;
|
||||
virtual float GetDPI() override;
|
||||
|
||||
NS_IMETHOD Move(double aX, double aY) override;
|
||||
NS_IMETHOD Resize(double aWidth, double aHeight, bool aRepaint) override;
|
||||
NS_IMETHOD Resize(double aX, double aY,
|
||||
double aWidth, double aHeight, bool aRepaint) override;
|
||||
|
||||
NS_IMETHOD Enable(bool aState) override;
|
||||
virtual bool IsEnabled() const override;
|
||||
NS_IMETHOD SetFocus(bool aRaise) override;
|
||||
virtual LayoutDeviceIntRect GetBounds() override;
|
||||
virtual LayoutDeviceIntRect GetClientBounds() override;
|
||||
virtual LayoutDeviceIntRect GetScreenBounds() override;
|
||||
|
||||
// Returns the "backing scale factor" of the view's window, which is the
|
||||
// ratio of pixels in the window's backing store to Cocoa points. Prior to
|
||||
// HiDPI support in OS X 10.7, this was always 1.0, but in HiDPI mode it
|
||||
// will be 2.0 (and might potentially other values as screen resolutions
|
||||
// evolve). This gives the relationship between what Gecko calls "device
|
||||
// pixels" and the Cocoa "points" coordinate system.
|
||||
CGFloat BackingScaleFactor() const;
|
||||
|
||||
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() final {
|
||||
return mozilla::DesktopToLayoutDeviceScale(BackingScaleFactor());
|
||||
}
|
||||
|
||||
// Call if the window's backing scale factor changes - i.e., it is moved
|
||||
// between HiDPI and non-HiDPI screens
|
||||
void BackingScaleFactorChanged();
|
||||
|
||||
virtual double GetDefaultScaleInternal() override;
|
||||
|
||||
virtual int32_t RoundsWidgetCoordinatesTo() override;
|
||||
|
||||
NS_IMETHOD Invalidate(const LayoutDeviceIntRect &aRect) override;
|
||||
|
||||
virtual void* GetNativeData(uint32_t aDataType) override;
|
||||
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
|
||||
virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
|
||||
virtual bool ShowsResizeIndicator(LayoutDeviceIntRect* aResizerRect) override;
|
||||
|
||||
static bool ConvertStatus(nsEventStatus aStatus)
|
||||
{ return aStatus == nsEventStatus_eConsumeNoDefault; }
|
||||
NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
|
||||
nsEventStatus& aStatus) override;
|
||||
|
||||
virtual bool WidgetTypeSupportsAcceleration() override;
|
||||
virtual bool ShouldUseOffMainThreadCompositing() override;
|
||||
|
||||
NS_IMETHOD SetCursor(nsCursor aCursor) override;
|
||||
NS_IMETHOD SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY) override;
|
||||
|
||||
NS_IMETHOD SetTitle(const nsAString& title) override;
|
||||
|
||||
NS_IMETHOD GetAttention(int32_t aCycleCount) override;
|
||||
|
||||
virtual bool HasPendingInputEvent() override;
|
||||
|
||||
NS_IMETHOD ActivateNativeMenuItemAt(const nsAString& indexString) override;
|
||||
NS_IMETHOD ForceUpdateNativeMenuAt(const nsAString& indexString) override;
|
||||
NS_IMETHOD GetSelectionAsPlaintext(nsAString& aResult) override;
|
||||
|
||||
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
|
||||
const InputContextAction& aAction) override;
|
||||
NS_IMETHOD_(InputContext) GetInputContext() override;
|
||||
NS_IMETHOD_(TextEventDispatcherListener*)
|
||||
GetNativeTextEventDispatcherListener() override;
|
||||
NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) override;
|
||||
NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
|
||||
NativeKeyBindingsType aType,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void* aCallbackData) override;
|
||||
bool ExecuteNativeKeyBindingRemapped(
|
||||
NativeKeyBindingsType aType,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void* aCallbackData,
|
||||
uint32_t aGeckoKeyCode,
|
||||
uint32_t aCocoaKeyCode);
|
||||
virtual nsIMEUpdatePreference GetIMEUpdatePreference() override;
|
||||
|
||||
virtual nsTransparencyMode GetTransparencyMode() override;
|
||||
virtual void SetTransparencyMode(nsTransparencyMode aMode) override;
|
||||
|
||||
virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
|
||||
int32_t aNativeKeyCode,
|
||||
uint32_t aModifierFlags,
|
||||
const nsAString& aCharacters,
|
||||
const nsAString& aUnmodifiedCharacters,
|
||||
nsIObserver* aObserver) override;
|
||||
|
||||
virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
|
||||
uint32_t aNativeMessage,
|
||||
uint32_t aModifierFlags,
|
||||
nsIObserver* aObserver) override;
|
||||
|
||||
virtual nsresult SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
|
||||
nsIObserver* aObserver) override
|
||||
{ return SynthesizeNativeMouseEvent(aPoint, NSMouseMoved, 0, aObserver); }
|
||||
virtual nsresult SynthesizeNativeMouseScrollEvent(LayoutDeviceIntPoint aPoint,
|
||||
uint32_t aNativeMessage,
|
||||
double aDeltaX,
|
||||
double aDeltaY,
|
||||
double aDeltaZ,
|
||||
uint32_t aModifierFlags,
|
||||
uint32_t aAdditionalFlags,
|
||||
nsIObserver* aObserver) override;
|
||||
virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
|
||||
TouchPointerState aPointerState,
|
||||
LayoutDeviceIntPoint aPoint,
|
||||
double aPointerPressure,
|
||||
uint32_t aPointerOrientation,
|
||||
nsIObserver* aObserver) override;
|
||||
|
||||
// Mac specific methods
|
||||
|
||||
virtual bool DispatchWindowEvent(mozilla::WidgetGUIEvent& event);
|
||||
|
||||
void WillPaintWindow();
|
||||
bool PaintWindow(LayoutDeviceIntRegion aRegion);
|
||||
bool PaintWindowInContext(CGContextRef aContext, const LayoutDeviceIntRegion& aRegion,
|
||||
mozilla::gfx::IntSize aSurfaceSize);
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
already_AddRefed<mozilla::a11y::Accessible> GetDocumentAccessible();
|
||||
#endif
|
||||
|
||||
virtual void CreateCompositor() override;
|
||||
virtual void PrepareWindowEffects() override;
|
||||
virtual void CleanupWindowEffects() override;
|
||||
virtual bool PreRender(mozilla::widget::WidgetRenderingContext* aContext) override;
|
||||
virtual void PostRender(mozilla::widget::WidgetRenderingContext* aContext) override;
|
||||
virtual void DrawWindowOverlay(mozilla::widget::WidgetRenderingContext* aManager,
|
||||
LayoutDeviceIntRect aRect) override;
|
||||
|
||||
virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override;
|
||||
|
||||
virtual void UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) override;
|
||||
LayoutDeviceIntRegion GetNonDraggableRegion() { return mNonDraggableRegion.Region(); }
|
||||
|
||||
virtual void ReportSwipeStarted(uint64_t aInputBlockId, bool aStartSwipe) override;
|
||||
|
||||
virtual void LookUpDictionary(
|
||||
const nsAString& aText,
|
||||
const nsTArray<mozilla::FontRange>& aFontRangeArray,
|
||||
const bool aIsVertical,
|
||||
const LayoutDeviceIntPoint& aPoint) override;
|
||||
|
||||
void ResetParent();
|
||||
|
||||
static bool DoHasPendingInputEvent();
|
||||
static uint32_t GetCurrentInputEventCount();
|
||||
static void UpdateCurrentInputEventCount();
|
||||
|
||||
NSView<mozView>* GetEditorView();
|
||||
|
||||
nsCocoaWindow* GetXULWindowWidget();
|
||||
|
||||
virtual void ReparentNativeWidget(nsIWidget* aNewParent) override;
|
||||
|
||||
mozilla::widget::TextInputHandler* GetTextInputHandler()
|
||||
{
|
||||
return mTextInputHandler;
|
||||
}
|
||||
|
||||
void ClearVibrantAreas();
|
||||
NSColor* VibrancyFillColorForThemeGeometryType(nsITheme::ThemeGeometryType aThemeGeometryType);
|
||||
NSColor* VibrancyFontSmoothingBackgroundColorForThemeGeometryType(nsITheme::ThemeGeometryType aThemeGeometryType);
|
||||
|
||||
// unit conversion convenience functions
|
||||
int32_t CocoaPointsToDevPixels(CGFloat aPts) const {
|
||||
return nsCocoaUtils::CocoaPointsToDevPixels(aPts, BackingScaleFactor());
|
||||
}
|
||||
LayoutDeviceIntPoint CocoaPointsToDevPixels(const NSPoint& aPt) const {
|
||||
return nsCocoaUtils::CocoaPointsToDevPixels(aPt, BackingScaleFactor());
|
||||
}
|
||||
LayoutDeviceIntPoint CocoaPointsToDevPixelsRoundDown(const NSPoint& aPt) const {
|
||||
return nsCocoaUtils::CocoaPointsToDevPixelsRoundDown(aPt, BackingScaleFactor());
|
||||
}
|
||||
LayoutDeviceIntRect CocoaPointsToDevPixels(const NSRect& aRect) const {
|
||||
return nsCocoaUtils::CocoaPointsToDevPixels(aRect, BackingScaleFactor());
|
||||
}
|
||||
CGFloat DevPixelsToCocoaPoints(int32_t aPixels) const {
|
||||
return nsCocoaUtils::DevPixelsToCocoaPoints(aPixels, BackingScaleFactor());
|
||||
}
|
||||
NSRect DevPixelsToCocoaPoints(const LayoutDeviceIntRect& aRect) const {
|
||||
return nsCocoaUtils::DevPixelsToCocoaPoints(aRect, BackingScaleFactor());
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::gfx::DrawTarget>
|
||||
StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
|
||||
mozilla::layers::BufferMode* aBufferMode) override;
|
||||
void EndRemoteDrawing() override;
|
||||
void CleanupRemoteDrawing() override;
|
||||
bool InitCompositor(mozilla::layers::Compositor* aCompositor) override;
|
||||
|
||||
NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
|
||||
int32_t aPanelX, int32_t aPanelY,
|
||||
nsString& aCommitted) override;
|
||||
|
||||
virtual void SetPluginFocused(bool& aFocused) override;
|
||||
|
||||
bool IsPluginFocused() { return mPluginFocused; }
|
||||
|
||||
virtual LayoutDeviceIntPoint GetClientOffset() override;
|
||||
|
||||
void DispatchAPZWheelInputEvent(mozilla::InputData& aEvent, bool aCanTriggerSwipe);
|
||||
|
||||
void SwipeFinished();
|
||||
|
||||
protected:
|
||||
virtual ~nsChildView();
|
||||
|
||||
void ReportMoveEvent();
|
||||
void ReportSizeEvent();
|
||||
|
||||
void TearDownView();
|
||||
|
||||
virtual already_AddRefed<nsIWidget>
|
||||
AllocateChildPopupWidget() override
|
||||
{
|
||||
static NS_DEFINE_IID(kCPopUpCID, NS_POPUP_CID);
|
||||
nsCOMPtr<nsIWidget> widget = do_CreateInstance(kCPopUpCID);
|
||||
return widget.forget();
|
||||
}
|
||||
|
||||
void ConfigureAPZCTreeManager() override;
|
||||
void ConfigureAPZControllerThread() override;
|
||||
|
||||
void DoRemoteComposition(const LayoutDeviceIntRect& aRenderRect);
|
||||
|
||||
// Overlay drawing functions for OpenGL drawing
|
||||
void DrawWindowOverlay(mozilla::layers::GLManager* aManager, LayoutDeviceIntRect aRect);
|
||||
void MaybeDrawResizeIndicator(mozilla::layers::GLManager* aManager);
|
||||
void MaybeDrawRoundedCorners(mozilla::layers::GLManager* aManager, const LayoutDeviceIntRect& aRect);
|
||||
void MaybeDrawTitlebar(mozilla::layers::GLManager* aManager);
|
||||
|
||||
// Redraw the contents of mTitlebarCGContext on the main thread, as
|
||||
// determined by mDirtyTitlebarRegion.
|
||||
void UpdateTitlebarCGContext();
|
||||
|
||||
LayoutDeviceIntRect RectContainingTitlebarControls();
|
||||
void UpdateVibrancy(const nsTArray<ThemeGeometry>& aThemeGeometries);
|
||||
mozilla::VibrancyManager& EnsureVibrancyManager();
|
||||
|
||||
nsIWidget* GetWidgetForListenerEvents();
|
||||
|
||||
struct SwipeInfo {
|
||||
bool wantsSwipe;
|
||||
uint32_t allowedDirections;
|
||||
};
|
||||
|
||||
SwipeInfo SendMayStartSwipe(const mozilla::PanGestureInput& aSwipeStartEvent);
|
||||
void TrackScrollEventAsSwipe(const mozilla::PanGestureInput& aSwipeStartEvent,
|
||||
uint32_t aAllowedDirections);
|
||||
|
||||
protected:
|
||||
|
||||
ChildView<mozView>* mView; // my parallel cocoa view, [STRONG]
|
||||
RefPtr<mozilla::widget::TextInputHandler> mTextInputHandler;
|
||||
InputContext mInputContext;
|
||||
|
||||
NSView<mozView>* mParentView;
|
||||
nsIWidget* mParentWidget;
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
// weak ref to this childview's associated mozAccessible for speed reasons
|
||||
// (we get queried for it *a lot* but don't want to own it)
|
||||
nsWeakPtr mAccessible;
|
||||
#endif
|
||||
|
||||
// Protects the view from being teared down while a composition is in
|
||||
// progress on the compositor thread.
|
||||
mozilla::Mutex mViewTearDownLock;
|
||||
|
||||
mozilla::Mutex mEffectsLock;
|
||||
|
||||
// May be accessed from any thread, protected
|
||||
// by mEffectsLock.
|
||||
bool mShowsResizeIndicator;
|
||||
LayoutDeviceIntRect mResizeIndicatorRect;
|
||||
bool mHasRoundedBottomCorners;
|
||||
int mDevPixelCornerRadius;
|
||||
bool mIsCoveringTitlebar;
|
||||
bool mIsFullscreen;
|
||||
bool mIsOpaque;
|
||||
LayoutDeviceIntRect mTitlebarRect;
|
||||
|
||||
// The area of mTitlebarCGContext that needs to be redrawn during the next
|
||||
// transaction. Accessed from any thread, protected by mEffectsLock.
|
||||
LayoutDeviceIntRegion mUpdatedTitlebarRegion;
|
||||
CGContextRef mTitlebarCGContext;
|
||||
|
||||
// Compositor thread only
|
||||
mozilla::UniquePtr<mozilla::widget::RectTextureImage> mResizerImage;
|
||||
mozilla::UniquePtr<mozilla::widget::RectTextureImage> mCornerMaskImage;
|
||||
mozilla::UniquePtr<mozilla::widget::RectTextureImage> mTitlebarImage;
|
||||
mozilla::UniquePtr<mozilla::widget::RectTextureImage> mBasicCompositorImage;
|
||||
|
||||
// The area of mTitlebarCGContext that has changed and needs to be
|
||||
// uploaded to to mTitlebarImage. Main thread only.
|
||||
nsIntRegion mDirtyTitlebarRegion;
|
||||
|
||||
mozilla::ViewRegion mNonDraggableRegion;
|
||||
|
||||
// Cached value of [mView backingScaleFactor], to avoid sending two obj-c
|
||||
// messages (respondsToSelector, backingScaleFactor) every time we need to
|
||||
// use it.
|
||||
// ** We'll need to reinitialize this if the backing resolution changes. **
|
||||
mutable CGFloat mBackingScaleFactor;
|
||||
|
||||
bool mVisible;
|
||||
bool mDrawing;
|
||||
bool mIsDispatchPaint; // Is a paint event being dispatched
|
||||
|
||||
bool mPluginFocused;
|
||||
|
||||
// Used in OMTC BasicLayers mode. Presents the BasicCompositor result
|
||||
// surface to the screen using an OpenGL context.
|
||||
mozilla::UniquePtr<GLPresenter> mGLPresenter;
|
||||
|
||||
mozilla::UniquePtr<mozilla::VibrancyManager> mVibrancyManager;
|
||||
RefPtr<mozilla::SwipeTracker> mSwipeTracker;
|
||||
mozilla::UniquePtr<mozilla::SwipeEventQueue> mSwipeEventQueue;
|
||||
|
||||
// Only used for drawRect-based painting in popups.
|
||||
RefPtr<mozilla::gfx::DrawTarget> mBackingSurface;
|
||||
|
||||
// This flag is only used when APZ is off. It indicates that the current pan
|
||||
// gesture was processed as a swipe. Sometimes the swipe animation can finish
|
||||
// before momentum events of the pan gesture have stopped firing, so this
|
||||
// flag tells us that we shouldn't allow the remaining events to cause
|
||||
// scrolling. It is reset to false once a new gesture starts (as indicated by
|
||||
// a PANGESTURE_(MAY)START event).
|
||||
bool mCurrentPanGestureBelongsToSwipe;
|
||||
|
||||
static uint32_t sLastInputEventCount;
|
||||
|
||||
void ReleaseTitlebarCGContext();
|
||||
|
||||
// This is used by SynthesizeNativeTouchPoint to maintain state between
|
||||
// multiple synthesized points
|
||||
mozilla::UniquePtr<mozilla::MultiTouchInput> mSynthesizedTouchInput;
|
||||
};
|
||||
|
||||
#endif // nsChildView_h_
|
||||
@@ -1,55 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsClipboard_h_
|
||||
#define nsClipboard_h_
|
||||
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
class nsITransferable;
|
||||
|
||||
class nsClipboard : public nsIClipboard
|
||||
{
|
||||
|
||||
public:
|
||||
nsClipboard();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICLIPBOARD
|
||||
|
||||
// On macOS, cache the transferable of the current selection (chrome/content)
|
||||
// in the parent process. This is needed for the services menu which
|
||||
// requires synchronous access to the current selection.
|
||||
static mozilla::StaticRefPtr<nsITransferable> sSelectionCache;
|
||||
|
||||
// Helper methods, used also by nsDragService
|
||||
static NSDictionary* PasteboardDictFromTransferable(nsITransferable *aTransferable);
|
||||
static bool IsStringType(const nsCString& aMIMEType, NSString** aPasteboardType);
|
||||
static NSString* WrapHtmlForSystemPasteboard(NSString* aString);
|
||||
static nsresult TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteboard *pboard);
|
||||
|
||||
protected:
|
||||
|
||||
// impelement the native clipboard behavior
|
||||
NS_IMETHOD SetNativeClipboardData(int32_t aWhichClipboard);
|
||||
NS_IMETHOD GetNativeClipboardData(nsITransferable * aTransferable, int32_t aWhichClipboard);
|
||||
void ClearSelectionCache();
|
||||
void SetSelectionCache(nsITransferable* aTransferable);
|
||||
|
||||
private:
|
||||
virtual ~nsClipboard();
|
||||
int32_t mCachedClipboard;
|
||||
int32_t mChangeCount; // Set to the native change count after any modification of the clipboard.
|
||||
|
||||
bool mIgnoreEmptyNotification;
|
||||
nsCOMPtr<nsIClipboardOwner> mClipboardOwner;
|
||||
nsCOMPtr<nsITransferable> mTransferable;
|
||||
};
|
||||
|
||||
#endif // nsClipboard_h_
|
||||
@@ -1,775 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "gfxPlatform.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsClipboard.h"
|
||||
#include "nsString.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsPrimitiveHelpers.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsDragService.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
|
||||
using mozilla::gfx::DataSourceSurface;
|
||||
using mozilla::gfx::SourceSurface;
|
||||
using mozilla::LogLevel;
|
||||
|
||||
// Screenshots use the (undocumented) png pasteboard type.
|
||||
#define IMAGE_PASTEBOARD_TYPES NSTIFFPboardType, @"Apple PNG pasteboard type", nil
|
||||
|
||||
extern PRLogModuleInfo* sCocoaLog;
|
||||
|
||||
extern void EnsureLogInitialized();
|
||||
|
||||
mozilla::StaticRefPtr<nsITransferable> nsClipboard::sSelectionCache;
|
||||
|
||||
nsClipboard::nsClipboard()
|
||||
: mCachedClipboard(-1)
|
||||
, mChangeCount(0)
|
||||
, mIgnoreEmptyNotification(false)
|
||||
{
|
||||
EnsureLogInitialized();
|
||||
}
|
||||
|
||||
nsClipboard::~nsClipboard()
|
||||
{
|
||||
EmptyClipboard(kGlobalClipboard);
|
||||
EmptyClipboard(kFindClipboard);
|
||||
ClearSelectionCache();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard)
|
||||
|
||||
// We separate this into its own function because after an @try, all local
|
||||
// variables within that function get marked as volatile, and our C++ type
|
||||
// system doesn't like volatile things.
|
||||
static NSData*
|
||||
GetDataFromPasteboard(NSPasteboard* aPasteboard, NSString* aType)
|
||||
{
|
||||
NSData *data = nil;
|
||||
@try {
|
||||
data = [aPasteboard dataForType:aType];
|
||||
} @catch (NSException* e) {
|
||||
NS_WARNING(nsPrintfCString("Exception raised while getting data from the pasteboard: \"%s - %s\"",
|
||||
[[e name] UTF8String], [[e reason] UTF8String]).get());
|
||||
mozilla::Unused << e;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
nsClipboard::SetSelectionCache(nsITransferable *aTransferable)
|
||||
{
|
||||
sSelectionCache = aTransferable;
|
||||
}
|
||||
|
||||
void
|
||||
nsClipboard::ClearSelectionCache()
|
||||
{
|
||||
sSelectionCache = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::SetNativeClipboardData(int32_t aWhichClipboard)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !mTransferable)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mIgnoreEmptyNotification = true;
|
||||
|
||||
NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(mTransferable);
|
||||
if (!pasteboardOutputDict)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
unsigned int outputCount = [pasteboardOutputDict count];
|
||||
NSArray* outputKeys = [pasteboardOutputDict allKeys];
|
||||
NSPasteboard* cocoaPasteboard;
|
||||
if (aWhichClipboard == kFindClipboard) {
|
||||
cocoaPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
|
||||
[cocoaPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
|
||||
} else {
|
||||
// Write everything else out to the general pasteboard.
|
||||
cocoaPasteboard = [NSPasteboard generalPasteboard];
|
||||
[cocoaPasteboard declareTypes:outputKeys owner:nil];
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < outputCount; i++) {
|
||||
NSString* currentKey = [outputKeys objectAtIndex:i];
|
||||
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
||||
if (aWhichClipboard == kFindClipboard) {
|
||||
if (currentKey == NSStringPboardType)
|
||||
[cocoaPasteboard setString:currentValue forType:currentKey];
|
||||
} else {
|
||||
if (currentKey == NSStringPboardType ||
|
||||
currentKey == kCorePboardType_url ||
|
||||
currentKey == kCorePboardType_urld ||
|
||||
currentKey == kCorePboardType_urln) {
|
||||
[cocoaPasteboard setString:currentValue forType:currentKey];
|
||||
} else if (currentKey == NSHTMLPboardType) {
|
||||
[cocoaPasteboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
|
||||
forType:currentKey];
|
||||
} else {
|
||||
[cocoaPasteboard setData:currentValue forType:currentKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mCachedClipboard = aWhichClipboard;
|
||||
mChangeCount = [cocoaPasteboard changeCount];
|
||||
|
||||
mIgnoreEmptyNotification = false;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteboard *cocoaPasteboard)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
// get flavor list that includes all acceptable flavors (including ones obtained through conversion)
|
||||
nsCOMPtr<nsIArray> flavorList;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
uint32_t flavorCount;
|
||||
flavorList->GetLength(&flavorCount);
|
||||
|
||||
for (uint32_t i = 0; i < flavorCount; i++) {
|
||||
nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i);
|
||||
if (!currentFlavor)
|
||||
continue;
|
||||
|
||||
nsXPIDLCString flavorStr;
|
||||
currentFlavor->ToString(getter_Copies(flavorStr)); // i has a flavr
|
||||
|
||||
// printf("looking for clipboard data of type %s\n", flavorStr.get());
|
||||
|
||||
NSString *pboardType = nil;
|
||||
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
||||
NSString* pString = [cocoaPasteboard stringForType:pboardType];
|
||||
if (!pString)
|
||||
continue;
|
||||
|
||||
NSData* stringData;
|
||||
if ([pboardType isEqualToString:NSRTFPboardType]) {
|
||||
stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
|
||||
} else {
|
||||
stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
|
||||
}
|
||||
unsigned int dataLength = [stringData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
[stringData getBytes:clipboardDataPtr];
|
||||
|
||||
// The DOM only wants LF, so convert from MacOS line endings to DOM line endings.
|
||||
int32_t signedDataLength = dataLength;
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength);
|
||||
dataLength = signedDataLength;
|
||||
|
||||
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
||||
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
|
||||
if ((dataLength > 2) &&
|
||||
((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
|
||||
(clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
||||
dataLength -= sizeof(char16_t);
|
||||
clipboardDataPtrNoBOM += 1;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
|
||||
free(clipboardDataPtr);
|
||||
break;
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
NSString* type = [cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
|
||||
if (!type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSData* pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
|
||||
if (!pasteboardData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int dataLength = [pasteboardData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
[pasteboardData getBytes:clipboardDataPtr];
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
|
||||
aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
|
||||
free(clipboardDataPtr);
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kPNGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kGIFImageMime)) {
|
||||
// Figure out if there's data on the pasteboard we can grab (sanity check)
|
||||
NSString *type = [cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]];
|
||||
if (!type)
|
||||
continue;
|
||||
|
||||
// Read data off the clipboard
|
||||
NSData *pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
|
||||
if (!pasteboardData)
|
||||
continue;
|
||||
|
||||
// Figure out what type we're converting to
|
||||
CFStringRef outputType = NULL;
|
||||
if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime))
|
||||
outputType = CFSTR("public.jpeg");
|
||||
else if (flavorStr.EqualsLiteral(kPNGImageMime))
|
||||
outputType = CFSTR("public.png");
|
||||
else if (flavorStr.EqualsLiteral(kGIFImageMime))
|
||||
outputType = CFSTR("com.compuserve.gif");
|
||||
else
|
||||
continue;
|
||||
|
||||
// Use ImageIO to interpret the data on the clipboard and transcode.
|
||||
// Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
|
||||
// and safely in most cases (like ObjC). A notable exception is CFRelease.
|
||||
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
(NSNumber*)kCFBooleanTrue, kCGImageSourceShouldAllowFloat,
|
||||
(type == NSTIFFPboardType ? @"public.tiff" : @"public.png"),
|
||||
kCGImageSourceTypeIdentifierHint, nil];
|
||||
|
||||
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
|
||||
(CFDictionaryRef)options);
|
||||
NSMutableData *encodedData = [NSMutableData data];
|
||||
CGImageDestinationRef dest = CGImageDestinationCreateWithData((CFMutableDataRef)encodedData,
|
||||
outputType,
|
||||
1, NULL);
|
||||
CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
|
||||
bool successfullyConverted = CGImageDestinationFinalize(dest);
|
||||
|
||||
if (successfullyConverted) {
|
||||
// Put the converted data in a form Gecko can understand
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
NS_NewByteInputStream(getter_AddRefs(byteStream), (const char*)[encodedData bytes],
|
||||
[encodedData length], NS_ASSIGNMENT_COPY);
|
||||
|
||||
aTransferable->SetTransferData(flavorStr, byteStream, sizeof(nsIInputStream*));
|
||||
}
|
||||
|
||||
if (dest)
|
||||
CFRelease(dest);
|
||||
if (source)
|
||||
CFRelease(source);
|
||||
|
||||
if (successfullyConverted)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !aTransferable)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NSPasteboard* cocoaPasteboard;
|
||||
if (aWhichClipboard == kFindClipboard) {
|
||||
cocoaPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
|
||||
} else {
|
||||
cocoaPasteboard = [NSPasteboard generalPasteboard];
|
||||
}
|
||||
if (!cocoaPasteboard)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// get flavor list that includes all acceptable flavors (including ones obtained through conversion)
|
||||
nsCOMPtr<nsIArray> flavorList;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
uint32_t flavorCount;
|
||||
flavorList->GetLength(&flavorCount);
|
||||
|
||||
// If we were the last ones to put something on the pasteboard, then just use the cached
|
||||
// transferable. Otherwise clear it because it isn't relevant any more.
|
||||
if (mCachedClipboard == aWhichClipboard &&
|
||||
mChangeCount == [cocoaPasteboard changeCount]) {
|
||||
if (mTransferable) {
|
||||
for (uint32_t i = 0; i < flavorCount; i++) {
|
||||
nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i);
|
||||
if (!currentFlavor)
|
||||
continue;
|
||||
|
||||
nsXPIDLCString flavorStr;
|
||||
currentFlavor->ToString(getter_Copies(flavorStr));
|
||||
|
||||
nsCOMPtr<nsISupports> dataSupports;
|
||||
uint32_t dataSize = 0;
|
||||
rv = mTransferable->GetTransferData(flavorStr, getter_AddRefs(dataSupports), &dataSize);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aTransferable->SetTransferData(flavorStr, dataSupports, dataSize);
|
||||
return NS_OK; // maybe try to fill in more types? Is there a point?
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EmptyClipboard(aWhichClipboard);
|
||||
}
|
||||
|
||||
// at this point we can't satisfy the request from cache data so let's look
|
||||
// for things other people put on the system clipboard
|
||||
|
||||
return nsClipboard::TransferableFromPasteboard(aTransferable, cocoaPasteboard);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
// returns true if we have *any* of the passed in flavors available for pasting
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
|
||||
int32_t aWhichClipboard, bool* outResult)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
*outResult = false;
|
||||
|
||||
if ((aWhichClipboard != kGlobalClipboard) || !aFlavorList)
|
||||
return NS_OK;
|
||||
|
||||
// first see if we have data for this in our cached transferable
|
||||
if (mTransferable) {
|
||||
nsCOMPtr<nsIArray> transferableFlavorList;
|
||||
nsresult rv = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(transferableFlavorList));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
uint32_t transferableFlavorCount;
|
||||
transferableFlavorList->GetLength(&transferableFlavorCount);
|
||||
for (uint32_t j = 0; j < transferableFlavorCount; j++) {
|
||||
nsCOMPtr<nsISupportsCString> currentTransferableFlavor =
|
||||
do_QueryElementAt(transferableFlavorList, j);
|
||||
if (!currentTransferableFlavor)
|
||||
continue;
|
||||
nsXPIDLCString transferableFlavorStr;
|
||||
currentTransferableFlavor->ToString(getter_Copies(transferableFlavorStr));
|
||||
|
||||
for (uint32_t k = 0; k < aLength; k++) {
|
||||
if (transferableFlavorStr.Equals(aFlavorList[k])) {
|
||||
*outResult = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
|
||||
|
||||
for (uint32_t i = 0; i < aLength; i++) {
|
||||
nsDependentCString mimeType(aFlavorList[i]);
|
||||
NSString *pboardType = nil;
|
||||
|
||||
if (nsClipboard::IsStringType(mimeType, &pboardType)) {
|
||||
NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
|
||||
if (availableType && [availableType isEqualToString:pboardType]) {
|
||||
*outResult = true;
|
||||
break;
|
||||
}
|
||||
} else if (!strcmp(aFlavorList[i], kCustomTypesMime)) {
|
||||
NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
|
||||
if (availableType) {
|
||||
*outResult = true;
|
||||
break;
|
||||
}
|
||||
} else if (!strcmp(aFlavorList[i], kJPEGImageMime) ||
|
||||
!strcmp(aFlavorList[i], kJPGImageMime) ||
|
||||
!strcmp(aFlavorList[i], kPNGImageMime) ||
|
||||
!strcmp(aFlavorList[i], kGIFImageMime)) {
|
||||
NSString* availableType = [generalPBoard availableTypeFromArray:
|
||||
[NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]];
|
||||
if (availableType) {
|
||||
*outResult = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::SupportsFindClipboard(bool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This function converts anything that other applications might understand into the system format
|
||||
// and puts it into a dictionary which it returns.
|
||||
// static
|
||||
NSDictionary*
|
||||
nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
if (!aTransferable)
|
||||
return nil;
|
||||
|
||||
NSMutableDictionary* pasteboardOutputDict = [NSMutableDictionary dictionary];
|
||||
|
||||
nsCOMPtr<nsIArray> flavorList;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
|
||||
if (NS_FAILED(rv))
|
||||
return nil;
|
||||
|
||||
uint32_t flavorCount;
|
||||
flavorList->GetLength(&flavorCount);
|
||||
for (uint32_t i = 0; i < flavorCount; i++) {
|
||||
nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i);
|
||||
if (!currentFlavor)
|
||||
continue;
|
||||
|
||||
nsXPIDLCString flavorStr;
|
||||
currentFlavor->ToString(getter_Copies(flavorStr));
|
||||
|
||||
MOZ_LOG(sCocoaLog, LogLevel::Info, ("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i));
|
||||
|
||||
NSString *pboardType = nil;
|
||||
|
||||
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
||||
void* data = nullptr;
|
||||
uint32_t dataSize = 0;
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &dataSize);
|
||||
nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr, genericDataWrapper, &data, dataSize);
|
||||
|
||||
NSString* nativeString;
|
||||
if (data)
|
||||
nativeString = [NSString stringWithCharacters:(const unichar*)data length:(dataSize / sizeof(char16_t))];
|
||||
else
|
||||
nativeString = [NSString string];
|
||||
|
||||
// be nice to Carbon apps, normalize the receiver's contents using Form C.
|
||||
nativeString = [nativeString precomposedStringWithCanonicalMapping];
|
||||
|
||||
[pasteboardOutputDict setObject:nativeString forKey:pboardType];
|
||||
|
||||
free(data);
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
void* data = nullptr;
|
||||
uint32_t dataSize = 0;
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &dataSize);
|
||||
nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr, genericDataWrapper, &data, dataSize);
|
||||
|
||||
if (data) {
|
||||
NSData* nativeData = [NSData dataWithBytes:data length:dataSize];
|
||||
|
||||
[pasteboardOutputDict setObject:nativeData forKey:kCustomTypesPboardType];
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime) ||
|
||||
flavorStr.EqualsLiteral(kNativeImageMime)) {
|
||||
uint32_t dataSize = 0;
|
||||
nsCOMPtr<nsISupports> transferSupports;
|
||||
aTransferable->GetTransferData(flavorStr, getter_AddRefs(transferSupports), &dataSize);
|
||||
nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_QueryInterface(transferSupports));
|
||||
if (!ptrPrimitive)
|
||||
continue;
|
||||
|
||||
nsCOMPtr<nsISupports> primitiveData;
|
||||
ptrPrimitive->GetData(getter_AddRefs(primitiveData));
|
||||
|
||||
nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData));
|
||||
if (!image) {
|
||||
NS_WARNING("Image isn't an imgIContainer in transferable");
|
||||
continue;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> surface =
|
||||
image->GetFrame(imgIContainer::FRAME_CURRENT,
|
||||
imgIContainer::FLAG_SYNC_DECODE);
|
||||
if (!surface) {
|
||||
continue;
|
||||
}
|
||||
CGImageRef imageRef = NULL;
|
||||
rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef);
|
||||
if (NS_FAILED(rv) || !imageRef) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert the CGImageRef to TIFF data.
|
||||
CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||
CGImageDestinationRef destRef = CGImageDestinationCreateWithData(tiffData,
|
||||
CFSTR("public.tiff"),
|
||||
1,
|
||||
NULL);
|
||||
CGImageDestinationAddImage(destRef, imageRef, NULL);
|
||||
bool successfullyConverted = CGImageDestinationFinalize(destRef);
|
||||
|
||||
CGImageRelease(imageRef);
|
||||
if (destRef)
|
||||
CFRelease(destRef);
|
||||
|
||||
if (!successfullyConverted) {
|
||||
if (tiffData)
|
||||
CFRelease(tiffData);
|
||||
continue;
|
||||
}
|
||||
|
||||
[pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:NSTIFFPboardType];
|
||||
if (tiffData)
|
||||
CFRelease(tiffData);
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kFileMime)) {
|
||||
uint32_t len = 0;
|
||||
nsCOMPtr<nsISupports> genericFile;
|
||||
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericFile), &len);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file(do_QueryInterface(genericFile));
|
||||
if (!file) {
|
||||
nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericFile));
|
||||
|
||||
if (ptr) {
|
||||
ptr->GetData(getter_AddRefs(genericFile));
|
||||
file = do_QueryInterface(genericFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString fileURI;
|
||||
rv = file->GetPath(fileURI);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSString* str = nsCocoaUtils::ToNSString(fileURI);
|
||||
NSArray* fileList = [NSArray arrayWithObjects:str, nil];
|
||||
[pasteboardOutputDict setObject:fileList forKey:NSFilenamesPboardType];
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
|
||||
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:NSFilesPromisePboardType];
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kURLMime)) {
|
||||
uint32_t len = 0;
|
||||
nsCOMPtr<nsISupports> genericURL;
|
||||
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericURL), &len);
|
||||
nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL));
|
||||
|
||||
nsAutoString url;
|
||||
urlObject->GetData(url);
|
||||
|
||||
// A newline embedded in the URL means that the form is actually URL + title.
|
||||
int32_t newlinePos = url.FindChar(char16_t('\n'));
|
||||
if (newlinePos >= 0) {
|
||||
url.Truncate(newlinePos);
|
||||
|
||||
nsAutoString urlTitle;
|
||||
urlObject->GetData(urlTitle);
|
||||
urlTitle.Mid(urlTitle, newlinePos + 1, len - (newlinePos + 1));
|
||||
|
||||
NSString *nativeTitle = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(urlTitle.get())
|
||||
length:urlTitle.Length()];
|
||||
// be nice to Carbon apps, normalize the receiver's contents using Form C.
|
||||
[pasteboardOutputDict setObject:[nativeTitle precomposedStringWithCanonicalMapping] forKey:kCorePboardType_urln];
|
||||
// Also put the title out as 'urld', since some recipients will look for that.
|
||||
[pasteboardOutputDict setObject:[nativeTitle precomposedStringWithCanonicalMapping] forKey:kCorePboardType_urld];
|
||||
[nativeTitle release];
|
||||
}
|
||||
|
||||
// The Finder doesn't like getting random binary data aka
|
||||
// Unicode, so change it into an escaped URL containing only
|
||||
// ASCII.
|
||||
nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length());
|
||||
nsAutoCString escData;
|
||||
NS_EscapeURL(utf8Data.get(), utf8Data.Length(), esc_OnlyNonASCII|esc_AlwaysCopy, escData);
|
||||
|
||||
// printf("Escaped url is %s, length %d\n", escData.get(), escData.Length());
|
||||
|
||||
NSString *nativeURL = [NSString stringWithUTF8String:escData.get()];
|
||||
[pasteboardOutputDict setObject:nativeURL forKey:kCorePboardType_url];
|
||||
}
|
||||
// If it wasn't a type that we recognize as exportable we don't put it on the system
|
||||
// clipboard. We'll just access it from our cached transferable when we need it.
|
||||
}
|
||||
|
||||
return pasteboardOutputDict;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPasteboardType)
|
||||
{
|
||||
if (aMIMEType.EqualsLiteral(kUnicodeMime)) {
|
||||
*aPasteboardType = NSStringPboardType;
|
||||
return true;
|
||||
} else if (aMIMEType.EqualsLiteral(kRTFMime)) {
|
||||
*aPasteboardType = NSRTFPboardType;
|
||||
return true;
|
||||
} else if (aMIMEType.EqualsLiteral(kHTMLMime)) {
|
||||
*aPasteboardType = NSHTMLPboardType;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString)
|
||||
{
|
||||
NSString* wrapped =
|
||||
[NSString stringWithFormat:
|
||||
@"<html>"
|
||||
"<head>"
|
||||
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"%@"
|
||||
"</body>"
|
||||
"</html>", aString];
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transferable object
|
||||
*
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::SetData(nsITransferable* aTransferable, nsIClipboardOwner* anOwner,
|
||||
int32_t aWhichClipboard)
|
||||
{
|
||||
NS_ASSERTION (aTransferable, "clipboard given a null transferable");
|
||||
|
||||
if (aWhichClipboard == kSelectionCache) {
|
||||
if (aTransferable) {
|
||||
SetSelectionCache(aTransferable);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (aTransferable == mTransferable && anOwner == mClipboardOwner) {
|
||||
return NS_OK;
|
||||
}
|
||||
bool selectClipPresent;
|
||||
SupportsSelectionClipboard(&selectClipPresent);
|
||||
bool findClipPresent;
|
||||
SupportsFindClipboard(&findClipPresent);
|
||||
if (!selectClipPresent && !findClipPresent && aWhichClipboard != kGlobalClipboard) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
EmptyClipboard(aWhichClipboard);
|
||||
|
||||
mClipboardOwner = anOwner;
|
||||
mTransferable = aTransferable;
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (mTransferable) {
|
||||
rv = SetNativeClipboardData(aWhichClipboard);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the transferable object
|
||||
*
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard)
|
||||
{
|
||||
NS_ASSERTION (aTransferable, "clipboard given a null transferable");
|
||||
|
||||
bool selectClipPresent;
|
||||
SupportsSelectionClipboard(&selectClipPresent);
|
||||
bool findClipPresent;
|
||||
SupportsFindClipboard(&findClipPresent);
|
||||
if (!selectClipPresent && !findClipPresent && aWhichClipboard != kGlobalClipboard)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (aTransferable) {
|
||||
return GetNativeClipboardData(aTransferable, aWhichClipboard);
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::EmptyClipboard(int32_t aWhichClipboard)
|
||||
{
|
||||
if (aWhichClipboard == kSelectionCache) {
|
||||
ClearSelectionCache();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool selectClipPresent;
|
||||
SupportsSelectionClipboard(&selectClipPresent);
|
||||
bool findClipPresent;
|
||||
SupportsFindClipboard(&findClipPresent);
|
||||
if (!selectClipPresent && !findClipPresent && aWhichClipboard != kGlobalClipboard) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mIgnoreEmptyNotification) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mClipboardOwner) {
|
||||
mClipboardOwner->LosingOwnership(mTransferable);
|
||||
mClipboardOwner = nullptr;
|
||||
}
|
||||
|
||||
mTransferable = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::SupportsSelectionClipboard(bool* _retval)
|
||||
{
|
||||
*_retval = false; // we don't support the selection clipboard by default.
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsCocoaDebugUtils_h_
|
||||
#define nsCocoaDebugUtils_h_
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
// Definitions and declarations of stuff used by us from the CoreSymbolication
|
||||
// framework. This is an undocumented, private framework available on OS X
|
||||
// 10.6 and up. It's used by Apple utilities like dtrace, atos, ReportCrash
|
||||
// and crashreporterd.
|
||||
|
||||
typedef struct _CSTypeRef {
|
||||
unsigned long type;
|
||||
void* contents;
|
||||
} CSTypeRef;
|
||||
|
||||
typedef CSTypeRef CSSymbolicatorRef;
|
||||
typedef CSTypeRef CSSymbolOwnerRef;
|
||||
typedef CSTypeRef CSSymbolRef;
|
||||
typedef CSTypeRef CSSourceInfoRef;
|
||||
|
||||
typedef struct _CSRange {
|
||||
unsigned long long location;
|
||||
unsigned long long length;
|
||||
} CSRange;
|
||||
|
||||
typedef unsigned long long CSArchitecture;
|
||||
|
||||
#define kCSNow LONG_MAX
|
||||
|
||||
extern "C" {
|
||||
|
||||
CSSymbolicatorRef
|
||||
CSSymbolicatorCreateWithPid(pid_t pid);
|
||||
|
||||
CSSymbolicatorRef
|
||||
CSSymbolicatorCreateWithPidFlagsAndNotification(pid_t pid,
|
||||
uint32_t flags,
|
||||
uint32_t notification);
|
||||
|
||||
CSArchitecture
|
||||
CSSymbolicatorGetArchitecture(CSSymbolicatorRef symbolicator);
|
||||
|
||||
CSSymbolOwnerRef
|
||||
CSSymbolicatorGetSymbolOwnerWithAddressAtTime(CSSymbolicatorRef symbolicator,
|
||||
unsigned long long address,
|
||||
long time);
|
||||
|
||||
const char*
|
||||
CSSymbolOwnerGetName(CSSymbolOwnerRef owner);
|
||||
|
||||
unsigned long long
|
||||
CSSymbolOwnerGetBaseAddress(CSSymbolOwnerRef owner);
|
||||
|
||||
CSSymbolRef
|
||||
CSSymbolOwnerGetSymbolWithAddress(CSSymbolOwnerRef owner,
|
||||
unsigned long long address);
|
||||
|
||||
CSSourceInfoRef
|
||||
CSSymbolOwnerGetSourceInfoWithAddress(CSSymbolOwnerRef owner,
|
||||
unsigned long long address);
|
||||
|
||||
const char*
|
||||
CSSymbolGetName(CSSymbolRef symbol);
|
||||
|
||||
CSRange
|
||||
CSSymbolGetRange(CSSymbolRef symbol);
|
||||
|
||||
const char*
|
||||
CSSourceInfoGetFilename(CSSourceInfoRef info);
|
||||
|
||||
uint32_t
|
||||
CSSourceInfoGetLineNumber(CSSourceInfoRef info);
|
||||
|
||||
CSTypeRef
|
||||
CSRetain(CSTypeRef);
|
||||
|
||||
void
|
||||
CSRelease(CSTypeRef);
|
||||
|
||||
bool
|
||||
CSIsNull(CSTypeRef);
|
||||
|
||||
void
|
||||
CSShow(CSTypeRef);
|
||||
|
||||
const char*
|
||||
CSArchitectureGetFamilyName(CSArchitecture);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
class nsCocoaDebugUtils
|
||||
{
|
||||
public:
|
||||
// Like NSLog() but records more information (for example the full path to
|
||||
// the executable and the "thread name"). Like NSLog(), writes to both
|
||||
// stdout and the system log.
|
||||
static void DebugLog(const char* aFormat, ...);
|
||||
|
||||
// Logs a stack trace of the current point of execution, to both stdout and
|
||||
// the system log.
|
||||
static void PrintStackTrace();
|
||||
|
||||
// Returns the name of the module that "owns" aAddress. This must be
|
||||
// free()ed by the caller.
|
||||
static char* GetOwnerName(void* aAddress);
|
||||
|
||||
// Returns a symbolicated representation of aAddress. This must be
|
||||
// free()ed by the caller.
|
||||
static char* GetAddressString(void* aAddress);
|
||||
|
||||
private:
|
||||
static void DebugLogInt(bool aDecorate, const char* aFormat, ...);
|
||||
static void DebugLogV(bool aDecorate, CFStringRef aFormat, va_list aArgs);
|
||||
|
||||
static void PrintAddress(void* aAddress);
|
||||
|
||||
// The values returned by GetOwnerNameInt() and GetAddressStringInt() must
|
||||
// be free()ed by the caller.
|
||||
static char* GetOwnerNameInt(void* aAddress,
|
||||
CSTypeRef aOwner = sInitializer);
|
||||
static char* GetAddressStringInt(void* aAddress,
|
||||
CSTypeRef aOwner = sInitializer);
|
||||
|
||||
static CSSymbolicatorRef GetSymbolicatorRef();
|
||||
static void ReleaseSymbolicator();
|
||||
|
||||
static CSTypeRef sInitializer;
|
||||
static CSSymbolicatorRef sSymbolicator;
|
||||
};
|
||||
|
||||
#endif // nsCocoaDebugUtils_h_
|
||||
@@ -1,284 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsCocoaDebugUtils.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <libproc.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <execinfo.h>
|
||||
#include <asl.h>
|
||||
|
||||
static char gProcPath[PROC_PIDPATHINFO_MAXSIZE] = {0};
|
||||
static char gBundleID[MAXPATHLEN] = {0};
|
||||
|
||||
static void MaybeGetPathAndID()
|
||||
{
|
||||
if (!gProcPath[0]) {
|
||||
proc_pidpath(getpid(), gProcPath, sizeof(gProcPath));
|
||||
}
|
||||
if (!gBundleID[0]) {
|
||||
// Apple's CFLog() uses "com.apple.console" (in its call to asl_open()) if
|
||||
// it can't find the bundle id.
|
||||
CFStringRef bundleID = NULL;
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
if (mainBundle) {
|
||||
bundleID = CFBundleGetIdentifier(mainBundle);
|
||||
}
|
||||
if (!bundleID) {
|
||||
strcpy(gBundleID, "com.apple.console");
|
||||
} else {
|
||||
CFStringGetCString(bundleID, gBundleID, sizeof(gBundleID),
|
||||
kCFStringEncodingUTF8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GetThreadName(char* aName, size_t aSize)
|
||||
{
|
||||
pthread_getname_np(pthread_self(), aName, aSize);
|
||||
}
|
||||
|
||||
void
|
||||
nsCocoaDebugUtils::DebugLog(const char* aFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, aFormat);
|
||||
CFStringRef formatCFSTR =
|
||||
CFStringCreateWithCString(kCFAllocatorDefault, aFormat,
|
||||
kCFStringEncodingUTF8);
|
||||
DebugLogV(true, formatCFSTR, args);
|
||||
CFRelease(formatCFSTR);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
nsCocoaDebugUtils::DebugLogInt(bool aDecorate, const char* aFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, aFormat);
|
||||
CFStringRef formatCFSTR =
|
||||
CFStringCreateWithCString(kCFAllocatorDefault, aFormat,
|
||||
kCFStringEncodingUTF8);
|
||||
DebugLogV(aDecorate, formatCFSTR, args);
|
||||
CFRelease(formatCFSTR);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
nsCocoaDebugUtils::DebugLogV(bool aDecorate, CFStringRef aFormat,
|
||||
va_list aArgs)
|
||||
{
|
||||
MaybeGetPathAndID();
|
||||
|
||||
CFStringRef message =
|
||||
CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL,
|
||||
aFormat, aArgs);
|
||||
|
||||
int msgLength =
|
||||
CFStringGetMaximumSizeForEncoding(CFStringGetLength(message),
|
||||
kCFStringEncodingUTF8);
|
||||
char* msgUTF8 = (char*) calloc(msgLength, 1);
|
||||
CFStringGetCString(message, msgUTF8, msgLength, kCFStringEncodingUTF8);
|
||||
CFRelease(message);
|
||||
|
||||
int finishedLength = msgLength + PROC_PIDPATHINFO_MAXSIZE;
|
||||
char* finished = (char*) calloc(finishedLength, 1);
|
||||
const time_t currentTime = time(NULL);
|
||||
char timestamp[30] = {0};
|
||||
ctime_r(¤tTime, timestamp);
|
||||
if (aDecorate) {
|
||||
char threadName[MAXPATHLEN] = {0};
|
||||
GetThreadName(threadName, sizeof(threadName));
|
||||
snprintf(finished, finishedLength, "(%s) %s[%u] %s[%p] %s\n",
|
||||
timestamp, gProcPath, getpid(), threadName, pthread_self(), msgUTF8);
|
||||
} else {
|
||||
snprintf(finished, finishedLength, "%s\n", msgUTF8);
|
||||
}
|
||||
free(msgUTF8);
|
||||
|
||||
fputs(finished, stdout);
|
||||
|
||||
// Use the Apple System Log facility, as NSLog and CFLog do.
|
||||
aslclient asl = asl_open(NULL, gBundleID, ASL_OPT_NO_DELAY);
|
||||
aslmsg msg = asl_new(ASL_TYPE_MSG);
|
||||
asl_set(msg, ASL_KEY_LEVEL, "4"); // kCFLogLevelWarning, used by NSLog()
|
||||
asl_set(msg, ASL_KEY_MSG, finished);
|
||||
asl_send(asl, msg);
|
||||
asl_free(msg);
|
||||
asl_close(asl);
|
||||
|
||||
free(finished);
|
||||
}
|
||||
|
||||
CSTypeRef
|
||||
nsCocoaDebugUtils::sInitializer = {0};
|
||||
|
||||
CSSymbolicatorRef
|
||||
nsCocoaDebugUtils::sSymbolicator = {0};
|
||||
|
||||
#define STACK_MAX 256
|
||||
|
||||
void
|
||||
nsCocoaDebugUtils::PrintStackTrace()
|
||||
{
|
||||
void** addresses = (void**) calloc(STACK_MAX, sizeof(void*));
|
||||
if (!addresses) {
|
||||
return;
|
||||
}
|
||||
|
||||
CSSymbolicatorRef symbolicator = GetSymbolicatorRef();
|
||||
if (CSIsNull(symbolicator)) {
|
||||
free(addresses);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t count = backtrace(addresses, STACK_MAX);
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
PrintAddress(addresses[i]);
|
||||
}
|
||||
|
||||
ReleaseSymbolicator();
|
||||
free(addresses);
|
||||
}
|
||||
|
||||
void
|
||||
nsCocoaDebugUtils::PrintAddress(void* aAddress)
|
||||
{
|
||||
const char* ownerName = "unknown";
|
||||
const char* addressString = "unknown + 0";
|
||||
|
||||
char* allocatedOwnerName = nullptr;
|
||||
char* allocatedAddressString = nullptr;
|
||||
|
||||
CSSymbolOwnerRef owner = {0};
|
||||
CSSymbolicatorRef symbolicator = GetSymbolicatorRef();
|
||||
|
||||
if (!CSIsNull(symbolicator)) {
|
||||
owner =
|
||||
CSSymbolicatorGetSymbolOwnerWithAddressAtTime(symbolicator,
|
||||
(unsigned long long) aAddress,
|
||||
kCSNow);
|
||||
}
|
||||
if (!CSIsNull(owner)) {
|
||||
ownerName = allocatedOwnerName = GetOwnerNameInt(aAddress, owner);
|
||||
addressString = allocatedAddressString = GetAddressStringInt(aAddress, owner);
|
||||
}
|
||||
DebugLogInt(false, " (%s) %s", ownerName, addressString);
|
||||
|
||||
free(allocatedOwnerName);
|
||||
free(allocatedAddressString);
|
||||
|
||||
ReleaseSymbolicator();
|
||||
}
|
||||
|
||||
char*
|
||||
nsCocoaDebugUtils::GetOwnerName(void* aAddress)
|
||||
{
|
||||
return GetOwnerNameInt(aAddress);
|
||||
}
|
||||
|
||||
char*
|
||||
nsCocoaDebugUtils::GetOwnerNameInt(void* aAddress, CSTypeRef aOwner)
|
||||
{
|
||||
char* retval = (char*) calloc(MAXPATHLEN, 1);
|
||||
|
||||
const char* ownerName = "unknown";
|
||||
|
||||
CSSymbolicatorRef symbolicator = GetSymbolicatorRef();
|
||||
CSTypeRef owner = aOwner;
|
||||
|
||||
if (CSIsNull(owner) && !CSIsNull(symbolicator)) {
|
||||
owner =
|
||||
CSSymbolicatorGetSymbolOwnerWithAddressAtTime(symbolicator,
|
||||
(unsigned long long) aAddress,
|
||||
kCSNow);
|
||||
}
|
||||
|
||||
if (!CSIsNull(owner)) {
|
||||
ownerName = CSSymbolOwnerGetName(owner);
|
||||
}
|
||||
|
||||
snprintf(retval, MAXPATHLEN, "%s", ownerName);
|
||||
ReleaseSymbolicator();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
char*
|
||||
nsCocoaDebugUtils::GetAddressString(void* aAddress)
|
||||
{
|
||||
return GetAddressStringInt(aAddress);
|
||||
}
|
||||
|
||||
char*
|
||||
nsCocoaDebugUtils::GetAddressStringInt(void* aAddress, CSTypeRef aOwner)
|
||||
{
|
||||
char* retval = (char*) calloc(MAXPATHLEN, 1);
|
||||
|
||||
const char* addressName = "unknown";
|
||||
unsigned long long addressOffset = 0;
|
||||
|
||||
CSSymbolicatorRef symbolicator = GetSymbolicatorRef();
|
||||
CSTypeRef owner = aOwner;
|
||||
|
||||
if (CSIsNull(owner) && !CSIsNull(symbolicator)) {
|
||||
owner =
|
||||
CSSymbolicatorGetSymbolOwnerWithAddressAtTime(symbolicator,
|
||||
(unsigned long long) aAddress,
|
||||
kCSNow);
|
||||
}
|
||||
|
||||
if (!CSIsNull(owner)) {
|
||||
CSSymbolRef symbol =
|
||||
CSSymbolOwnerGetSymbolWithAddress(owner,
|
||||
(unsigned long long) aAddress);
|
||||
if (!CSIsNull(symbol)) {
|
||||
addressName = CSSymbolGetName(symbol);
|
||||
CSRange range = CSSymbolGetRange(symbol);
|
||||
addressOffset = (unsigned long long) aAddress - range.location;
|
||||
} else {
|
||||
addressOffset = (unsigned long long)
|
||||
aAddress - CSSymbolOwnerGetBaseAddress(owner);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(retval, MAXPATHLEN, "%s + 0x%llx",
|
||||
addressName, addressOffset);
|
||||
ReleaseSymbolicator();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
CSSymbolicatorRef
|
||||
nsCocoaDebugUtils::GetSymbolicatorRef()
|
||||
{
|
||||
if (CSIsNull(sSymbolicator)) {
|
||||
// 0x40e0000 is the value returned by
|
||||
// uint32_t CSSymbolicatorGetFlagsForNListOnlyData(void). We don't use
|
||||
// this method directly because it doesn't exist on OS X 10.6. Unless
|
||||
// we limit ourselves to NList data, it will take too long to get a
|
||||
// stack trace where Dwarf debugging info is available (about 15 seconds
|
||||
// with Firefox). This means we won't be able to get a CSSourceInfoRef,
|
||||
// or line number information. Oh well.
|
||||
sSymbolicator =
|
||||
CSSymbolicatorCreateWithPidFlagsAndNotification(getpid(),
|
||||
0x40e0000, 0);
|
||||
}
|
||||
// Retaining just after creation prevents crashes when calling symbolicator
|
||||
// code (for example from PrintStackTrace()) as Firefox is quitting. Not
|
||||
// sure why. Doing this may mean that we leak sSymbolicator on quitting
|
||||
// (if we ever created it). No particular harm in that, though.
|
||||
return CSRetain(sSymbolicator);
|
||||
}
|
||||
|
||||
void
|
||||
nsCocoaDebugUtils::ReleaseSymbolicator()
|
||||
{
|
||||
if (!CSIsNull(sSymbolicator)) {
|
||||
CSRelease(sSymbolicator);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsCocoaFeatures_h_
|
||||
#define nsCocoaFeatures_h_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/// Note that this class assumes we support the platform we are running on.
|
||||
/// For better or worse, if the version is unknown or less than what we
|
||||
/// support, we set it to the minimum supported version. GetSystemVersion
|
||||
/// is the only call that returns the unadjusted values.
|
||||
class nsCocoaFeatures {
|
||||
public:
|
||||
static int32_t macOSVersion();
|
||||
static int32_t macOSVersionMajor();
|
||||
static int32_t macOSVersionMinor();
|
||||
static int32_t macOSVersionBugFix();
|
||||
static bool OnYosemiteOrLater();
|
||||
static bool OnElCapitanOrLater();
|
||||
static bool OnSierraOrLater();
|
||||
static bool OnHighSierraOrLater();
|
||||
static bool OnMojaveOrLater();
|
||||
static bool OnCatalinaOrLater();
|
||||
static bool OnBigSurOrLater();
|
||||
|
||||
static bool IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix=0);
|
||||
|
||||
// These are utilities that do not change or depend on the value of mOSXVersion
|
||||
// and instead just encapsulate the encoding algorithm. Note that GetVersion
|
||||
// actually adjusts to the lowest supported OS, so it will always return
|
||||
// a "supported" version. GetSystemVersion does not make any modifications.
|
||||
static void GetSystemVersion(int &aMajor, int &aMinor, int &aBugFix);
|
||||
static int32_t GetVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix);
|
||||
static int32_t ExtractMajorVersion(int32_t aVersion);
|
||||
static int32_t ExtractMinorVersion(int32_t aVersion);
|
||||
static int32_t ExtractBugFixVersion(int32_t aVersion);
|
||||
|
||||
private:
|
||||
static void InitializeVersionNumbers();
|
||||
|
||||
static int32_t mOSVersion;
|
||||
};
|
||||
#endif // nsCocoaFeatures_h_
|
||||
@@ -1,209 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This file makes some assumptions about the versions of macOS.
|
||||
// We are assuming that the major, minor and bugfix versions are each less than
|
||||
// 256.
|
||||
// There are MOZ_ASSERTs for that.
|
||||
|
||||
// The formula for the version integer is (major << 16) + (minor << 8) + bugfix.
|
||||
|
||||
#define MACOS_VERSION_MASK 0x00FFFFFF
|
||||
#define MACOS_MAJOR_VERSION_MASK 0x00FFFFFF
|
||||
#define MACOS_MINOR_VERSION_MASK 0x00FFFFFF
|
||||
#define MACOS_BUGFIX_VERSION_MASK 0x00FFFFFF
|
||||
#define MACOS_VERSION_10_0_HEX 0x000A0000
|
||||
#define MACOS_VERSION_10_7_HEX 0x000A0700
|
||||
#define MACOS_VERSION_10_8_HEX 0x000A0800
|
||||
#define MACOS_VERSION_10_9_HEX 0x000A0900
|
||||
#define MACOS_VERSION_10_10_HEX 0x000A0A00
|
||||
#define MACOS_VERSION_10_11_HEX 0x000A0B00
|
||||
#define MACOS_VERSION_10_12_HEX 0x000A0C00
|
||||
#define MACOS_VERSION_10_13_HEX 0x000A0D00
|
||||
#define MACOS_VERSION_10_14_HEX 0x000A0E00
|
||||
#define MACOS_VERSION_10_15_HEX 0x000A0F00
|
||||
#define MACOS_VERSION_10_16_HEX 0x000A1000
|
||||
#define MACOS_VERSION_11_0_HEX 0x000B0000
|
||||
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
int32_t nsCocoaFeatures::mOSVersion = 0;
|
||||
|
||||
// This should not be called with unchecked aMajor, which should be >= 10.
|
||||
inline int32_t AssembleVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
|
||||
{
|
||||
MOZ_ASSERT(aMajor >= 10);
|
||||
return (aMajor << 16) + (aMinor << 8) + aBugFix;
|
||||
}
|
||||
|
||||
int32_t nsCocoaFeatures::ExtractMajorVersion(int32_t aVersion)
|
||||
{
|
||||
MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
|
||||
return (aVersion & 0xFF0000) >> 16;
|
||||
}
|
||||
|
||||
int32_t nsCocoaFeatures::ExtractMinorVersion(int32_t aVersion)
|
||||
{
|
||||
MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
|
||||
return (aVersion & 0xFF00) >> 8;
|
||||
}
|
||||
|
||||
int32_t nsCocoaFeatures::ExtractBugFixVersion(int32_t aVersion)
|
||||
{
|
||||
MOZ_ASSERT((aVersion & MACOS_VERSION_MASK) == aVersion);
|
||||
return aVersion & 0xFF;
|
||||
}
|
||||
|
||||
static int intAtStringIndex(NSArray *array, int index)
|
||||
{
|
||||
return [(NSString*)[array objectAtIndex:index] integerValue];
|
||||
}
|
||||
|
||||
void nsCocoaFeatures::GetSystemVersion(int &major, int &minor, int &bugfix)
|
||||
{
|
||||
major = minor = bugfix = 0;
|
||||
|
||||
NSString* versionString = [[NSDictionary dictionaryWithContentsOfFile:
|
||||
@"/System/Library/CoreServices/SystemVersion.plist"] objectForKey:@"ProductVersion"];
|
||||
NSArray* versions = [versionString componentsSeparatedByString:@"."];
|
||||
NSUInteger count = [versions count];
|
||||
if (count > 0) {
|
||||
major = intAtStringIndex(versions, 0);
|
||||
if (count > 1) {
|
||||
minor = intAtStringIndex(versions, 1);
|
||||
if (count > 2) {
|
||||
bugfix = intAtStringIndex(versions, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t nsCocoaFeatures::GetVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
|
||||
{
|
||||
int32_t macOSVersion;
|
||||
if (aMajor < 10) {
|
||||
aMajor = 10;
|
||||
NS_ERROR("Couldn't determine macOS version, assuming 10.7");
|
||||
macOSVersion = MACOS_VERSION_10_7_HEX;
|
||||
} else if (aMajor == 10 && aMinor < 7) {
|
||||
aMinor = 7;
|
||||
NS_ERROR("macOS version too old, assuming 10.7");
|
||||
macOSVersion = MACOS_VERSION_10_7_HEX;
|
||||
} else {
|
||||
MOZ_ASSERT(aMajor >= 10);
|
||||
MOZ_ASSERT(aMajor < 256);
|
||||
MOZ_ASSERT(aMinor >= 0);
|
||||
MOZ_ASSERT(aMinor < 256);
|
||||
MOZ_ASSERT(aBugFix >= 0);
|
||||
MOZ_ASSERT(aBugFix < 256);
|
||||
macOSVersion = AssembleVersion(aMajor, aMinor, aBugFix);
|
||||
}
|
||||
MOZ_ASSERT(aMajor == ExtractMajorVersion(macOSVersion));
|
||||
MOZ_ASSERT(aMinor == ExtractMinorVersion(macOSVersion));
|
||||
MOZ_ASSERT(aBugFix == ExtractBugFixVersion(macOSVersion));
|
||||
return macOSVersion;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
nsCocoaFeatures::InitializeVersionNumbers()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
// Provide an autorelease pool to avoid leaking Cocoa objects,
|
||||
// as this gets called before the main autorelease pool is in place.
|
||||
nsAutoreleasePool localPool;
|
||||
|
||||
int major, minor, bugfix;
|
||||
GetSystemVersion(major, minor, bugfix);
|
||||
mOSVersion = GetVersion(major, minor, bugfix);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
nsCocoaFeatures::macOSVersion()
|
||||
{
|
||||
// Don't let this be called while we're first setting the value...
|
||||
MOZ_ASSERT((mOSVersion & MACOS_VERSION_MASK) >= 0);
|
||||
if (!mOSVersion) {
|
||||
mOSVersion = -1;
|
||||
InitializeVersionNumbers();
|
||||
}
|
||||
return mOSVersion;
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
nsCocoaFeatures::macOSVersionMajor()
|
||||
{
|
||||
return ExtractMajorVersion(macOSVersion());
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
nsCocoaFeatures::macOSVersionMinor()
|
||||
{
|
||||
return ExtractMinorVersion(macOSVersion());
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
nsCocoaFeatures::macOSVersionBugFix()
|
||||
{
|
||||
return ExtractBugFixVersion(macOSVersion());
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnYosemiteOrLater()
|
||||
{
|
||||
return (macOSVersion() >= MACOS_VERSION_10_10_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnElCapitanOrLater()
|
||||
{
|
||||
return (macOSVersion() >= MACOS_VERSION_10_11_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnSierraOrLater()
|
||||
{
|
||||
return (macOSVersion() >= MACOS_VERSION_10_12_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnHighSierraOrLater()
|
||||
{
|
||||
return (macOSVersion() >= MACOS_VERSION_10_13_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnMojaveOrLater()
|
||||
{
|
||||
return (macOSVersion() >= MACOS_VERSION_10_14_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnCatalinaOrLater()
|
||||
{
|
||||
return (macOSVersion() >= MACOS_VERSION_10_15_HEX);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnBigSurOrLater()
|
||||
{
|
||||
// Account for the version being 10.16 (which occurs when the
|
||||
// application is linked with an older SDK) or 11.0 on Big Sur.
|
||||
return ((macOSVersion() >= MACOS_VERSION_10_16_HEX) ||
|
||||
(macOSVersion() >= MACOS_VERSION_11_0_HEX));
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix)
|
||||
{
|
||||
return macOSVersion() >= GetVersion(aMajor, aMinor, aBugFix);
|
||||
}
|
||||
@@ -1,389 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsCocoaUtils_h_
|
||||
#define nsCocoaUtils_h_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "nsRect.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "npapi.h"
|
||||
#include "nsTArray.h"
|
||||
#include "Units.h"
|
||||
|
||||
// This must be the last include:
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
|
||||
// Declare the backingScaleFactor method that we want to call
|
||||
// on NSView/Window/Screen objects, if they recognize it.
|
||||
@interface NSObject (BackingScaleFactorCategory)
|
||||
- (CGFloat)backingScaleFactor;
|
||||
@end
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
|
||||
enum {
|
||||
NSEventPhaseMayBegin = 0x1 << 5
|
||||
};
|
||||
#endif
|
||||
|
||||
class nsIWidget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class SourceSurface;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
// Used to retain a Cocoa object for the remainder of a method's execution.
|
||||
class nsAutoRetainCocoaObject {
|
||||
public:
|
||||
explicit nsAutoRetainCocoaObject(id anObject)
|
||||
{
|
||||
mObject = NS_OBJC_TRY_EXPR_ABORT([anObject retain]);
|
||||
}
|
||||
~nsAutoRetainCocoaObject()
|
||||
{
|
||||
NS_OBJC_TRY_ABORT([mObject release]);
|
||||
}
|
||||
private:
|
||||
id mObject; // [STRONG]
|
||||
};
|
||||
|
||||
// Provide a local autorelease pool for the remainder of a method's execution.
|
||||
class nsAutoreleasePool {
|
||||
public:
|
||||
nsAutoreleasePool()
|
||||
{
|
||||
mLocalPool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
~nsAutoreleasePool()
|
||||
{
|
||||
[mLocalPool release];
|
||||
}
|
||||
private:
|
||||
NSAutoreleasePool *mLocalPool;
|
||||
};
|
||||
|
||||
@interface NSApplication (Undocumented)
|
||||
|
||||
// Present in all versions of OS X from (at least) 10.2.8 through 10.5.
|
||||
- (BOOL)_isRunningModal;
|
||||
- (BOOL)_isRunningAppModal;
|
||||
|
||||
// It's sometimes necessary to explicitly remove a window from the "window
|
||||
// cache" in order to deactivate it. The "window cache" is an undocumented
|
||||
// subsystem, all of whose methods are included in the NSWindowCache category
|
||||
// of the NSApplication class (in header files generated using class-dump).
|
||||
// Present in all versions of OS X from (at least) 10.2.8 through 10.5.
|
||||
- (void)_removeWindowFromCache:(NSWindow *)aWindow;
|
||||
|
||||
// Send an event to the current Cocoa app-modal session. Present in all
|
||||
// versions of OS X from (at least) 10.2.8 through 10.5.
|
||||
- (void)_modalSession:(NSModalSession)aSession sendEvent:(NSEvent *)theEvent;
|
||||
|
||||
@end
|
||||
|
||||
struct KeyBindingsCommand
|
||||
{
|
||||
SEL selector;
|
||||
id data;
|
||||
};
|
||||
|
||||
@interface NativeKeyBindingsRecorder : NSResponder
|
||||
{
|
||||
@private
|
||||
nsTArray<KeyBindingsCommand>* mCommands;
|
||||
}
|
||||
|
||||
- (void)startRecording:(nsTArray<KeyBindingsCommand>&)aCommands;
|
||||
|
||||
- (void)doCommandBySelector:(SEL)aSelector;
|
||||
|
||||
- (void)insertText:(id)aString;
|
||||
|
||||
@end // NativeKeyBindingsRecorder
|
||||
|
||||
class nsCocoaUtils
|
||||
{
|
||||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
|
||||
typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
|
||||
|
||||
public:
|
||||
|
||||
// Get the backing scale factor from an object that supports this selector
|
||||
// (NSView/Window/Screen, on 10.7 or later), returning 1.0 if not supported
|
||||
static CGFloat
|
||||
GetBackingScaleFactor(id aObject)
|
||||
{
|
||||
if (HiDPIEnabled() &&
|
||||
[aObject respondsToSelector:@selector(backingScaleFactor)]) {
|
||||
return [aObject backingScaleFactor];
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// Conversions between Cocoa points and device pixels, given the backing
|
||||
// scale factor from a view/window/screen.
|
||||
static int32_t
|
||||
CocoaPointsToDevPixels(CGFloat aPts, CGFloat aBackingScale)
|
||||
{
|
||||
return NSToIntRound(aPts * aBackingScale);
|
||||
}
|
||||
|
||||
static LayoutDeviceIntPoint
|
||||
CocoaPointsToDevPixels(const NSPoint& aPt, CGFloat aBackingScale)
|
||||
{
|
||||
return LayoutDeviceIntPoint(NSToIntRound(aPt.x * aBackingScale),
|
||||
NSToIntRound(aPt.y * aBackingScale));
|
||||
}
|
||||
|
||||
static LayoutDeviceIntPoint
|
||||
CocoaPointsToDevPixelsRoundDown(const NSPoint& aPt, CGFloat aBackingScale)
|
||||
{
|
||||
return LayoutDeviceIntPoint(NSToIntFloor(aPt.x * aBackingScale),
|
||||
NSToIntFloor(aPt.y * aBackingScale));
|
||||
}
|
||||
|
||||
static LayoutDeviceIntRect
|
||||
CocoaPointsToDevPixels(const NSRect& aRect, CGFloat aBackingScale)
|
||||
{
|
||||
return LayoutDeviceIntRect(NSToIntRound(aRect.origin.x * aBackingScale),
|
||||
NSToIntRound(aRect.origin.y * aBackingScale),
|
||||
NSToIntRound(aRect.size.width * aBackingScale),
|
||||
NSToIntRound(aRect.size.height * aBackingScale));
|
||||
}
|
||||
|
||||
static CGFloat
|
||||
DevPixelsToCocoaPoints(int32_t aPixels, CGFloat aBackingScale)
|
||||
{
|
||||
return (CGFloat)aPixels / aBackingScale;
|
||||
}
|
||||
|
||||
static NSPoint
|
||||
DevPixelsToCocoaPoints(const mozilla::LayoutDeviceIntPoint& aPt,
|
||||
CGFloat aBackingScale)
|
||||
{
|
||||
return NSMakePoint((CGFloat)aPt.x / aBackingScale,
|
||||
(CGFloat)aPt.y / aBackingScale);
|
||||
}
|
||||
|
||||
// Implements an NSPoint equivalent of -[NSWindow convertRectFromScreen:].
|
||||
static NSPoint
|
||||
ConvertPointFromScreen(NSWindow* aWindow, const NSPoint& aPt)
|
||||
{
|
||||
return [aWindow convertRectFromScreen:NSMakeRect(aPt.x, aPt.y, 0, 0)].origin;
|
||||
}
|
||||
|
||||
// Implements an NSPoint equivalent of -[NSWindow convertRectToScreen:].
|
||||
static NSPoint
|
||||
ConvertPointToScreen(NSWindow* aWindow, const NSPoint& aPt)
|
||||
{
|
||||
return [aWindow convertRectToScreen:NSMakeRect(aPt.x, aPt.y, 0, 0)].origin;
|
||||
}
|
||||
|
||||
static NSRect
|
||||
DevPixelsToCocoaPoints(const LayoutDeviceIntRect& aRect,
|
||||
CGFloat aBackingScale)
|
||||
{
|
||||
return NSMakeRect((CGFloat)aRect.x / aBackingScale,
|
||||
(CGFloat)aRect.y / aBackingScale,
|
||||
(CGFloat)aRect.width / aBackingScale,
|
||||
(CGFloat)aRect.height / aBackingScale);
|
||||
}
|
||||
|
||||
// Returns the given y coordinate, which must be in screen coordinates,
|
||||
// flipped from Gecko to Cocoa or Cocoa to Gecko.
|
||||
static float FlippedScreenY(float y);
|
||||
|
||||
// The following functions come in "DevPix" variants that work with
|
||||
// backing-store (device pixel) coordinates, as well as the original
|
||||
// versions that expect coordinates in Cocoa points/CSS pixels.
|
||||
// The difference becomes important in HiDPI display modes, where Cocoa
|
||||
// points and backing-store pixels are no longer 1:1.
|
||||
|
||||
// Gecko rects (nsRect) contain an origin (x,y) in a coordinate
|
||||
// system with (0,0) in the top-left of the primary screen. Cocoa rects
|
||||
// (NSRect) contain an origin (x,y) in a coordinate system with (0,0)
|
||||
// in the bottom-left of the primary screen. Both nsRect and NSRect
|
||||
// contain width/height info, with no difference in their use.
|
||||
// This function does no scaling, so the Gecko coordinates are
|
||||
// expected to be desktop pixels, which are equal to Cocoa points
|
||||
// (by definition).
|
||||
static NSRect GeckoRectToCocoaRect(const mozilla::DesktopIntRect &geckoRect);
|
||||
|
||||
// Converts aGeckoRect in dev pixels to points in Cocoa coordinates
|
||||
static NSRect
|
||||
GeckoRectToCocoaRectDevPix(const mozilla::LayoutDeviceIntRect &aGeckoRect,
|
||||
CGFloat aBackingScale);
|
||||
|
||||
// See explanation for geckoRectToCocoaRect, guess what this does...
|
||||
static mozilla::DesktopIntRect CocoaRectToGeckoRect(const NSRect &cocoaRect);
|
||||
|
||||
static mozilla::LayoutDeviceIntRect CocoaRectToGeckoRectDevPix(
|
||||
const NSRect& aCocoaRect, CGFloat aBackingScale);
|
||||
|
||||
// Gives the location for the event in screen coordinates. Do not call this
|
||||
// unless the window the event was originally targeted at is still alive!
|
||||
// anEvent may be nil -- in that case the current mouse location is returned.
|
||||
static NSPoint ScreenLocationForEvent(NSEvent* anEvent);
|
||||
|
||||
// Determines if an event happened over a window, whether or not the event
|
||||
// is for the window. Does not take window z-order into account.
|
||||
static BOOL IsEventOverWindow(NSEvent* anEvent, NSWindow* aWindow);
|
||||
|
||||
// Events are set up so that their coordinates refer to the window to which they
|
||||
// were originally sent. If we reroute the event somewhere else, we'll have
|
||||
// to get the window coordinates this way. Do not call this unless the window
|
||||
// the event was originally targeted at is still alive!
|
||||
static NSPoint EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow);
|
||||
|
||||
// Compatibility wrappers for the -[NSEvent phase], -[NSEvent momentumPhase],
|
||||
// -[NSEvent hasPreciseScrollingDeltas] and -[NSEvent scrollingDeltaX/Y] APIs
|
||||
// that became availaible starting with the 10.7 SDK.
|
||||
// All of these can be removed once we drop support for 10.6.
|
||||
static NSEventPhase EventPhase(NSEvent* aEvent);
|
||||
static NSEventPhase EventMomentumPhase(NSEvent* aEvent);
|
||||
static BOOL IsMomentumScrollEvent(NSEvent* aEvent);
|
||||
static BOOL HasPreciseScrollingDeltas(NSEvent* aEvent);
|
||||
static void GetScrollingDeltas(NSEvent* aEvent, CGFloat* aOutDeltaX, CGFloat* aOutDeltaY);
|
||||
static BOOL EventHasPhaseInformation(NSEvent* aEvent);
|
||||
|
||||
// Hides the Menu bar and the Dock. Multiple hide/show requests can be nested.
|
||||
static void HideOSChromeOnScreen(bool aShouldHide);
|
||||
|
||||
static nsIWidget* GetHiddenWindowWidget();
|
||||
|
||||
static void PrepareForNativeAppModalDialog();
|
||||
static void CleanUpAfterNativeAppModalDialog();
|
||||
|
||||
// 3 utility functions to go from a frame of imgIContainer to CGImage and then to NSImage
|
||||
// Convert imgIContainer -> CGImageRef, caller owns result
|
||||
|
||||
/** Creates a <code>CGImageRef</code> from a frame contained in an <code>imgIContainer</code>.
|
||||
Copies the pixel data from the indicated frame of the <code>imgIContainer</code> into a new <code>CGImageRef</code>.
|
||||
The caller owns the <code>CGImageRef</code>.
|
||||
@param aFrame the frame to convert
|
||||
@param aResult the resulting CGImageRef
|
||||
@return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise
|
||||
*/
|
||||
static nsresult CreateCGImageFromSurface(SourceSurface* aSurface,
|
||||
CGImageRef* aResult);
|
||||
|
||||
/** Creates a Cocoa <code>NSImage</code> from a <code>CGImageRef</code>.
|
||||
Copies the pixel data from the <code>CGImageRef</code> into a new <code>NSImage</code>.
|
||||
The caller owns the <code>NSImage</code>.
|
||||
@param aInputImage the image to convert
|
||||
@param aResult the resulting NSImage
|
||||
@return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise
|
||||
*/
|
||||
static nsresult CreateNSImageFromCGImage(CGImageRef aInputImage, NSImage **aResult);
|
||||
|
||||
/** Creates a Cocoa <code>NSImage</code> from a frame of an <code>imgIContainer</code>.
|
||||
Combines the two methods above. The caller owns the <code>NSImage</code>.
|
||||
@param aImage the image to extract a frame from
|
||||
@param aWhichFrame the frame to extract (see imgIContainer FRAME_*)
|
||||
@param aResult the resulting NSImage
|
||||
@param scaleFactor the desired scale factor of the NSImage (2 for a retina display)
|
||||
@return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise
|
||||
*/
|
||||
static nsresult CreateNSImageFromImageContainer(imgIContainer *aImage, uint32_t aWhichFrame, NSImage **aResult, CGFloat scaleFactor);
|
||||
|
||||
/**
|
||||
* Returns nsAString for aSrc.
|
||||
*/
|
||||
static void GetStringForNSString(const NSString *aSrc, nsAString& aDist);
|
||||
|
||||
/**
|
||||
* Makes NSString instance for aString.
|
||||
*/
|
||||
static NSString* ToNSString(const nsAString& aString);
|
||||
|
||||
/**
|
||||
* Returns NSRect for aGeckoRect.
|
||||
* Just copies values between the two types; it does no coordinate-system
|
||||
* conversion, so both rects must have the same coordinate origin/direction.
|
||||
*/
|
||||
static void GeckoRectToNSRect(const nsIntRect& aGeckoRect,
|
||||
NSRect& aOutCocoaRect);
|
||||
|
||||
/**
|
||||
* Returns Gecko rect for aCocoaRect.
|
||||
* Just copies values between the two types; it does no coordinate-system
|
||||
* conversion, so both rects must have the same coordinate origin/direction.
|
||||
*/
|
||||
static void NSRectToGeckoRect(const NSRect& aCocoaRect,
|
||||
nsIntRect& aOutGeckoRect);
|
||||
|
||||
/**
|
||||
* Makes NSEvent instance for aEventTytpe and aEvent.
|
||||
*/
|
||||
static NSEvent* MakeNewCocoaEventWithType(NSEventType aEventType,
|
||||
NSEvent *aEvent);
|
||||
|
||||
/**
|
||||
* Initializes aNPCocoaEvent.
|
||||
*/
|
||||
static void InitNPCocoaEvent(NPCocoaEvent* aNPCocoaEvent);
|
||||
|
||||
/**
|
||||
* Initializes WidgetInputEvent for aNativeEvent or aModifiers.
|
||||
*/
|
||||
static void InitInputEvent(mozilla::WidgetInputEvent &aInputEvent,
|
||||
NSEvent* aNativeEvent);
|
||||
|
||||
/**
|
||||
* Converts the native modifiers from aNativeEvent into WidgetMouseEvent
|
||||
* Modifiers. aNativeEvent can be null.
|
||||
*/
|
||||
static mozilla::Modifiers ModifiersForEvent(NSEvent* aNativeEvent);
|
||||
|
||||
/**
|
||||
* ConvertToCarbonModifier() returns carbon modifier flags for the cocoa
|
||||
* modifier flags.
|
||||
* NOTE: The result never includes right*Key.
|
||||
*/
|
||||
static UInt32 ConvertToCarbonModifier(NSUInteger aCocoaModifier);
|
||||
|
||||
/**
|
||||
* Whether to support HiDPI rendering. For testing purposes, to be removed
|
||||
* once we're comfortable with the HiDPI behavior.
|
||||
*/
|
||||
static bool HiDPIEnabled();
|
||||
|
||||
/**
|
||||
* Keys can optionally be bound by system or user key bindings to one or more
|
||||
* commands based on selectors. This collects any such commands in the
|
||||
* provided array.
|
||||
*/
|
||||
static void GetCommandsFromKeyEvent(NSEvent* aEvent,
|
||||
nsTArray<KeyBindingsCommand>& aCommands);
|
||||
|
||||
/**
|
||||
* Converts the string name of a Gecko key (like "VK_HOME") to the
|
||||
* corresponding Cocoa Unicode character.
|
||||
*/
|
||||
static uint32_t ConvertGeckoNameToMacCharCode(const nsAString& aKeyCodeName);
|
||||
|
||||
/**
|
||||
* Converts a Gecko key code (like NS_VK_HOME) to the corresponding Cocoa
|
||||
* Unicode character.
|
||||
*/
|
||||
static uint32_t ConvertGeckoKeyCodeToMacCharCode(uint32_t aKeyCode);
|
||||
|
||||
/**
|
||||
* Convert string with font attribute to NSMutableAttributedString
|
||||
*/
|
||||
static NSMutableAttributedString* GetNSMutableAttributedString(
|
||||
const nsAString& aText,
|
||||
const nsTArray<mozilla::FontRange>& aFontRanges,
|
||||
const bool aIsVertical,
|
||||
const CGFloat aBackingScaleFactor);
|
||||
};
|
||||
|
||||
#endif // nsCocoaUtils_h_
|
||||
@@ -1,426 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsCocoaWindow_h_
|
||||
#define nsCocoaWindow_h_
|
||||
|
||||
#undef DARWIN
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsBaseWidget.h"
|
||||
#include "nsPIWidgetCocoa.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
|
||||
class nsCocoaWindow;
|
||||
class nsChildView;
|
||||
class nsMenuBarX;
|
||||
@class ChildView;
|
||||
|
||||
typedef struct _nsCocoaWindowList {
|
||||
_nsCocoaWindowList() : prev(nullptr), window(nullptr) {}
|
||||
struct _nsCocoaWindowList *prev;
|
||||
nsCocoaWindow *window; // Weak
|
||||
} nsCocoaWindowList;
|
||||
|
||||
// NSWindow subclass that is the base class for all of our own window classes.
|
||||
// Among other things, this class handles the storage of those settings that
|
||||
// need to be persisted across window destruction and reconstruction, i.e. when
|
||||
// switching to and from fullscreen mode.
|
||||
// We don't save shadow, transparency mode or background color because it's not
|
||||
// worth the hassle - Gecko will reset them anyway as soon as the window is
|
||||
// resized.
|
||||
@interface BaseWindow : NSWindow
|
||||
{
|
||||
// Data Storage
|
||||
NSMutableDictionary* mState;
|
||||
BOOL mDrawsIntoWindowFrame;
|
||||
NSColor* mActiveTitlebarColor;
|
||||
NSColor* mInactiveTitlebarColor;
|
||||
|
||||
// Shadow
|
||||
BOOL mScheduledShadowInvalidation;
|
||||
|
||||
// Invalidation disabling
|
||||
BOOL mDisabledNeedsDisplay;
|
||||
|
||||
// DPI cache. Getting the physical screen size (CGDisplayScreenSize)
|
||||
// is ridiculously slow, so we cache it in the toplevel window for all
|
||||
// descendants to use.
|
||||
float mDPI;
|
||||
|
||||
NSTrackingArea* mTrackingArea;
|
||||
|
||||
NSRect mDirtyRect;
|
||||
|
||||
BOOL mBeingShown;
|
||||
BOOL mDrawTitle;
|
||||
BOOL mBrightTitlebarForeground;
|
||||
BOOL mUseMenuStyle;
|
||||
}
|
||||
|
||||
- (void)importState:(NSDictionary*)aState;
|
||||
- (NSMutableDictionary*)exportState;
|
||||
- (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
|
||||
- (BOOL)drawsContentsIntoWindowFrame;
|
||||
- (void)setTitlebarColor:(NSColor*)aColor forActiveWindow:(BOOL)aActive;
|
||||
- (NSColor*)titlebarColorForActiveWindow:(BOOL)aActive;
|
||||
|
||||
- (void)deferredInvalidateShadow;
|
||||
- (void)invalidateShadow;
|
||||
- (float)getDPI;
|
||||
|
||||
- (void)mouseEntered:(NSEvent*)aEvent;
|
||||
- (void)mouseExited:(NSEvent*)aEvent;
|
||||
- (void)mouseMoved:(NSEvent*)aEvent;
|
||||
- (void)updateTrackingArea;
|
||||
- (NSView*)trackingAreaView;
|
||||
|
||||
- (void)setBeingShown:(BOOL)aValue;
|
||||
- (BOOL)isBeingShown;
|
||||
- (BOOL)isVisibleOrBeingShown;
|
||||
|
||||
- (ChildView*)mainChildView;
|
||||
|
||||
- (NSArray*)titlebarControls;
|
||||
|
||||
- (void)setWantsTitleDrawn:(BOOL)aDrawTitle;
|
||||
- (BOOL)wantsTitleDrawn;
|
||||
|
||||
- (void)setUseBrightTitlebarForeground:(BOOL)aBrightForeground;
|
||||
- (BOOL)useBrightTitlebarForeground;
|
||||
|
||||
- (void)disableSetNeedsDisplay;
|
||||
- (void)enableSetNeedsDisplay;
|
||||
|
||||
- (NSRect)getAndResetNativeDirtyRect;
|
||||
|
||||
- (void)setUseMenuStyle:(BOOL)aValue;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSWindow (Undocumented)
|
||||
|
||||
// If a window has been explicitly removed from the "window cache" (to
|
||||
// deactivate it), it's sometimes necessary to "reset" it to reactivate it
|
||||
// (and put it back in the "window cache"). One way to do this, which Apple
|
||||
// often uses, is to set the "window number" to '-1' and then back to its
|
||||
// original value.
|
||||
- (void)_setWindowNumber:(NSInteger)aNumber;
|
||||
|
||||
// If we set the window's stylemask to be textured, the corners on the bottom of
|
||||
// the window are rounded by default. We use this private method to make
|
||||
// the corners square again, a la Safari. Starting with 10.7, all windows have
|
||||
// rounded bottom corners, so this call doesn't have any effect there.
|
||||
- (void)setBottomCornerRounded:(BOOL)rounded;
|
||||
- (BOOL)bottomCornerRounded;
|
||||
|
||||
// Present in the same form on OS X since at least OS X 10.5.
|
||||
- (NSRect)contentRectForFrameRect:(NSRect)windowFrame styleMask:(NSUInteger)windowStyle;
|
||||
- (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSUInteger)windowStyle;
|
||||
|
||||
// Present since at least OS X 10.5. The OS calls this method on NSWindow
|
||||
// (and its subclasses) to find out which NSFrameView subclass to instantiate
|
||||
// to create its "frame view".
|
||||
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
|
||||
|
||||
@end
|
||||
|
||||
@interface PopupWindow : BaseWindow
|
||||
{
|
||||
@private
|
||||
BOOL mIsContextMenu;
|
||||
}
|
||||
|
||||
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
|
||||
backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation;
|
||||
- (BOOL)isContextMenu;
|
||||
- (void)setIsContextMenu:(BOOL)flag;
|
||||
- (BOOL)canBecomeMainWindow;
|
||||
|
||||
@end
|
||||
|
||||
@interface BorderlessWindow : BaseWindow
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyWindow;
|
||||
- (BOOL)canBecomeMainWindow;
|
||||
|
||||
@end
|
||||
|
||||
@interface WindowDelegate : NSObject <NSWindowDelegate>
|
||||
{
|
||||
nsCocoaWindow* mGeckoWindow; // [WEAK] (we are owned by the window)
|
||||
// Used to avoid duplication when we send NS_ACTIVATE and
|
||||
// NS_DEACTIVATE to Gecko for toplevel widgets. Starts out
|
||||
// false.
|
||||
bool mToplevelActiveState;
|
||||
BOOL mHasEverBeenZoomed;
|
||||
}
|
||||
+ (void)paintMenubarForWindow:(NSWindow*)aWindow;
|
||||
- (id)initWithGeckoWindow:(nsCocoaWindow*)geckoWind;
|
||||
- (void)windowDidResize:(NSNotification*)aNotification;
|
||||
- (nsCocoaWindow*)geckoWidget;
|
||||
- (bool)toplevelActiveState;
|
||||
- (void)sendToplevelActivateEvents;
|
||||
- (void)sendToplevelDeactivateEvents;
|
||||
@end
|
||||
|
||||
@class ToolbarWindow;
|
||||
|
||||
// NSColor subclass that allows us to draw separate colors both in the titlebar
|
||||
// and for background of the window.
|
||||
@interface TitlebarAndBackgroundColor : NSColor
|
||||
{
|
||||
ToolbarWindow *mWindow; // [WEAK] (we are owned by the window)
|
||||
}
|
||||
|
||||
- (id)initWithWindow:(ToolbarWindow*)aWindow;
|
||||
|
||||
@end
|
||||
|
||||
// NSWindow subclass for handling windows with toolbars.
|
||||
@interface ToolbarWindow : BaseWindow
|
||||
{
|
||||
TitlebarAndBackgroundColor *mColor; // strong
|
||||
CGFloat mUnifiedToolbarHeight;
|
||||
NSColor *mBackgroundColor; // strong
|
||||
NSView *mTitlebarView; // strong
|
||||
NSRect mWindowButtonsRect;
|
||||
NSRect mFullScreenButtonRect;
|
||||
}
|
||||
// Pass nil here to get the default appearance.
|
||||
- (void)setTitlebarColor:(NSColor*)aColor forActiveWindow:(BOOL)aActive;
|
||||
- (void)setUnifiedToolbarHeight:(CGFloat)aHeight;
|
||||
- (CGFloat)unifiedToolbarHeight;
|
||||
- (CGFloat)titlebarHeight;
|
||||
- (NSRect)titlebarRect;
|
||||
- (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect sync:(BOOL)aSync;
|
||||
- (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect;
|
||||
- (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
|
||||
- (void)setSheetAttachmentPosition:(CGFloat)aY;
|
||||
- (void)placeWindowButtons:(NSRect)aRect;
|
||||
- (void)placeFullScreenButton:(NSRect)aRect;
|
||||
- (NSPoint)windowButtonsPositionWithDefaultPosition:(NSPoint)aDefaultPosition;
|
||||
- (NSPoint)fullScreenButtonPositionWithDefaultPosition:(NSPoint)aDefaultPosition;
|
||||
- (void)setTemporaryBackgroundColor;
|
||||
- (void)restoreBackgroundColor;
|
||||
@end
|
||||
|
||||
class nsCocoaWindow : public nsBaseWidget, public nsPIWidgetCocoa
|
||||
{
|
||||
private:
|
||||
typedef nsBaseWidget Inherited;
|
||||
|
||||
public:
|
||||
|
||||
nsCocoaWindow();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSPIWIDGETCOCOA
|
||||
|
||||
virtual MOZ_MUST_USE nsresult Create(nsIWidget* aParent,
|
||||
nsNativeWidget aNativeParent,
|
||||
const DesktopIntRect& aRect,
|
||||
nsWidgetInitData* aInitData = nullptr)
|
||||
override;
|
||||
|
||||
virtual MOZ_MUST_USE nsresult Create(nsIWidget* aParent,
|
||||
nsNativeWidget aNativeParent,
|
||||
const LayoutDeviceIntRect& aRect,
|
||||
nsWidgetInitData* aInitData = nullptr)
|
||||
override;
|
||||
|
||||
virtual void Destroy() override;
|
||||
|
||||
NS_IMETHOD Show(bool aState) override;
|
||||
virtual nsIWidget* GetSheetWindowParent(void) override;
|
||||
NS_IMETHOD Enable(bool aState) override;
|
||||
virtual bool IsEnabled() const override;
|
||||
virtual void SetModal(bool aState) override;
|
||||
virtual void SetFakeModal(bool aState) override;
|
||||
virtual bool IsRunningAppModal() override;
|
||||
virtual bool IsVisible() const override;
|
||||
NS_IMETHOD SetFocus(bool aState=false) override;
|
||||
virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
|
||||
virtual LayoutDeviceIntPoint GetClientOffset() override;
|
||||
virtual LayoutDeviceIntSize
|
||||
ClientToWindowSize(const LayoutDeviceIntSize& aClientSize) override;
|
||||
|
||||
virtual void* GetNativeData(uint32_t aDataType) override;
|
||||
|
||||
virtual void ConstrainPosition(bool aAllowSlop,
|
||||
int32_t *aX, int32_t *aY) override;
|
||||
virtual void SetSizeConstraints(const SizeConstraints& aConstraints) override;
|
||||
NS_IMETHOD Move(double aX, double aY) override;
|
||||
virtual void SetSizeMode(nsSizeMode aMode) override;
|
||||
NS_IMETHOD HideWindowChrome(bool aShouldHide) override;
|
||||
|
||||
void EnteredFullScreen(bool aFullScreen, bool aNativeMode = true);
|
||||
virtual bool PrepareForFullscreenTransition(nsISupports** aData) override;
|
||||
virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage,
|
||||
uint16_t aDuration,
|
||||
nsISupports* aData,
|
||||
nsIRunnable* aCallback) override;
|
||||
virtual nsresult MakeFullScreen(
|
||||
bool aFullScreen, nsIScreen* aTargetScreen = nullptr) override final;
|
||||
NS_IMETHOD MakeFullScreenWithNativeTransition(
|
||||
bool aFullScreen, nsIScreen* aTargetScreen = nullptr) override final;
|
||||
NSAnimation* FullscreenTransitionAnimation() const { return mFullscreenTransitionAnimation; }
|
||||
void ReleaseFullscreenTransitionAnimation()
|
||||
{
|
||||
MOZ_ASSERT(mFullscreenTransitionAnimation,
|
||||
"Should only be called when there is animation");
|
||||
[mFullscreenTransitionAnimation release];
|
||||
mFullscreenTransitionAnimation = nil;
|
||||
}
|
||||
|
||||
NS_IMETHOD Resize(double aWidth, double aHeight, bool aRepaint) override;
|
||||
NS_IMETHOD Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint) override;
|
||||
virtual LayoutDeviceIntRect GetClientBounds() override;
|
||||
virtual LayoutDeviceIntRect GetScreenBounds() override;
|
||||
void ReportMoveEvent();
|
||||
void ReportSizeEvent();
|
||||
NS_IMETHOD SetCursor(nsCursor aCursor) override;
|
||||
NS_IMETHOD SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY) override;
|
||||
|
||||
CGFloat BackingScaleFactor();
|
||||
void BackingScaleFactorChanged();
|
||||
virtual double GetDefaultScaleInternal() override;
|
||||
virtual int32_t RoundsWidgetCoordinatesTo() override;
|
||||
|
||||
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() final {
|
||||
return mozilla::DesktopToLayoutDeviceScale(BackingScaleFactor());
|
||||
}
|
||||
|
||||
NS_IMETHOD SetTitle(const nsAString& aTitle) override;
|
||||
|
||||
NS_IMETHOD Invalidate(const LayoutDeviceIntRect& aRect) override;
|
||||
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
|
||||
virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
|
||||
LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
|
||||
LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
|
||||
NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
|
||||
nsEventStatus& aStatus) override;
|
||||
virtual void CaptureRollupEvents(nsIRollupListener * aListener,
|
||||
bool aDoCapture) override;
|
||||
NS_IMETHOD GetAttention(int32_t aCycleCount) override;
|
||||
virtual bool HasPendingInputEvent() override;
|
||||
virtual nsTransparencyMode GetTransparencyMode() override;
|
||||
virtual void SetTransparencyMode(nsTransparencyMode aMode) override;
|
||||
virtual void SetWindowShadowStyle(int32_t aStyle) override;
|
||||
virtual void SetShowsToolbarButton(bool aShow) override;
|
||||
virtual void SetShowsFullScreenButton(bool aShow) override;
|
||||
virtual void SetWindowAnimationType(WindowAnimationType aType) override;
|
||||
virtual void SetDrawsTitle(bool aDrawTitle) override;
|
||||
virtual void SetUseBrightTitlebarForeground(bool aBrightForeground) override;
|
||||
NS_IMETHOD SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override;
|
||||
virtual void SetWindowTitlebarColor(nscolor aColor, bool aActive) override;
|
||||
virtual void SetDrawsInTitlebar(bool aState) override;
|
||||
virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override;
|
||||
virtual nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
|
||||
uint32_t aNativeMessage,
|
||||
uint32_t aModifierFlags,
|
||||
nsIObserver* aObserver) override;
|
||||
|
||||
void DispatchSizeModeEvent();
|
||||
|
||||
// be notified that a some form of drag event needs to go into Gecko
|
||||
virtual bool DragEvent(unsigned int aMessage, mozilla::gfx::Point aMouseGlobal, UInt16 aKeyModifiers);
|
||||
|
||||
bool HasModalDescendents() { return mNumModalDescendents > 0; }
|
||||
NSWindow *GetCocoaWindow() { return mWindow; }
|
||||
|
||||
void SetMenuBar(nsMenuBarX* aMenuBar);
|
||||
nsMenuBarX *GetMenuBar();
|
||||
|
||||
NS_IMETHOD_(void) SetInputContext(
|
||||
const InputContext& aContext,
|
||||
const InputContextAction& aAction) override;
|
||||
NS_IMETHOD_(InputContext) GetInputContext() override
|
||||
{
|
||||
return mInputContext;
|
||||
}
|
||||
NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
|
||||
NativeKeyBindingsType aType,
|
||||
const mozilla::WidgetKeyboardEvent& aEvent,
|
||||
DoCommandCallback aCallback,
|
||||
void* aCallbackData) override;
|
||||
|
||||
void SetPopupWindowLevel();
|
||||
|
||||
protected:
|
||||
virtual ~nsCocoaWindow();
|
||||
|
||||
nsresult CreateNativeWindow(const NSRect &aRect,
|
||||
nsBorderStyle aBorderStyle,
|
||||
bool aRectIsFrameRect);
|
||||
nsresult CreatePopupContentView(const LayoutDeviceIntRect &aRect,
|
||||
nsWidgetInitData* aInitData);
|
||||
void DestroyNativeWindow();
|
||||
void AdjustWindowShadow();
|
||||
void SetWindowBackgroundBlur();
|
||||
void UpdateBounds();
|
||||
|
||||
nsresult DoResize(double aX, double aY, double aWidth, double aHeight,
|
||||
bool aRepaint, bool aConstrainToCurrentScreen);
|
||||
|
||||
inline bool ShouldToggleNativeFullscreen(bool aFullScreen,
|
||||
bool aUseSystemTransition);
|
||||
nsresult DoMakeFullScreen(bool aFullScreen, bool aUseSystemTransition);
|
||||
|
||||
virtual already_AddRefed<nsIWidget>
|
||||
AllocateChildPopupWidget() override
|
||||
{
|
||||
static NS_DEFINE_IID(kCPopUpCID, NS_POPUP_CID);
|
||||
nsCOMPtr<nsIWidget> widget = do_CreateInstance(kCPopUpCID);
|
||||
return widget.forget();
|
||||
}
|
||||
|
||||
nsIWidget* mParent; // if we're a popup, this is our parent [WEAK]
|
||||
nsIWidget* mAncestorLink; // link to traverse ancestors [WEAK]
|
||||
BaseWindow* mWindow; // our cocoa window [STRONG]
|
||||
WindowDelegate* mDelegate; // our delegate for processing window msgs [STRONG]
|
||||
RefPtr<nsMenuBarX> mMenuBar;
|
||||
NSWindow* mSheetWindowParent; // if this is a sheet, this is the NSWindow it's attached to
|
||||
nsChildView* mPopupContentView; // if this is a popup, this is its content widget
|
||||
// if this is a toplevel window, and there is any ongoing fullscreen
|
||||
// transition, it is the animation object.
|
||||
NSAnimation* mFullscreenTransitionAnimation;
|
||||
int32_t mShadowStyle;
|
||||
|
||||
CGFloat mBackingScaleFactor;
|
||||
|
||||
WindowAnimationType mAnimationType;
|
||||
|
||||
bool mWindowMadeHere; // true if we created the window, false for embedding
|
||||
bool mSheetNeedsShow; // if this is a sheet, are we waiting to be shown?
|
||||
// this is used for sibling sheet contention only
|
||||
bool mInFullScreenMode;
|
||||
bool mInFullScreenTransition; // true from the request to enter/exit fullscreen
|
||||
// (MakeFullScreen() call) to EnteredFullScreen()
|
||||
bool mModal;
|
||||
bool mFakeModal;
|
||||
|
||||
// Only true on 10.7+ if SetShowsFullScreenButton(true) is called.
|
||||
bool mSupportsNativeFullScreen;
|
||||
// Whether we are currently using native fullscreen. It could be false because
|
||||
// we are in the DOM fullscreen where we do not use the native fullscreen.
|
||||
bool mInNativeFullScreenMode;
|
||||
|
||||
bool mIsAnimationSuppressed;
|
||||
|
||||
bool mInReportMoveEvent; // true if in a call to ReportMoveEvent().
|
||||
bool mInResize; // true if in a call to DoResize().
|
||||
|
||||
bool mAlwaysOnTop;
|
||||
|
||||
int32_t mNumModalDescendents;
|
||||
InputContext mInputContext;
|
||||
};
|
||||
|
||||
#endif // nsCocoaWindow_h_
|
||||
@@ -1,50 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsColorPicker_h_
|
||||
#define nsColorPicker_h_
|
||||
|
||||
#include "nsIColorPicker.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIColorPickerShownCallback;
|
||||
class mozIDOMWindowProxy;
|
||||
@class NSColorPanelWrapper;
|
||||
@class NSColor;
|
||||
|
||||
class nsColorPicker final : public nsIColorPicker
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
|
||||
const nsAString& aInitialColor) override;
|
||||
NS_IMETHOD Open(nsIColorPickerShownCallback* aCallback) override;
|
||||
|
||||
// For NSColorPanelWrapper.
|
||||
void Update(NSColor* aColor);
|
||||
// Call this method if you are done with this input, but the color picker needs to
|
||||
// stay open as it will be associated to another input
|
||||
void DoneWithRetarget();
|
||||
// Same as DoneWithRetarget + clean the static instance of sColorPanelWrapper,
|
||||
// as it is not needed anymore for now
|
||||
void Done();
|
||||
|
||||
private:
|
||||
~nsColorPicker();
|
||||
|
||||
static NSColor* GetNSColorFromHexString(const nsAString& aColor);
|
||||
static void GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult);
|
||||
|
||||
static NSColorPanelWrapper* sColorPanelWrapper;
|
||||
|
||||
nsString mTitle;
|
||||
nsString mColor;
|
||||
nsCOMPtr<nsIColorPickerShownCallback> mCallback;
|
||||
};
|
||||
|
||||
#endif // nsColorPicker_h_
|
||||
@@ -1,188 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "nsColorPicker.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static unsigned int
|
||||
HexStrToInt(NSString* str)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
|
||||
for (unsigned int i = 0; i < [str length]; ++i) {
|
||||
char c = [str characterAtIndex:i];
|
||||
result *= 16;
|
||||
if (c >= '0' && c <= '9') {
|
||||
result += c - '0';
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
result += 10 + (c - 'A');
|
||||
} else {
|
||||
result += 10 + (c - 'a');
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@interface NSColorPanelWrapper : NSObject <NSWindowDelegate>
|
||||
{
|
||||
NSColorPanel* mColorPanel;
|
||||
nsColorPicker* mColorPicker;
|
||||
}
|
||||
- (id)initWithPicker:(nsColorPicker*)aPicker;
|
||||
- (void)open:(NSColor*)aInitialColor title:(NSString*)aTitle;
|
||||
- (void)retarget:(nsColorPicker*)aPicker;
|
||||
- (void)colorChanged:(NSColorPanel*)aPanel;
|
||||
@end
|
||||
|
||||
@implementation NSColorPanelWrapper
|
||||
- (id)initWithPicker:(nsColorPicker*)aPicker
|
||||
{
|
||||
mColorPicker = aPicker;
|
||||
mColorPanel = [NSColorPanel sharedColorPanel];
|
||||
|
||||
self = [super init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)open:(NSColor*)aInitialColor title:(NSString*)aTitle
|
||||
{
|
||||
[mColorPanel setTarget:self];
|
||||
[mColorPanel setAction:@selector(colorChanged:)];
|
||||
[mColorPanel setDelegate:self];
|
||||
[mColorPanel setTitle:aTitle];
|
||||
[mColorPanel setColor:aInitialColor];
|
||||
[mColorPanel makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
- (void)colorChanged:(NSColorPanel*)aPanel
|
||||
{
|
||||
mColorPicker->Update([mColorPanel color]);
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)aNotification
|
||||
{
|
||||
mColorPicker->Done();
|
||||
}
|
||||
|
||||
- (void)retarget:(nsColorPicker*)aPicker
|
||||
{
|
||||
mColorPicker->DoneWithRetarget();
|
||||
mColorPicker = aPicker;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[mColorPanel setTarget:nil];
|
||||
[mColorPanel setAction:nil];
|
||||
[mColorPanel setDelegate:nil];
|
||||
|
||||
mColorPanel = nil;
|
||||
mColorPicker = nullptr;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
|
||||
|
||||
NSColorPanelWrapper* nsColorPicker::sColorPanelWrapper = nullptr;
|
||||
|
||||
nsColorPicker::~nsColorPicker()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsColorPicker::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
|
||||
const nsAString& aInitialColor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"Color pickers can only be opened from main thread currently");
|
||||
mTitle = aTitle;
|
||||
mColor = aInitialColor;
|
||||
|
||||
if (sColorPanelWrapper) {
|
||||
// Update current wrapper to target the new input instead
|
||||
[sColorPanelWrapper retarget:this];
|
||||
} else {
|
||||
// Create a brand new color panel wrapper
|
||||
sColorPanelWrapper = [[NSColorPanelWrapper alloc] initWithPicker:this];
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ NSColor*
|
||||
nsColorPicker::GetNSColorFromHexString(const nsAString& aColor)
|
||||
{
|
||||
NSString* str = nsCocoaUtils::ToNSString(aColor);
|
||||
|
||||
double red = HexStrToInt([str substringWithRange:NSMakeRange(1, 2)]) / 255.0;
|
||||
double green = HexStrToInt([str substringWithRange:NSMakeRange(3, 2)]) / 255.0;
|
||||
double blue = HexStrToInt([str substringWithRange:NSMakeRange(5, 2)]) / 255.0;
|
||||
|
||||
return [NSColor colorWithDeviceRed: red green: green blue: blue alpha: 1.0];
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsColorPicker::GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult)
|
||||
{
|
||||
CGFloat redFloat, greenFloat, blueFloat;
|
||||
|
||||
NSColor* color = aColor;
|
||||
@try {
|
||||
[color getRed:&redFloat green:&greenFloat blue:&blueFloat alpha: nil];
|
||||
} @catch (NSException* e) {
|
||||
color = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
|
||||
[color getRed:&redFloat green:&greenFloat blue:&blueFloat alpha: nil];
|
||||
}
|
||||
|
||||
nsCocoaUtils::GetStringForNSString([NSString stringWithFormat:@"#%02x%02x%02x",
|
||||
(int)(redFloat * 255),
|
||||
(int)(greenFloat * 255),
|
||||
(int)(blueFloat * 255)],
|
||||
aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsColorPicker::Open(nsIColorPickerShownCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(aCallback);
|
||||
mCallback = aCallback;
|
||||
|
||||
[sColorPanelWrapper open:GetNSColorFromHexString(mColor)
|
||||
title:nsCocoaUtils::ToNSString(mTitle)];
|
||||
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsColorPicker::Update(NSColor* aColor)
|
||||
{
|
||||
GetHexStringFromNSColor(aColor, mColor);
|
||||
mCallback->Update(mColor);
|
||||
}
|
||||
|
||||
void
|
||||
nsColorPicker::DoneWithRetarget()
|
||||
{
|
||||
mCallback->Done(EmptyString());
|
||||
mCallback = nullptr;
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
|
||||
void
|
||||
nsColorPicker::Done()
|
||||
{
|
||||
[sColorPanelWrapper release];
|
||||
sColorPanelWrapper = nullptr;
|
||||
DoneWithRetarget();
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsCursorManager_h_
|
||||
#define nsCursorManager_h_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "nsIWidget.h"
|
||||
#include "nsMacCursor.h"
|
||||
|
||||
/*! @class nsCursorManager
|
||||
@abstract Singleton service provides access to all cursors available in the application.
|
||||
@discussion Use <code>nsCusorManager</code> to set the current cursor using an XP <code>nsCusor</code> enum value.
|
||||
<code>nsCursorManager</code> encapsulates the details of setting different types of cursors, animating
|
||||
cursors and cleaning up cursors when they are no longer in use.
|
||||
*/
|
||||
@interface nsCursorManager : NSObject
|
||||
{
|
||||
@private
|
||||
NSMutableDictionary *mCursors;
|
||||
nsMacCursor *mCurrentMacCursor;
|
||||
}
|
||||
|
||||
/*! @method setCursor:
|
||||
@abstract Sets the current cursor.
|
||||
@discussion Sets the current cursor to the cursor indicated by the XP cursor constant given as an argument.
|
||||
Resources associated with the previous cursor are cleaned up.
|
||||
@param aCursor the cursor to use
|
||||
*/
|
||||
- (nsresult) setCursor: (nsCursor) aCursor;
|
||||
|
||||
/*! @method setCursorWithImage:hotSpotX:hotSpotY:
|
||||
@abstract Sets the current cursor to a custom image
|
||||
@discussion Sets the current cursor to the cursor given by the aCursorImage argument.
|
||||
Resources associated with the previous cursor are cleaned up.
|
||||
@param aCursorImage the cursor image to use
|
||||
@param aHotSpotX the x coordinate of the cursor's hotspot
|
||||
@param aHotSpotY the y coordinate of the cursor's hotspot
|
||||
@param scaleFactor the scale factor of the target display (2 for a retina display)
|
||||
*/
|
||||
- (nsresult) setCursorWithImage: (imgIContainer*) aCursorImage hotSpotX: (uint32_t) aHotspotX hotSpotY: (uint32_t) aHotspotY scaleFactor: (CGFloat) scaleFactor;
|
||||
|
||||
|
||||
/*! @method sharedInstance
|
||||
@abstract Get the Singleton instance of the cursor manager.
|
||||
@discussion Use this method to obtain a reference to the cursor manager.
|
||||
@result a reference to the cursor manager
|
||||
*/
|
||||
+ (nsCursorManager *) sharedInstance;
|
||||
|
||||
/*! @method dispose
|
||||
@abstract Releases the shared instance of the cursor manager.
|
||||
@discussion Use dispose to clean up the cursor manager and associated cursors.
|
||||
*/
|
||||
+ (void) dispose;
|
||||
@end
|
||||
|
||||
@interface NSCursor (Undocumented)
|
||||
// busyButClickableCursor is an undocumented NSCursor API, but has been in use since
|
||||
// at least OS X 10.4 and through 10.9.
|
||||
+ (NSCursor*)busyButClickableCursor;
|
||||
@end
|
||||
|
||||
#endif // nsCursorManager_h_
|
||||
@@ -1,308 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "imgIContainer.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsCursorManager.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include <math.h>
|
||||
|
||||
static nsCursorManager *gInstance;
|
||||
static CGFloat sCursorScaleFactor = 0.0f;
|
||||
static imgIContainer *sCursorImgContainer = nullptr;
|
||||
static const nsCursor sCustomCursor = eCursorCount;
|
||||
|
||||
/*! @category nsCursorManager(PrivateMethods)
|
||||
Private methods for the cursor manager class.
|
||||
*/
|
||||
@interface nsCursorManager(PrivateMethods)
|
||||
/*! @method getCursor:
|
||||
@abstract Get a reference to the native Mac representation of a cursor.
|
||||
@discussion Gets a reference to the Mac native implementation of a cursor.
|
||||
If the cursor has been requested before, it is retreived from the cursor cache,
|
||||
otherwise it is created and cached.
|
||||
@param aCursor the cursor to get
|
||||
@result the Mac native implementation of the cursor
|
||||
*/
|
||||
- (nsMacCursor *) getCursor: (nsCursor) aCursor;
|
||||
|
||||
/*! @method setMacCursor:
|
||||
@abstract Set the current Mac native cursor
|
||||
@discussion Sets the current cursor - this routine is what actually causes the cursor to change.
|
||||
The argument is retained and the old cursor is released.
|
||||
@param aMacCursor the cursor to set
|
||||
@result NS_OK
|
||||
*/
|
||||
- (nsresult) setMacCursor: (nsMacCursor*) aMacCursor;
|
||||
|
||||
/*! @method createCursor:
|
||||
@abstract Create a Mac native representation of a cursor.
|
||||
@discussion Creates a version of the Mac native representation of this cursor
|
||||
@param aCursor the cursor to create
|
||||
@result the Mac native implementation of the cursor
|
||||
*/
|
||||
+ (nsMacCursor *) createCursor: (enum nsCursor) aCursor;
|
||||
|
||||
@end
|
||||
|
||||
@implementation nsCursorManager
|
||||
|
||||
+ (nsCursorManager *) sharedInstance
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
if (!gInstance) {
|
||||
gInstance = [[nsCursorManager alloc] init];
|
||||
}
|
||||
return gInstance;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
+ (void) dispose
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
[gInstance release];
|
||||
gInstance = nil;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
+ (nsMacCursor *) createCursor: (enum nsCursor) aCursor
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
switch(aCursor)
|
||||
{
|
||||
SEL cursorSelector;
|
||||
case eCursor_standard:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
|
||||
case eCursor_wait:
|
||||
case eCursor_spinning:
|
||||
{
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor] type:aCursor];
|
||||
}
|
||||
case eCursor_select:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor];
|
||||
case eCursor_hyperlink:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor] type:aCursor];
|
||||
case eCursor_crosshair:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor] type:aCursor];
|
||||
case eCursor_move:
|
||||
return [nsMacCursor cursorWithImageNamed:@"move" hotSpot:NSMakePoint(12,12) type:aCursor];
|
||||
case eCursor_help:
|
||||
return [nsMacCursor cursorWithImageNamed:@"help" hotSpot:NSMakePoint(12,12) type:aCursor];
|
||||
case eCursor_copy:
|
||||
cursorSelector = @selector(dragCopyCursor);
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
|
||||
[NSCursor performSelector:cursorSelector] :
|
||||
[NSCursor arrowCursor] type:aCursor];
|
||||
case eCursor_alias:
|
||||
cursorSelector = @selector(dragLinkCursor);
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
|
||||
[NSCursor performSelector:cursorSelector] :
|
||||
[NSCursor arrowCursor] type:aCursor];
|
||||
case eCursor_context_menu:
|
||||
cursorSelector = @selector(contextualMenuCursor);
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
|
||||
[NSCursor performSelector:cursorSelector] :
|
||||
[NSCursor arrowCursor] type:aCursor];
|
||||
case eCursor_cell:
|
||||
return [nsMacCursor cursorWithImageNamed:@"cell" hotSpot:NSMakePoint(12,12) type:aCursor];
|
||||
case eCursor_grab:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
|
||||
case eCursor_grabbing:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor] type:aCursor];
|
||||
case eCursor_zoom_in:
|
||||
return [nsMacCursor cursorWithImageNamed:@"zoomIn" hotSpot:NSMakePoint(10,10) type:aCursor];
|
||||
case eCursor_zoom_out:
|
||||
return [nsMacCursor cursorWithImageNamed:@"zoomOut" hotSpot:NSMakePoint(10,10) type:aCursor];
|
||||
case eCursor_vertical_text:
|
||||
return [nsMacCursor cursorWithImageNamed:@"vtIBeam" hotSpot:NSMakePoint(12,11) type:aCursor];
|
||||
case eCursor_all_scroll:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
|
||||
case eCursor_not_allowed:
|
||||
case eCursor_no_drop:
|
||||
cursorSelector = @selector(operationNotAllowedCursor);
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
|
||||
[NSCursor performSelector:cursorSelector] :
|
||||
[NSCursor arrowCursor] type:aCursor];
|
||||
// Resize Cursors:
|
||||
// North
|
||||
case eCursor_n_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor] type:aCursor];
|
||||
// North East
|
||||
case eCursor_ne_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNE" hotSpot:NSMakePoint(12,11) type:aCursor];
|
||||
// East
|
||||
case eCursor_e_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor] type:aCursor];
|
||||
// South East
|
||||
case eCursor_se_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeSE" hotSpot:NSMakePoint(12,12) type:aCursor];
|
||||
// South
|
||||
case eCursor_s_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor] type:aCursor];
|
||||
// South West
|
||||
case eCursor_sw_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeSW" hotSpot:NSMakePoint(10,12) type:aCursor];
|
||||
// West
|
||||
case eCursor_w_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor] type:aCursor];
|
||||
// North West
|
||||
case eCursor_nw_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNW" hotSpot:NSMakePoint(11,11) type:aCursor];
|
||||
// North & South
|
||||
case eCursor_ns_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor] type:aCursor];
|
||||
// East & West
|
||||
case eCursor_ew_resize:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor] type:aCursor];
|
||||
// North East & South West
|
||||
case eCursor_nesw_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNESW" hotSpot:NSMakePoint(12,12) type:aCursor];
|
||||
// North West & South East
|
||||
case eCursor_nwse_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"sizeNWSE" hotSpot:NSMakePoint(12,12) type:aCursor];
|
||||
// Column Resize
|
||||
case eCursor_col_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"colResize" hotSpot:NSMakePoint(12,12) type:aCursor];
|
||||
// Row Resize
|
||||
case eCursor_row_resize:
|
||||
return [nsMacCursor cursorWithImageNamed:@"rowResize" hotSpot:NSMakePoint(12,12) type:aCursor];
|
||||
default:
|
||||
return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
if ((self = [super init])) {
|
||||
mCursors = [[NSMutableDictionary alloc] initWithCapacity:25];
|
||||
}
|
||||
return self;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
- (nsresult) setCursor: (enum nsCursor) aCursor
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
// Some plugins mess with our cursors and set a cursor that even
|
||||
// [NSCursor currentCursor] doesn't know about. In case that happens, just
|
||||
// reset the state.
|
||||
[[NSCursor currentCursor] set];
|
||||
|
||||
nsCursor oldType = [mCurrentMacCursor type];
|
||||
if (oldType != aCursor) {
|
||||
if (aCursor == eCursor_none) {
|
||||
[NSCursor hide];
|
||||
} else if (oldType == eCursor_none) {
|
||||
[NSCursor unhide];
|
||||
}
|
||||
}
|
||||
[self setMacCursor:[self getCursor:aCursor]];
|
||||
|
||||
// if a custom cursor was previously set, release sCursorImgContainer
|
||||
if (oldType == sCustomCursor) {
|
||||
NS_IF_RELEASE(sCursorImgContainer);
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
- (nsresult) setMacCursor: (nsMacCursor*) aMacCursor
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (mCurrentMacCursor != aMacCursor || ![mCurrentMacCursor isSet]) {
|
||||
[aMacCursor retain];
|
||||
[mCurrentMacCursor unset];
|
||||
[aMacCursor set];
|
||||
[mCurrentMacCursor release];
|
||||
mCurrentMacCursor = aMacCursor;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
- (nsresult) setCursorWithImage: (imgIContainer*) aCursorImage hotSpotX: (uint32_t) aHotspotX hotSpotY: (uint32_t) aHotspotY scaleFactor: (CGFloat) scaleFactor
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
// As the user moves the mouse, this gets called repeatedly with the same aCursorImage
|
||||
if (sCursorImgContainer == aCursorImage && sCursorScaleFactor == scaleFactor && mCurrentMacCursor) {
|
||||
[self setMacCursor:mCurrentMacCursor];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
[[NSCursor currentCursor] set];
|
||||
int32_t width = 0, height = 0;
|
||||
aCursorImage->GetWidth(&width);
|
||||
aCursorImage->GetHeight(&height);
|
||||
// prevent DoS attacks
|
||||
if (width > 128 || height > 128) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NSImage *cursorImage;
|
||||
nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(aCursorImage, imgIContainer::FRAME_FIRST, &cursorImage, scaleFactor);
|
||||
if (NS_FAILED(rv) || !cursorImage) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// if the hotspot is nonsensical, make it 0,0
|
||||
aHotspotX = (aHotspotX > (uint32_t)width - 1) ? 0 : aHotspotX;
|
||||
aHotspotY = (aHotspotY > (uint32_t)height - 1) ? 0 : aHotspotY;
|
||||
|
||||
NSPoint hotSpot = ::NSMakePoint(aHotspotX, aHotspotY);
|
||||
[self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc] initWithImage:cursorImage hotSpot:hotSpot] type:sCustomCursor]];
|
||||
[cursorImage release];
|
||||
|
||||
NS_IF_RELEASE(sCursorImgContainer);
|
||||
sCursorImgContainer = aCursorImage;
|
||||
sCursorScaleFactor = scaleFactor;
|
||||
NS_ADDREF(sCursorImgContainer);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
- (nsMacCursor *) getCursor: (enum nsCursor) aCursor
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
nsMacCursor * result = [mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
|
||||
if (!result) {
|
||||
result = [nsCursorManager createCursor:aCursor];
|
||||
[mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]];
|
||||
}
|
||||
return result;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
[mCurrentMacCursor unset];
|
||||
[mCurrentMacCursor release];
|
||||
[mCursors release];
|
||||
NS_IF_RELEASE(sCursorImgContainer);
|
||||
[super dealloc];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,41 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsDeviceContextSpecX_h_
|
||||
#define nsDeviceContextSpecX_h_
|
||||
|
||||
#include "nsIDeviceContextSpec.h"
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
class nsDeviceContextSpecX : public nsIDeviceContextSpec
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsDeviceContextSpecX();
|
||||
|
||||
NS_IMETHOD Init(nsIWidget *aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override;
|
||||
virtual already_AddRefed<PrintTarget> MakePrintTarget() final;
|
||||
NS_IMETHOD BeginDocument(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage,
|
||||
int32_t aEndPage) override;
|
||||
NS_IMETHOD EndDocument() override;
|
||||
NS_IMETHOD BeginPage() override;
|
||||
NS_IMETHOD EndPage() override;
|
||||
|
||||
void GetPaperRect(double* aTop, double* aLeft, double* aBottom, double* aRight);
|
||||
|
||||
protected:
|
||||
virtual ~nsDeviceContextSpecX();
|
||||
|
||||
protected:
|
||||
PMPrintSession mPrintSession; // printing context.
|
||||
PMPageFormat mPageFormat; // page format.
|
||||
PMPrintSettings mPrintSettings; // print settings.
|
||||
};
|
||||
|
||||
#endif //nsDeviceContextSpecX_h_
|
||||
@@ -1,165 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsDeviceContextSpecX.h"
|
||||
|
||||
#include "mozilla/gfx/PrintTargetCG.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCRT.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsPrintSettingsX.h"
|
||||
|
||||
// This must be the last include:
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
nsDeviceContextSpecX::nsDeviceContextSpecX()
|
||||
: mPrintSession(NULL)
|
||||
, mPageFormat(kPMNoPageFormat)
|
||||
, mPrintSettings(kPMNoPrintSettings)
|
||||
{
|
||||
}
|
||||
|
||||
nsDeviceContextSpecX::~nsDeviceContextSpecX()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (mPrintSession)
|
||||
::PMRelease(mPrintSession);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDeviceContextSpecX, nsIDeviceContextSpec)
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIWidget *aWidget,
|
||||
nsIPrintSettings* aPS,
|
||||
bool aIsPrintPreview)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
RefPtr<nsPrintSettingsX> settings(do_QueryObject(aPS));
|
||||
if (!settings)
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
|
||||
mPrintSession = settings->GetPMPrintSession();
|
||||
::PMRetain(mPrintSession);
|
||||
mPageFormat = settings->GetPMPageFormat();
|
||||
mPrintSettings = settings->GetPMPrintSettings();
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage,
|
||||
int32_t aEndPage)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (!aTitle.IsEmpty()) {
|
||||
CFStringRef cfString =
|
||||
::CFStringCreateWithCharacters(NULL, reinterpret_cast<const UniChar*>(aTitle.BeginReading()),
|
||||
aTitle.Length());
|
||||
if (cfString) {
|
||||
::PMPrintSettingsSetJobName(mPrintSettings, cfString);
|
||||
::CFRelease(cfString);
|
||||
}
|
||||
}
|
||||
|
||||
OSStatus status;
|
||||
status = ::PMSetFirstPage(mPrintSettings, aStartPage, false);
|
||||
NS_ASSERTION(status == noErr, "PMSetFirstPage failed");
|
||||
status = ::PMSetLastPage(mPrintSettings, aEndPage, false);
|
||||
NS_ASSERTION(status == noErr, "PMSetLastPage failed");
|
||||
|
||||
status = ::PMSessionBeginCGDocumentNoDialog(mPrintSession, mPrintSettings, mPageFormat);
|
||||
if (status != noErr)
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::EndDocument()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
::PMSessionEndDocumentNoDialog(mPrintSession);
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::BeginPage()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
PMSessionError(mPrintSession);
|
||||
OSStatus status = ::PMSessionBeginPageNoDialog(mPrintSession, mPageFormat, NULL);
|
||||
if (status != noErr) return NS_ERROR_ABORT;
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDeviceContextSpecX::EndPage()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
OSStatus status = ::PMSessionEndPageNoDialog(mPrintSession);
|
||||
if (status != noErr) return NS_ERROR_ABORT;
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
void nsDeviceContextSpecX::GetPaperRect(double* aTop, double* aLeft, double* aBottom, double* aRight)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
PMRect paperRect;
|
||||
::PMGetAdjustedPaperRect(mPageFormat, &paperRect);
|
||||
|
||||
*aTop = paperRect.top, *aLeft = paperRect.left;
|
||||
*aBottom = paperRect.bottom, *aRight = paperRect.right;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
already_AddRefed<PrintTarget> nsDeviceContextSpecX::MakePrintTarget()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
double top, left, bottom, right;
|
||||
GetPaperRect(&top, &left, &bottom, &right);
|
||||
const double width = right - left;
|
||||
const double height = bottom - top;
|
||||
IntSize size = IntSize::Floor(width, height);
|
||||
|
||||
CGContextRef context;
|
||||
::PMSessionGetCGGraphicsContext(mPrintSession, &context);
|
||||
|
||||
if (context) {
|
||||
// Initially, origin is at bottom-left corner of the paper.
|
||||
// Here, we translate it to top-left corner of the paper.
|
||||
CGContextTranslateCTM(context, 0, height);
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
return PrintTargetCG::CreateOrNull(context, size);
|
||||
}
|
||||
|
||||
// Apparently we do need this branch - bug 368933.
|
||||
return PrintTargetCG::CreateOrNull(size, SurfaceFormat::A8R8G8B8_UINT32);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsDragService_h_
|
||||
#define nsDragService_h_
|
||||
|
||||
#include "nsBaseDragService.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
extern NSString* const kWildcardPboardType;
|
||||
extern NSString* const kCorePboardType_url;
|
||||
extern NSString* const kCorePboardType_urld;
|
||||
extern NSString* const kCorePboardType_urln;
|
||||
extern NSString* const kCustomTypesPboardType;
|
||||
|
||||
class nsDragService : public nsBaseDragService
|
||||
{
|
||||
public:
|
||||
nsDragService();
|
||||
|
||||
// nsBaseDragService
|
||||
virtual nsresult InvokeDragSessionImpl(nsIArray* anArrayTransferables,
|
||||
nsIScriptableRegion* aRegion,
|
||||
uint32_t aActionType);
|
||||
// nsIDragService
|
||||
NS_IMETHOD EndDragSession(bool aDoneDrag);
|
||||
|
||||
// nsIDragSession
|
||||
NS_IMETHOD GetData(nsITransferable * aTransferable, uint32_t aItemIndex);
|
||||
NS_IMETHOD IsDataFlavorSupported(const char *aDataFlavor, bool *_retval);
|
||||
NS_IMETHOD GetNumDropItems(uint32_t * aNumItems);
|
||||
|
||||
protected:
|
||||
virtual ~nsDragService();
|
||||
|
||||
private:
|
||||
|
||||
NSImage* ConstructDragImage(nsIDOMNode* aDOMNode,
|
||||
mozilla::LayoutDeviceIntRect* aDragRect,
|
||||
nsIScriptableRegion* aRegion);
|
||||
bool IsValidType(NSString* availableType, bool allowFileURL);
|
||||
NSString* GetStringForType(NSPasteboardItem* item, const NSString* type,
|
||||
bool allowFileURL = false);
|
||||
NSString* GetTitleForURL(NSPasteboardItem* item);
|
||||
NSString* GetFilePath(NSPasteboardItem* item);
|
||||
|
||||
nsCOMPtr<nsIArray> mDataItems; // only valid for a drag started within gecko
|
||||
NSView* mNativeDragView;
|
||||
NSEvent* mNativeDragEvent;
|
||||
};
|
||||
|
||||
#endif // nsDragService_h_
|
||||
@@ -1,669 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsDragService.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsString.h"
|
||||
#include "nsClipboard.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsPrimitiveHelpers.h"
|
||||
#include "nsLinebreakConverter.h"
|
||||
#include "nsIMacUtils.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsPoint.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsView.h"
|
||||
#include "gfxContext.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
extern PRLogModuleInfo* sCocoaLog;
|
||||
|
||||
extern void EnsureLogInitialized();
|
||||
|
||||
extern NSPasteboard* globalDragPboard;
|
||||
extern NSView* gLastDragView;
|
||||
extern NSEvent* gLastDragMouseDownEvent;
|
||||
extern bool gUserCancelledDrag;
|
||||
|
||||
// This global makes the transferable array available to Cocoa's promised
|
||||
// file destination callback.
|
||||
nsIArray *gDraggedTransferables = nullptr;
|
||||
|
||||
NSString* const kWildcardPboardType = @"MozillaWildcard";
|
||||
NSString* const kCorePboardType_url = @"CorePasteboardFlavorType 0x75726C20"; // 'url ' url
|
||||
NSString* const kCorePboardType_urld = @"CorePasteboardFlavorType 0x75726C64"; // 'urld' desc
|
||||
NSString* const kCorePboardType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln' title
|
||||
NSString* const kUTTypeURLName = @"public.url-name";
|
||||
NSString* const kCustomTypesPboardType = @"org.mozilla.custom-clipdata";
|
||||
|
||||
nsDragService::nsDragService()
|
||||
{
|
||||
mNativeDragView = nil;
|
||||
mNativeDragEvent = nil;
|
||||
|
||||
EnsureLogInitialized();
|
||||
}
|
||||
|
||||
nsDragService::~nsDragService()
|
||||
{
|
||||
}
|
||||
|
||||
static nsresult SetUpDragClipboard(nsIArray* aTransferableArray)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (!aTransferableArray)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
uint32_t count = 0;
|
||||
aTransferableArray->GetLength(&count);
|
||||
|
||||
NSPasteboard* dragPBoard = [NSPasteboard pasteboardWithName:NSDragPboard];
|
||||
|
||||
for (uint32_t j = 0; j < count; j++) {
|
||||
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(aTransferableArray, j);
|
||||
if (!currentTransferable)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Transform the transferable to an NSDictionary
|
||||
NSDictionary* pasteboardOutputDict = nsClipboard::PasteboardDictFromTransferable(currentTransferable);
|
||||
if (!pasteboardOutputDict)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// write everything out to the general pasteboard
|
||||
unsigned int typeCount = [pasteboardOutputDict count];
|
||||
NSMutableArray* types = [NSMutableArray arrayWithCapacity:typeCount + 1];
|
||||
[types addObjectsFromArray:[pasteboardOutputDict allKeys]];
|
||||
// Gecko is initiating this drag so we always want its own views to consider
|
||||
// it. Add our wildcard type to the pasteboard to accomplish this.
|
||||
[types addObject:kWildcardPboardType]; // we don't increase the count for the loop below on purpose
|
||||
[dragPBoard declareTypes:types owner:nil];
|
||||
for (unsigned int k = 0; k < typeCount; k++) {
|
||||
NSString* currentKey = [types objectAtIndex:k];
|
||||
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
||||
if (currentKey == NSStringPboardType ||
|
||||
currentKey == kCorePboardType_url ||
|
||||
currentKey == kCorePboardType_urld ||
|
||||
currentKey == kCorePboardType_urln) {
|
||||
[dragPBoard setString:currentValue forType:currentKey];
|
||||
}
|
||||
else if (currentKey == NSHTMLPboardType) {
|
||||
[dragPBoard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
|
||||
forType:currentKey];
|
||||
}
|
||||
else if (currentKey == NSTIFFPboardType ||
|
||||
currentKey == kCustomTypesPboardType) {
|
||||
[dragPBoard setData:currentValue forType:currentKey];
|
||||
}
|
||||
else if (currentKey == NSFilesPromisePboardType ||
|
||||
currentKey == NSFilenamesPboardType) {
|
||||
[dragPBoard setPropertyList:currentValue forType:currentKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NSImage*
|
||||
nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode,
|
||||
LayoutDeviceIntRect* aDragRect,
|
||||
nsIScriptableRegion* aRegion)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView);
|
||||
|
||||
RefPtr<SourceSurface> surface;
|
||||
nsPresContext* pc;
|
||||
nsresult rv = DrawDrag(aDOMNode, aRegion, mScreenPosition,
|
||||
aDragRect, &surface, &pc);
|
||||
if (pc && (!aDragRect->width || !aDragRect->height)) {
|
||||
// just use some suitable defaults
|
||||
int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor);
|
||||
aDragRect->SetRect(pc->CSSPixelsToDevPixels(mScreenPosition.x),
|
||||
pc->CSSPixelsToDevPixels(mScreenPosition.y), size, size);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) || !surface)
|
||||
return nil;
|
||||
|
||||
uint32_t width = aDragRect->width;
|
||||
uint32_t height = aDragRect->height;
|
||||
|
||||
RefPtr<DataSourceSurface> dataSurface =
|
||||
Factory::CreateDataSourceSurface(IntSize(width, height),
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateDrawTargetForData(BackendType::CAIRO,
|
||||
map.mData,
|
||||
dataSurface->GetSize(),
|
||||
map.mStride,
|
||||
dataSurface->GetFormat());
|
||||
if (!dt) {
|
||||
dataSurface->Unmap();
|
||||
return nil;
|
||||
}
|
||||
|
||||
dt->FillRect(gfx::Rect(0, 0, width, height),
|
||||
SurfacePattern(surface, ExtendMode::CLAMP),
|
||||
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
|
||||
|
||||
NSBitmapImageRep* imageRep =
|
||||
[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:width
|
||||
pixelsHigh:height
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSDeviceRGBColorSpace
|
||||
bytesPerRow:width * 4
|
||||
bitsPerPixel:32];
|
||||
|
||||
uint8_t* dest = [imageRep bitmapData];
|
||||
for (uint32_t i = 0; i < height; ++i) {
|
||||
uint8_t* src = map.mData + i * map.mStride;
|
||||
for (uint32_t j = 0; j < width; ++j) {
|
||||
// Reduce transparency overall by multipying by a factor. Remember, Alpha
|
||||
// is premultipled here. Also, Quartz likes RGBA, so do that translation as well.
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
dest[0] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
|
||||
dest[1] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
|
||||
dest[2] = uint8_t(src[3] * DRAG_TRANSLUCENCY);
|
||||
dest[3] = uint8_t(src[0] * DRAG_TRANSLUCENCY);
|
||||
#else
|
||||
dest[0] = uint8_t(src[2] * DRAG_TRANSLUCENCY);
|
||||
dest[1] = uint8_t(src[1] * DRAG_TRANSLUCENCY);
|
||||
dest[2] = uint8_t(src[0] * DRAG_TRANSLUCENCY);
|
||||
dest[3] = uint8_t(src[3] * DRAG_TRANSLUCENCY);
|
||||
#endif
|
||||
src += 4;
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
dataSurface->Unmap();
|
||||
|
||||
NSImage* image =
|
||||
[[NSImage alloc] initWithSize:NSMakeSize(width / scaleFactor,
|
||||
height / scaleFactor)];
|
||||
[image addRepresentation:imageRep];
|
||||
[imageRep release];
|
||||
|
||||
return [image autorelease];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDragService::IsValidType(NSString* availableType, bool allowFileURL)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
// Prevent exposing fileURL for non-fileURL type.
|
||||
// We need URL provided by dropped webloc file, but don't need file's URL.
|
||||
// kUTTypeFileURL is returned by [NSPasteboard availableTypeFromArray:] for
|
||||
// kUTTypeURL, since it conforms to kUTTypeURL.
|
||||
if (!allowFileURL && [availableType isEqualToString:(id)kUTTypeFileURL]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
|
||||
}
|
||||
|
||||
NSString*
|
||||
nsDragService::GetStringForType(NSPasteboardItem* item, const NSString* type,
|
||||
bool allowFileURL)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
NSString* availableType = [item availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
|
||||
if (availableType && IsValidType(availableType, allowFileURL)) {
|
||||
return [item stringForType:(id)availableType];
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
NSString*
|
||||
nsDragService::GetTitleForURL(NSPasteboardItem* item)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
NSString* name = GetStringForType(item, (const NSString*)kUTTypeURLName);
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
NSString* filePath = GetFilePath(item);
|
||||
if (filePath) {
|
||||
return [filePath lastPathComponent];
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
NSString*
|
||||
nsDragService::GetFilePath(NSPasteboardItem* item)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
NSString* urlString = GetStringForType(item, (const NSString*)kUTTypeFileURL, true);
|
||||
if (urlString) {
|
||||
NSURL* url = [NSURL URLWithString:urlString];
|
||||
if (url) {
|
||||
return [url path];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
// We can only invoke NSView's 'dragImage:at:offset:event:pasteboard:source:slideBack:' from
|
||||
// within NSView's 'mouseDown:' or 'mouseDragged:'. Luckily 'mouseDragged' is always on the
|
||||
// stack when InvokeDragSession gets called.
|
||||
nsresult
|
||||
nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
|
||||
nsIScriptableRegion* aDragRgn,
|
||||
uint32_t aActionType)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
mDataItems = aTransferableArray;
|
||||
|
||||
// put data on the clipboard
|
||||
if (NS_FAILED(SetUpDragClipboard(aTransferableArray)))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView);
|
||||
|
||||
LayoutDeviceIntRect dragRect(0, 0, 20, 20);
|
||||
NSImage* image = ConstructDragImage(mSourceNode, &dragRect, aDragRgn);
|
||||
if (!image) {
|
||||
// if no image was returned, just draw a rectangle
|
||||
NSSize size;
|
||||
size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
|
||||
size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
|
||||
image = [[NSImage alloc] initWithSize:size];
|
||||
[image lockFocus];
|
||||
[[NSColor grayColor] set];
|
||||
NSBezierPath* path = [NSBezierPath bezierPath];
|
||||
[path setLineWidth:2.0];
|
||||
[path moveToPoint:NSMakePoint(0, 0)];
|
||||
[path lineToPoint:NSMakePoint(0, size.height)];
|
||||
[path lineToPoint:NSMakePoint(size.width, size.height)];
|
||||
[path lineToPoint:NSMakePoint(size.width, 0)];
|
||||
[path lineToPoint:NSMakePoint(0, 0)];
|
||||
[path stroke];
|
||||
[image unlockFocus];
|
||||
}
|
||||
|
||||
LayoutDeviceIntPoint pt(dragRect.x, dragRect.YMost());
|
||||
NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor);
|
||||
point.y = nsCocoaUtils::FlippedScreenY(point.y);
|
||||
|
||||
point = nsCocoaUtils::ConvertPointFromScreen([gLastDragView window], point);
|
||||
NSPoint localPoint = [gLastDragView convertPoint:point fromView:nil];
|
||||
|
||||
// Save the transferables away in case a promised file callback is invoked.
|
||||
gDraggedTransferables = aTransferableArray;
|
||||
|
||||
nsBaseDragService::StartDragSession();
|
||||
nsBaseDragService::OpenDragPopup();
|
||||
|
||||
// We need to retain the view and the event during the drag in case either gets destroyed.
|
||||
mNativeDragView = [gLastDragView retain];
|
||||
mNativeDragEvent = [gLastDragMouseDownEvent retain];
|
||||
|
||||
gUserCancelledDrag = false;
|
||||
[mNativeDragView dragImage:image
|
||||
at:localPoint
|
||||
offset:NSZeroSize
|
||||
event:mNativeDragEvent
|
||||
pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]
|
||||
source:mNativeDragView
|
||||
slideBack:YES];
|
||||
gUserCancelledDrag = false;
|
||||
|
||||
if (mDoingDrag)
|
||||
nsBaseDragService::EndDragSession(false);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (!aTransferable)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// get flavor list that includes all acceptable flavors (including ones obtained through conversion)
|
||||
nsCOMPtr<nsIArray> flavorList;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
uint32_t acceptableFlavorCount;
|
||||
flavorList->GetLength(&acceptableFlavorCount);
|
||||
|
||||
// if this drag originated within Mozilla we should just use the cached data from
|
||||
// when the drag started if possible
|
||||
if (mDataItems) {
|
||||
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, aItemIndex);
|
||||
if (currentTransferable) {
|
||||
for (uint32_t i = 0; i < acceptableFlavorCount; i++) {
|
||||
nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i);
|
||||
if (!currentFlavor)
|
||||
continue;
|
||||
nsXPIDLCString flavorStr;
|
||||
currentFlavor->ToString(getter_Copies(flavorStr));
|
||||
|
||||
nsCOMPtr<nsISupports> dataSupports;
|
||||
uint32_t dataSize = 0;
|
||||
rv = currentTransferable->GetTransferData(flavorStr, getter_AddRefs(dataSupports), &dataSize);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aTransferable->SetTransferData(flavorStr, dataSupports, dataSize);
|
||||
return NS_OK; // maybe try to fill in more types? Is there a point?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now check the actual clipboard for data
|
||||
for (uint32_t i = 0; i < acceptableFlavorCount; i++) {
|
||||
nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i);
|
||||
if (!currentFlavor)
|
||||
continue;
|
||||
|
||||
nsXPIDLCString flavorStr;
|
||||
currentFlavor->ToString(getter_Copies(flavorStr));
|
||||
|
||||
MOZ_LOG(sCocoaLog, LogLevel::Info, ("nsDragService::GetData: looking for clipboard data of type %s\n", flavorStr.get()));
|
||||
|
||||
NSArray* droppedItems = [globalDragPboard pasteboardItems];
|
||||
if (!droppedItems) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t itemCount = [droppedItems count];
|
||||
if (aItemIndex >= itemCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSPasteboardItem* item = [droppedItems objectAtIndex:aItemIndex];
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flavorStr.EqualsLiteral(kFileMime)) {
|
||||
NSString* filePath = GetFilePath(item);
|
||||
if (!filePath)
|
||||
continue;
|
||||
|
||||
unsigned int stringLength = [filePath length];
|
||||
unsigned int dataLength = (stringLength + 1) * sizeof(char16_t); // in bytes
|
||||
char16_t* clipboardDataPtr = (char16_t*)malloc(dataLength);
|
||||
if (!clipboardDataPtr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
[filePath getCharacters:reinterpret_cast<unichar*>(clipboardDataPtr)];
|
||||
clipboardDataPtr[stringLength] = 0; // null terminate
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = NS_NewLocalFile(nsDependentString(clipboardDataPtr), true, getter_AddRefs(file));
|
||||
free(clipboardDataPtr);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
aTransferable->SetTransferData(flavorStr, file, dataLength);
|
||||
|
||||
break;
|
||||
}
|
||||
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
NSString* availableType = [item availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
|
||||
if (!availableType || !IsValidType(availableType, false)) {
|
||||
continue;
|
||||
}
|
||||
NSData *pasteboardData = [item dataForType:availableType];
|
||||
if (!pasteboardData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int dataLength = [pasteboardData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
[pasteboardData getBytes:clipboardDataPtr];
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
|
||||
aTransferable->SetTransferData(flavorStr, genericDataWrapper, sizeof(nsIInputStream*));
|
||||
free(clipboardDataPtr);
|
||||
break;
|
||||
}
|
||||
|
||||
NSString* pString = nil;
|
||||
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
||||
pString = GetStringForType(item, (const NSString*)kUTTypeUTF8PlainText);
|
||||
} else if (flavorStr.EqualsLiteral(kHTMLMime)) {
|
||||
pString = GetStringForType(item, (const NSString*)kUTTypeHTML);
|
||||
} else if (flavorStr.EqualsLiteral(kURLMime)) {
|
||||
pString = GetStringForType(item, (const NSString*)kUTTypeURL);
|
||||
if (pString) {
|
||||
NSString* title = GetTitleForURL(item);
|
||||
if (!title) {
|
||||
title = pString;
|
||||
}
|
||||
pString = [NSString stringWithFormat:@"%@\n%@", pString, title];
|
||||
}
|
||||
} else if (flavorStr.EqualsLiteral(kURLDataMime)) {
|
||||
pString = GetStringForType(item, (const NSString*)kUTTypeURL);
|
||||
} else if (flavorStr.EqualsLiteral(kURLDescriptionMime)) {
|
||||
pString = GetTitleForURL(item);
|
||||
} else if (flavorStr.EqualsLiteral(kRTFMime)) {
|
||||
pString = GetStringForType(item, (const NSString*)kUTTypeRTF);
|
||||
}
|
||||
if (pString) {
|
||||
NSData* stringData;
|
||||
if (flavorStr.EqualsLiteral(kRTFMime)) {
|
||||
stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
|
||||
} else {
|
||||
stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
|
||||
}
|
||||
unsigned int dataLength = [stringData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
[stringData getBytes:clipboardDataPtr];
|
||||
|
||||
// The DOM only wants LF, so convert from MacOS line endings to DOM line endings.
|
||||
int32_t signedDataLength = dataLength;
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength);
|
||||
dataLength = signedDataLength;
|
||||
|
||||
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
||||
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
|
||||
if ((dataLength > 2) &&
|
||||
((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
|
||||
(clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
||||
dataLength -= sizeof(char16_t);
|
||||
clipboardDataPtrNoBOM += 1;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
|
||||
free(clipboardDataPtr);
|
||||
break;
|
||||
}
|
||||
|
||||
// We have never supported this on Mac OS X, we should someday. Normally dragging images
|
||||
// in is accomplished with a file path drag instead of the image data itself.
|
||||
/*
|
||||
if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) {
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
*_retval = false;
|
||||
|
||||
if (!globalDragPboard)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsDependentCString dataFlavor(aDataFlavor);
|
||||
|
||||
// first see if we have data for this in our cached transferable
|
||||
if (mDataItems) {
|
||||
uint32_t dataItemsCount;
|
||||
mDataItems->GetLength(&dataItemsCount);
|
||||
for (unsigned int i = 0; i < dataItemsCount; i++) {
|
||||
nsCOMPtr<nsITransferable> currentTransferable = do_QueryElementAt(mDataItems, i);
|
||||
if (!currentTransferable)
|
||||
continue;
|
||||
|
||||
nsCOMPtr<nsIArray> flavorList;
|
||||
nsresult rv = currentTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
uint32_t flavorCount;
|
||||
flavorList->GetLength(&flavorCount);
|
||||
for (uint32_t j = 0; j < flavorCount; j++) {
|
||||
nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, j);
|
||||
if (!currentFlavor)
|
||||
continue;
|
||||
nsXPIDLCString flavorStr;
|
||||
currentFlavor->ToString(getter_Copies(flavorStr));
|
||||
if (dataFlavor.Equals(flavorStr)) {
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const NSString* type = nil;
|
||||
bool allowFileURL = false;
|
||||
if (dataFlavor.EqualsLiteral(kFileMime)) {
|
||||
type = (const NSString*)kUTTypeFileURL;
|
||||
allowFileURL = true;
|
||||
} else if (dataFlavor.EqualsLiteral(kUnicodeMime)) {
|
||||
type = (const NSString*)kUTTypeUTF8PlainText;
|
||||
} else if (dataFlavor.EqualsLiteral(kHTMLMime)) {
|
||||
type = (const NSString*)kUTTypeHTML;
|
||||
} else if (dataFlavor.EqualsLiteral(kURLMime) ||
|
||||
dataFlavor.EqualsLiteral(kURLDataMime)) {
|
||||
type = (const NSString*)kUTTypeURL;
|
||||
} else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) {
|
||||
type = (const NSString*)kUTTypeURLName;
|
||||
} else if (dataFlavor.EqualsLiteral(kRTFMime)) {
|
||||
type = (const NSString*)kUTTypeRTF;
|
||||
} else if (dataFlavor.EqualsLiteral(kCustomTypesMime)) {
|
||||
type = (const NSString*)kCustomTypesPboardType;
|
||||
}
|
||||
|
||||
NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
|
||||
if (availableType && IsValidType(availableType, allowFileURL)) {
|
||||
*_retval = true;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDragService::GetNumDropItems(uint32_t* aNumItems)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
*aNumItems = 0;
|
||||
|
||||
// first check to see if we have a number of items cached
|
||||
if (mDataItems) {
|
||||
mDataItems->GetLength(aNumItems);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NSArray* droppedItems = [globalDragPboard pasteboardItems];
|
||||
if (droppedItems) {
|
||||
*aNumItems = [droppedItems count];
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDragService::EndDragSession(bool aDoneDrag)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (mNativeDragView) {
|
||||
[mNativeDragView release];
|
||||
mNativeDragView = nil;
|
||||
}
|
||||
if (mNativeDragEvent) {
|
||||
[mNativeDragEvent release];
|
||||
mNativeDragEvent = nil;
|
||||
}
|
||||
|
||||
mUserCancelled = gUserCancelledDrag;
|
||||
|
||||
nsresult rv = nsBaseDragService::EndDragSession(aDoneDrag);
|
||||
mDataItems = nullptr;
|
||||
return rv;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsFilePicker_h_
|
||||
#define nsFilePicker_h_
|
||||
|
||||
#include "nsBaseFilePicker.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsILocalFileMac;
|
||||
@class NSArray;
|
||||
|
||||
class nsFilePicker : public nsBaseFilePicker
|
||||
{
|
||||
public:
|
||||
nsFilePicker();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIFilePicker (less what's in nsBaseFilePicker)
|
||||
NS_IMETHOD GetDefaultString(nsAString& aDefaultString) override;
|
||||
NS_IMETHOD SetDefaultString(const nsAString& aDefaultString) override;
|
||||
NS_IMETHOD GetDefaultExtension(nsAString& aDefaultExtension) override;
|
||||
NS_IMETHOD GetFilterIndex(int32_t *aFilterIndex) override;
|
||||
NS_IMETHOD SetFilterIndex(int32_t aFilterIndex) override;
|
||||
NS_IMETHOD SetDefaultExtension(const nsAString& aDefaultExtension) override;
|
||||
NS_IMETHOD GetFile(nsIFile * *aFile) override;
|
||||
NS_IMETHOD GetFileURL(nsIURI * *aFileURL) override;
|
||||
NS_IMETHOD GetFiles(nsISimpleEnumerator **aFiles) override;
|
||||
NS_IMETHOD Show(int16_t *_retval) override;
|
||||
NS_IMETHOD AppendFilter(const nsAString& aTitle, const nsAString& aFilter) override;
|
||||
|
||||
/**
|
||||
* Returns the current filter list in the format used by Cocoa's NSSavePanel
|
||||
* and NSOpenPanel.
|
||||
* Returns nil if no filter currently apply.
|
||||
*/
|
||||
NSArray* GetFilterList();
|
||||
|
||||
protected:
|
||||
virtual ~nsFilePicker();
|
||||
|
||||
virtual void InitNative(nsIWidget *aParent, const nsAString& aTitle) override;
|
||||
|
||||
// actual implementations of get/put dialogs using NSOpenPanel & NSSavePanel
|
||||
// aFile is an existing but unspecified file. These functions must specify it.
|
||||
//
|
||||
// will return |returnCancel| or |returnOK| as result.
|
||||
int16_t GetLocalFiles(const nsString& inTitle, bool inAllowMultiple, nsCOMArray<nsIFile>& outFiles);
|
||||
int16_t GetLocalFolder(const nsString& inTitle, nsIFile** outFile);
|
||||
int16_t PutLocalFile(const nsString& inTitle, const nsString& inDefaultName, nsIFile** outFile);
|
||||
|
||||
void SetDialogTitle(const nsString& inTitle, id aDialog);
|
||||
NSString *PanelDefaultDirectory();
|
||||
NSView* GetAccessoryView();
|
||||
|
||||
nsString mTitle;
|
||||
nsCOMArray<nsIFile> mFiles;
|
||||
nsString mDefault;
|
||||
|
||||
nsTArray<nsString> mFilters;
|
||||
nsTArray<nsString> mTitles;
|
||||
|
||||
int32_t mSelectedTypeIndex;
|
||||
};
|
||||
|
||||
#endif // nsFilePicker_h_
|
||||
@@ -1,676 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "nsFilePicker.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
// This must be included last:
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
const float kAccessoryViewPadding = 5;
|
||||
const int kSaveTypeControlTag = 1;
|
||||
|
||||
static bool gCallSecretHiddenFileAPI = false;
|
||||
const char kShowHiddenFilesPref[] = "filepicker.showHiddenFiles";
|
||||
|
||||
/**
|
||||
* This class is an observer of NSPopUpButton selection change.
|
||||
*/
|
||||
@interface NSPopUpButtonObserver : NSObject
|
||||
{
|
||||
NSPopUpButton* mPopUpButton;
|
||||
NSOpenPanel* mOpenPanel;
|
||||
nsFilePicker* mFilePicker;
|
||||
}
|
||||
- (void) setPopUpButton:(NSPopUpButton*)aPopUpButton;
|
||||
- (void) setOpenPanel:(NSOpenPanel*)aOpenPanel;
|
||||
- (void) setFilePicker:(nsFilePicker*)aFilePicker;
|
||||
- (void) menuChangedItem:(NSNotification*)aSender;
|
||||
@end
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsFilePicker, nsIFilePicker)
|
||||
|
||||
// We never want to call the secret show hidden files API unless the pref
|
||||
// has been set. Once the pref has been set we always need to call it even
|
||||
// if it disappears so that we stop showing hidden files if a user deletes
|
||||
// the pref. If the secret API was used once and things worked out it should
|
||||
// continue working for subsequent calls so the user is at no more risk.
|
||||
static void SetShowHiddenFileState(NSSavePanel* panel)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
bool show = false;
|
||||
if (NS_SUCCEEDED(Preferences::GetBool(kShowHiddenFilesPref, &show))) {
|
||||
gCallSecretHiddenFileAPI = true;
|
||||
}
|
||||
|
||||
if (gCallSecretHiddenFileAPI) {
|
||||
// invoke a method to get a Cocoa-internal nav view
|
||||
SEL navViewSelector = @selector(_navView);
|
||||
NSMethodSignature* navViewSignature = [panel methodSignatureForSelector:navViewSelector];
|
||||
if (!navViewSignature)
|
||||
return;
|
||||
NSInvocation* navViewInvocation = [NSInvocation invocationWithMethodSignature:navViewSignature];
|
||||
[navViewInvocation setSelector:navViewSelector];
|
||||
[navViewInvocation setTarget:panel];
|
||||
[navViewInvocation invoke];
|
||||
|
||||
// get the returned nav view
|
||||
id navView = nil;
|
||||
[navViewInvocation getReturnValue:&navView];
|
||||
|
||||
// invoke the secret show hidden file state method on the nav view
|
||||
SEL showHiddenFilesSelector = @selector(setShowsHiddenFiles:);
|
||||
NSMethodSignature* showHiddenFilesSignature = [navView methodSignatureForSelector:showHiddenFilesSelector];
|
||||
if (!showHiddenFilesSignature)
|
||||
return;
|
||||
NSInvocation* showHiddenFilesInvocation = [NSInvocation invocationWithMethodSignature:showHiddenFilesSignature];
|
||||
[showHiddenFilesInvocation setSelector:showHiddenFilesSelector];
|
||||
[showHiddenFilesInvocation setTarget:navView];
|
||||
[showHiddenFilesInvocation setArgument:&show atIndex:2];
|
||||
[showHiddenFilesInvocation invoke];
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
nsFilePicker::nsFilePicker()
|
||||
: mSelectedTypeIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsFilePicker::~nsFilePicker()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFilePicker::InitNative(nsIWidget *aParent, const nsAString& aTitle)
|
||||
{
|
||||
mTitle = aTitle;
|
||||
}
|
||||
|
||||
NSView* nsFilePicker::GetAccessoryView()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
NSView* accessoryView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease];
|
||||
|
||||
// Set a label's default value.
|
||||
NSString* label = @"Format:";
|
||||
|
||||
// Try to get the localized string.
|
||||
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
nsresult rv = sbs->CreateBundle("chrome://global/locale/filepicker.properties", getter_AddRefs(bundle));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsXPIDLString locaLabel;
|
||||
bundle->GetStringFromName(u"formatLabel", getter_Copies(locaLabel));
|
||||
if (locaLabel) {
|
||||
label = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get())
|
||||
length:locaLabel.Length()];
|
||||
}
|
||||
}
|
||||
|
||||
// set up label text field
|
||||
NSTextField* textField = [[[NSTextField alloc] init] autorelease];
|
||||
[textField setEditable:NO];
|
||||
[textField setSelectable:NO];
|
||||
[textField setDrawsBackground:NO];
|
||||
[textField setBezeled:NO];
|
||||
[textField setBordered:NO];
|
||||
[textField setFont:[NSFont labelFontOfSize:13.0]];
|
||||
[textField setStringValue:label];
|
||||
[textField setTag:0];
|
||||
[textField sizeToFit];
|
||||
|
||||
// set up popup button
|
||||
NSPopUpButton* popupButton = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0) pullsDown:NO] autorelease];
|
||||
uint32_t numMenuItems = mTitles.Length();
|
||||
for (uint32_t i = 0; i < numMenuItems; i++) {
|
||||
const nsString& currentTitle = mTitles[i];
|
||||
NSString *titleString;
|
||||
if (currentTitle.IsEmpty()) {
|
||||
const nsString& currentFilter = mFilters[i];
|
||||
titleString = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentFilter.get())
|
||||
length:currentFilter.Length()];
|
||||
}
|
||||
else {
|
||||
titleString = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentTitle.get())
|
||||
length:currentTitle.Length()];
|
||||
}
|
||||
[popupButton addItemWithTitle:titleString];
|
||||
[titleString release];
|
||||
}
|
||||
if (mSelectedTypeIndex >= 0 && (uint32_t)mSelectedTypeIndex < numMenuItems)
|
||||
[popupButton selectItemAtIndex:mSelectedTypeIndex];
|
||||
[popupButton setTag:kSaveTypeControlTag];
|
||||
[popupButton sizeToFit]; // we have to do sizeToFit to get the height calculated for us
|
||||
// This is just a default width that works well, doesn't truncate the vast majority of
|
||||
// things that might end up in the menu.
|
||||
[popupButton setFrameSize:NSMakeSize(180, [popupButton frame].size.height)];
|
||||
|
||||
// position everything based on control sizes with kAccessoryViewPadding pix padding
|
||||
// on each side kAccessoryViewPadding pix horizontal padding between controls
|
||||
float greatestHeight = [textField frame].size.height;
|
||||
if ([popupButton frame].size.height > greatestHeight)
|
||||
greatestHeight = [popupButton frame].size.height;
|
||||
float totalViewHeight = greatestHeight + kAccessoryViewPadding * 2;
|
||||
float totalViewWidth = [textField frame].size.width + [popupButton frame].size.width + kAccessoryViewPadding * 3;
|
||||
[accessoryView setFrameSize:NSMakeSize(totalViewWidth, totalViewHeight)];
|
||||
|
||||
float textFieldOriginY = ((greatestHeight - [textField frame].size.height) / 2 + 1) + kAccessoryViewPadding;
|
||||
[textField setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)];
|
||||
|
||||
float popupOriginX = [textField frame].size.width + kAccessoryViewPadding * 2;
|
||||
float popupOriginY = ((greatestHeight - [popupButton frame].size.height) / 2) + kAccessoryViewPadding;
|
||||
[popupButton setFrameOrigin:NSMakePoint(popupOriginX, popupOriginY)];
|
||||
|
||||
[accessoryView addSubview:textField];
|
||||
[accessoryView addSubview:popupButton];
|
||||
return accessoryView;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
// Display the file dialog
|
||||
NS_IMETHODIMP nsFilePicker::Show(int16_t *retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(retval);
|
||||
|
||||
*retval = returnCancel;
|
||||
|
||||
int16_t userClicksOK = returnCancel;
|
||||
|
||||
// Random questions from DHH:
|
||||
//
|
||||
// Why do we pass mTitle, mDefault to the functions? Can GetLocalFile. PutLocalFile,
|
||||
// and GetLocalFolder get called someplace else? It generates a bunch of warnings
|
||||
// as it is right now.
|
||||
//
|
||||
// I think we could easily combine GetLocalFile and GetLocalFolder together, just
|
||||
// setting panel pick options based on mMode. I didn't do it here b/c I wanted to
|
||||
// make this look as much like Carbon nsFilePicker as possible.
|
||||
|
||||
mFiles.Clear();
|
||||
nsCOMPtr<nsIFile> theFile;
|
||||
|
||||
switch (mMode)
|
||||
{
|
||||
case modeOpen:
|
||||
userClicksOK = GetLocalFiles(mTitle, false, mFiles);
|
||||
break;
|
||||
|
||||
case modeOpenMultiple:
|
||||
userClicksOK = GetLocalFiles(mTitle, true, mFiles);
|
||||
break;
|
||||
|
||||
case modeSave:
|
||||
userClicksOK = PutLocalFile(mTitle, mDefault, getter_AddRefs(theFile));
|
||||
break;
|
||||
|
||||
case modeGetFolder:
|
||||
userClicksOK = GetLocalFolder(mTitle, getter_AddRefs(theFile));
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_ERROR("Unknown file picker mode");
|
||||
break;
|
||||
}
|
||||
|
||||
if (theFile)
|
||||
mFiles.AppendObject(theFile);
|
||||
|
||||
*retval = userClicksOK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static
|
||||
void UpdatePanelFileTypes(NSOpenPanel* aPanel, NSArray* aFilters)
|
||||
{
|
||||
// If we show all file types, also "expose" bundles' contents.
|
||||
[aPanel setTreatsFilePackagesAsDirectories:!aFilters];
|
||||
|
||||
[aPanel setAllowedFileTypes:aFilters];
|
||||
}
|
||||
|
||||
@implementation NSPopUpButtonObserver
|
||||
- (void) setPopUpButton:(NSPopUpButton*)aPopUpButton
|
||||
{
|
||||
mPopUpButton = aPopUpButton;
|
||||
}
|
||||
|
||||
- (void) setOpenPanel:(NSOpenPanel*)aOpenPanel
|
||||
{
|
||||
mOpenPanel = aOpenPanel;
|
||||
}
|
||||
|
||||
- (void) setFilePicker:(nsFilePicker*)aFilePicker
|
||||
{
|
||||
mFilePicker = aFilePicker;
|
||||
}
|
||||
|
||||
- (void) menuChangedItem:(NSNotification *)aSender
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
int32_t selectedItem = [mPopUpButton indexOfSelectedItem];
|
||||
if (selectedItem < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFilePicker->SetFilterIndex(selectedItem);
|
||||
UpdatePanelFileTypes(mOpenPanel, mFilePicker->GetFilterList());
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN();
|
||||
}
|
||||
@end
|
||||
|
||||
// Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in the dialog.
|
||||
int16_t
|
||||
nsFilePicker::GetLocalFiles(const nsString& inTitle, bool inAllowMultiple, nsCOMArray<nsIFile>& outFiles)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
int16_t retVal = (int16_t)returnCancel;
|
||||
NSOpenPanel *thePanel = [NSOpenPanel openPanel];
|
||||
|
||||
SetShowHiddenFileState(thePanel);
|
||||
|
||||
// Set the options for how the get file dialog will appear
|
||||
SetDialogTitle(inTitle, thePanel);
|
||||
[thePanel setAllowsMultipleSelection:inAllowMultiple];
|
||||
[thePanel setCanSelectHiddenExtension:YES];
|
||||
[thePanel setCanChooseDirectories:NO];
|
||||
[thePanel setCanChooseFiles:YES];
|
||||
[thePanel setResolvesAliases:YES]; //this is default - probably doesn't need to be set
|
||||
|
||||
// Get filters
|
||||
// filters may be null, if we should allow all file types.
|
||||
NSArray *filters = GetFilterList();
|
||||
|
||||
// set up default directory
|
||||
NSString *theDir = PanelDefaultDirectory();
|
||||
|
||||
// if this is the "Choose application..." dialog, and no other start
|
||||
// dir has been set, then use the Applications folder.
|
||||
if (!theDir) {
|
||||
if (filters && [filters count] == 1 &&
|
||||
[(NSString *)[filters objectAtIndex:0] isEqualToString:@"app"])
|
||||
theDir = @"/Applications/";
|
||||
else
|
||||
theDir = @"";
|
||||
}
|
||||
|
||||
if (theDir) {
|
||||
[thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
|
||||
}
|
||||
|
||||
int result;
|
||||
nsCocoaUtils::PrepareForNativeAppModalDialog();
|
||||
if (mFilters.Length() > 1) {
|
||||
// [NSURL initWithString:] (below) throws an exception if URLString is nil.
|
||||
|
||||
NSPopUpButtonObserver* observer = [[NSPopUpButtonObserver alloc] init];
|
||||
|
||||
NSView* accessoryView = GetAccessoryView();
|
||||
[thePanel setAccessoryView:accessoryView];
|
||||
|
||||
[observer setPopUpButton:[accessoryView viewWithTag:kSaveTypeControlTag]];
|
||||
[observer setOpenPanel:thePanel];
|
||||
[observer setFilePicker:this];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:observer
|
||||
selector:@selector(menuChangedItem:)
|
||||
name:NSMenuWillSendActionNotification object:nil];
|
||||
|
||||
UpdatePanelFileTypes(thePanel, filters);
|
||||
result = [thePanel runModal];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:observer];
|
||||
[observer release];
|
||||
} else {
|
||||
// If we show all file types, also "expose" bundles' contents.
|
||||
if (!filters) {
|
||||
[thePanel setTreatsFilePackagesAsDirectories:YES];
|
||||
}
|
||||
[thePanel setAllowedFileTypes:filters];
|
||||
result = [thePanel runModal];
|
||||
}
|
||||
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
||||
|
||||
if (result == NSFileHandlingPanelCancelButton)
|
||||
return retVal;
|
||||
|
||||
// Converts data from a NSArray of NSURL to the returned format.
|
||||
// We should be careful to not call [thePanel URLs] more than once given that
|
||||
// it creates a new array each time.
|
||||
// We are using Fast Enumeration, thus the NSURL array is created once then
|
||||
// iterated.
|
||||
for (NSURL* url in [thePanel URLs]) {
|
||||
if (!url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
|
||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
|
||||
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)url))) {
|
||||
outFiles.AppendObject(localFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (outFiles.Count() > 0)
|
||||
retVal = returnOK;
|
||||
|
||||
return retVal;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
|
||||
}
|
||||
|
||||
// Use OpenPanel to do a GetFolder. Returns |returnOK| if the user presses OK in the dialog.
|
||||
int16_t
|
||||
nsFilePicker::GetLocalFolder(const nsString& inTitle, nsIFile** outFile)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
|
||||
|
||||
int16_t retVal = (int16_t)returnCancel;
|
||||
NSOpenPanel *thePanel = [NSOpenPanel openPanel];
|
||||
|
||||
SetShowHiddenFileState(thePanel);
|
||||
|
||||
// Set the options for how the get file dialog will appear
|
||||
SetDialogTitle(inTitle, thePanel);
|
||||
[thePanel setAllowsMultipleSelection:NO]; //this is default -probably doesn't need to be set
|
||||
[thePanel setCanSelectHiddenExtension:YES];
|
||||
[thePanel setCanChooseDirectories:YES];
|
||||
[thePanel setCanChooseFiles:NO];
|
||||
[thePanel setResolvesAliases:YES]; //this is default - probably doesn't need to be set
|
||||
[thePanel setCanCreateDirectories:YES];
|
||||
|
||||
// packages != folders
|
||||
[thePanel setTreatsFilePackagesAsDirectories:NO];
|
||||
|
||||
// set up default directory
|
||||
NSString *theDir = PanelDefaultDirectory();
|
||||
if (theDir) {
|
||||
[thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
|
||||
}
|
||||
nsCocoaUtils::PrepareForNativeAppModalDialog();
|
||||
int result = [thePanel runModal];
|
||||
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
||||
|
||||
if (result == NSFileHandlingPanelCancelButton)
|
||||
return retVal;
|
||||
|
||||
// get the path for the folder (we allow just 1, so that's all we get)
|
||||
NSURL *theURL = [[thePanel URLs] objectAtIndex:0];
|
||||
if (theURL) {
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
|
||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
|
||||
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)theURL))) {
|
||||
*outFile = localFile;
|
||||
NS_ADDREF(*outFile);
|
||||
retVal = returnOK;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
|
||||
}
|
||||
|
||||
// Returns |returnOK| if the user presses OK in the dialog.
|
||||
int16_t
|
||||
nsFilePicker::PutLocalFile(const nsString& inTitle, const nsString& inDefaultName, nsIFile** outFile)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
|
||||
|
||||
int16_t retVal = returnCancel;
|
||||
NSSavePanel *thePanel = [NSSavePanel savePanel];
|
||||
|
||||
SetShowHiddenFileState(thePanel);
|
||||
|
||||
SetDialogTitle(inTitle, thePanel);
|
||||
|
||||
// set up accessory view for file format options
|
||||
NSView* accessoryView = GetAccessoryView();
|
||||
[thePanel setAccessoryView:accessoryView];
|
||||
|
||||
// set up default file name
|
||||
NSString* defaultFilename = [NSString stringWithCharacters:(const unichar*)inDefaultName.get() length:inDefaultName.Length()];
|
||||
|
||||
// set up allowed types; this prevents the extension from being selected
|
||||
// use the UTI for the file type to allow alternate extensions (e.g., jpg vs. jpeg)
|
||||
NSString* extension = defaultFilename.pathExtension;
|
||||
if (extension.length != 0) {
|
||||
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)extension, NULL);
|
||||
|
||||
if (type) {
|
||||
thePanel.allowedFileTypes = @[(NSString*)type];
|
||||
CFRelease(type);
|
||||
} else {
|
||||
// if there's no UTI for the file extension, use the extension itself.
|
||||
thePanel.allowedFileTypes = @[extension];
|
||||
}
|
||||
}
|
||||
// Allow users to change the extension.
|
||||
thePanel.allowsOtherFileTypes = YES;
|
||||
|
||||
// set up default directory
|
||||
NSString *theDir = PanelDefaultDirectory();
|
||||
if (theDir) {
|
||||
[thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
|
||||
}
|
||||
|
||||
// load the panel
|
||||
nsCocoaUtils::PrepareForNativeAppModalDialog();
|
||||
[thePanel setNameFieldStringValue:defaultFilename];
|
||||
int result = [thePanel runModal];
|
||||
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
||||
if (result == NSFileHandlingPanelCancelButton)
|
||||
return retVal;
|
||||
|
||||
// get the save type
|
||||
NSPopUpButton* popupButton = [accessoryView viewWithTag:kSaveTypeControlTag];
|
||||
if (popupButton) {
|
||||
mSelectedTypeIndex = [popupButton indexOfSelectedItem];
|
||||
}
|
||||
|
||||
NSURL* fileURL = [thePanel URL];
|
||||
if (fileURL) {
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
|
||||
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
|
||||
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)fileURL))) {
|
||||
*outFile = localFile;
|
||||
NS_ADDREF(*outFile);
|
||||
// We tell if we are replacing or not by just looking to see if the file exists.
|
||||
// The user could not have hit OK and not meant to replace the file.
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
|
||||
retVal = returnReplace;
|
||||
else
|
||||
retVal = returnOK;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
|
||||
}
|
||||
|
||||
NSArray *
|
||||
nsFilePicker::GetFilterList()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
if (!mFilters.Length()) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (mFilters.Length() <= (uint32_t)mSelectedTypeIndex) {
|
||||
NS_WARNING("An out of range index has been selected. Using the first index instead.");
|
||||
mSelectedTypeIndex = 0;
|
||||
}
|
||||
|
||||
const nsString& filterWide = mFilters[mSelectedTypeIndex];
|
||||
if (!filterWide.Length()) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (filterWide.Equals(NS_LITERAL_STRING("*"))) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// The extensions in filterWide are in the format "*.ext" but are expected
|
||||
// in the format "ext" by NSOpenPanel. So we need to filter some characters.
|
||||
NSMutableString* filterString = [[[NSMutableString alloc] initWithString:
|
||||
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(filterWide.get())
|
||||
length:filterWide.Length()]] autorelease];
|
||||
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@". *"];
|
||||
NSRange range = [filterString rangeOfCharacterFromSet:set];
|
||||
while (range.length) {
|
||||
[filterString replaceCharactersInRange:range withString:@""];
|
||||
range = [filterString rangeOfCharacterFromSet:set];
|
||||
}
|
||||
|
||||
return [[[NSArray alloc] initWithArray:
|
||||
[filterString componentsSeparatedByString:@";"]] autorelease];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
// Sets the dialog title to whatever it should be. If it fails, eh,
|
||||
// the OS will provide a sensible default.
|
||||
void
|
||||
nsFilePicker::SetDialogTitle(const nsString& inTitle, id aPanel)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
[aPanel setTitle:[NSString stringWithCharacters:(const unichar*)inTitle.get() length:inTitle.Length()]];
|
||||
|
||||
if (!mOkButtonLabel.IsEmpty()) {
|
||||
[aPanel setPrompt:[NSString stringWithCharacters:(const unichar*)mOkButtonLabel.get() length:mOkButtonLabel.Length()]];
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
// Converts path from an nsIFile into a NSString path
|
||||
// If it fails, returns an empty string.
|
||||
NSString *
|
||||
nsFilePicker::PanelDefaultDirectory()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
NSString *directory = nil;
|
||||
if (mDisplayDirectory) {
|
||||
nsAutoString pathStr;
|
||||
mDisplayDirectory->GetPath(pathStr);
|
||||
directory = [[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get())
|
||||
length:pathStr.Length()] autorelease];
|
||||
}
|
||||
return directory;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetFile(nsIFile **aFile)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFile);
|
||||
*aFile = nullptr;
|
||||
|
||||
// just return the first file
|
||||
if (mFiles.Count() > 0) {
|
||||
*aFile = mFiles.ObjectAt(0);
|
||||
NS_IF_ADDREF(*aFile);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetFileURL(nsIURI **aFileURL)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFileURL);
|
||||
*aFileURL = nullptr;
|
||||
|
||||
if (mFiles.Count() == 0)
|
||||
return NS_OK;
|
||||
|
||||
return NS_NewFileURI(aFileURL, mFiles.ObjectAt(0));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
|
||||
{
|
||||
return NS_NewArrayEnumerator(aFiles, mFiles);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString)
|
||||
{
|
||||
mDefault = aString;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// The default extension to use for files
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension)
|
||||
{
|
||||
aExtension.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Append an entry to the filters array
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
|
||||
{
|
||||
// "..apps" has to be translated with native executable extensions.
|
||||
if (aFilter.EqualsLiteral("..apps")) {
|
||||
mFilters.AppendElement(NS_LITERAL_STRING("*.app"));
|
||||
} else {
|
||||
mFilters.AppendElement(aFilter);
|
||||
}
|
||||
mTitles.AppendElement(aTitle);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get the filter index - do we still need this?
|
||||
NS_IMETHODIMP nsFilePicker::GetFilterIndex(int32_t *aFilterIndex)
|
||||
{
|
||||
*aFilterIndex = mSelectedTypeIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Set the filter index - do we still need this?
|
||||
NS_IMETHODIMP nsFilePicker::SetFilterIndex(int32_t aFilterIndex)
|
||||
{
|
||||
mSelectedTypeIndex = aFilterIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsIdleServiceX_h_
|
||||
#define nsIdleServiceX_h_
|
||||
|
||||
#include "nsIdleService.h"
|
||||
|
||||
class nsIdleServiceX : public nsIdleService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
bool PollIdleTime(uint32_t* aIdleTime) override;
|
||||
|
||||
static already_AddRefed<nsIdleServiceX> GetInstance()
|
||||
{
|
||||
RefPtr<nsIdleService> idleService = nsIdleService::GetInstance();
|
||||
if (!idleService) {
|
||||
idleService = new nsIdleServiceX();
|
||||
}
|
||||
|
||||
return idleService.forget().downcast<nsIdleServiceX>();
|
||||
}
|
||||
|
||||
protected:
|
||||
nsIdleServiceX() { }
|
||||
virtual ~nsIdleServiceX() { }
|
||||
bool UsePollMode() override;
|
||||
};
|
||||
|
||||
#endif // nsIdleServiceX_h_
|
||||
@@ -1,77 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIdleServiceX.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(nsIdleServiceX, nsIdleService)
|
||||
|
||||
bool
|
||||
nsIdleServiceX::PollIdleTime(uint32_t *aIdleTime)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
kern_return_t rval;
|
||||
mach_port_t masterPort;
|
||||
|
||||
rval = IOMasterPort(kIOMasterPortDefault, &masterPort);
|
||||
if (rval != KERN_SUCCESS)
|
||||
return false;
|
||||
|
||||
io_iterator_t hidItr;
|
||||
rval = IOServiceGetMatchingServices(masterPort,
|
||||
IOServiceMatching("IOHIDSystem"),
|
||||
&hidItr);
|
||||
|
||||
if (rval != KERN_SUCCESS)
|
||||
return false;
|
||||
NS_ASSERTION(hidItr, "Our iterator is null, but it ought not to be!");
|
||||
|
||||
io_registry_entry_t entry = IOIteratorNext(hidItr);
|
||||
NS_ASSERTION(entry, "Our IO Registry Entry is null, but it shouldn't be!");
|
||||
|
||||
IOObjectRelease(hidItr);
|
||||
|
||||
NSMutableDictionary *hidProps;
|
||||
rval = IORegistryEntryCreateCFProperties(entry,
|
||||
(CFMutableDictionaryRef*)&hidProps,
|
||||
kCFAllocatorDefault, 0);
|
||||
if (rval != KERN_SUCCESS)
|
||||
return false;
|
||||
NS_ASSERTION(hidProps, "HIDProperties is null, but no error was returned.");
|
||||
[hidProps autorelease];
|
||||
|
||||
id idleObj = [hidProps objectForKey:@"HIDIdleTime"];
|
||||
NS_ASSERTION([idleObj isKindOfClass: [NSData class]] ||
|
||||
[idleObj isKindOfClass: [NSNumber class]],
|
||||
"What we got for the idle object is not what we expect!");
|
||||
|
||||
uint64_t time;
|
||||
if ([idleObj isKindOfClass: [NSData class]])
|
||||
[idleObj getBytes: &time];
|
||||
else
|
||||
time = [idleObj unsignedLongLongValue];
|
||||
|
||||
IOObjectRelease(entry);
|
||||
|
||||
// convert to ms from ns
|
||||
time /= 1000000;
|
||||
if (time > UINT32_MAX) // Overflow will occur
|
||||
return false;
|
||||
|
||||
*aIdleTime = static_cast<uint32_t>(time);
|
||||
|
||||
return true;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
|
||||
}
|
||||
|
||||
bool
|
||||
nsIdleServiceX::UsePollMode()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsLookAndFeel_h_
|
||||
#define nsLookAndFeel_h_
|
||||
#include "nsXPLookAndFeel.h"
|
||||
|
||||
class nsLookAndFeel: public nsXPLookAndFeel {
|
||||
public:
|
||||
nsLookAndFeel();
|
||||
virtual ~nsLookAndFeel();
|
||||
|
||||
virtual nsresult NativeGetColor(ColorID aID, nscolor &aResult);
|
||||
virtual nsresult GetIntImpl(IntID aID, int32_t &aResult);
|
||||
virtual nsresult GetFloatImpl(FloatID aID, float &aResult);
|
||||
virtual bool GetFontImpl(FontID aID, nsString& aFontName,
|
||||
gfxFontStyle& aFontStyle,
|
||||
float aDevPixPerCSSPixel);
|
||||
virtual char16_t GetPasswordCharacterImpl()
|
||||
{
|
||||
// unicode value for the bullet character, used for password textfields.
|
||||
return 0x2022;
|
||||
}
|
||||
|
||||
static bool UseOverlayScrollbars();
|
||||
|
||||
virtual nsTArray<LookAndFeelInt> GetIntCacheImpl();
|
||||
virtual void SetIntCacheImpl(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache);
|
||||
|
||||
virtual void RefreshImpl();
|
||||
|
||||
protected:
|
||||
static bool SystemWantsOverlayScrollbars();
|
||||
static bool AllowOverlayScrollbarsOverlap();
|
||||
|
||||
private:
|
||||
int32_t mUseOverlayScrollbars;
|
||||
bool mUseOverlayScrollbarsCached;
|
||||
|
||||
int32_t mAllowOverlayScrollbarsOverlap;
|
||||
bool mAllowOverlayScrollbarsOverlapCached;
|
||||
};
|
||||
|
||||
#endif // nsLookAndFeel_h_
|
||||
@@ -1,584 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsLookAndFeel.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsNativeThemeColors.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsIContent.h"
|
||||
#include "gfxFont.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "gfxPlatformMac.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/widget/WidgetMessageUtils.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
// This must be included last:
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
enum {
|
||||
mozNSScrollerStyleLegacy = 0,
|
||||
mozNSScrollerStyleOverlay = 1
|
||||
};
|
||||
typedef NSInteger mozNSScrollerStyle;
|
||||
|
||||
@interface NSScroller(AvailableSinceLion)
|
||||
+ (mozNSScrollerStyle)preferredScrollerStyle;
|
||||
@end
|
||||
|
||||
nsLookAndFeel::nsLookAndFeel()
|
||||
: nsXPLookAndFeel()
|
||||
, mUseOverlayScrollbars(-1)
|
||||
, mUseOverlayScrollbarsCached(false)
|
||||
, mAllowOverlayScrollbarsOverlap(-1)
|
||||
, mAllowOverlayScrollbarsOverlapCached(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsLookAndFeel::~nsLookAndFeel()
|
||||
{
|
||||
}
|
||||
|
||||
static nscolor GetColorFromNSColor(NSColor* aColor)
|
||||
{
|
||||
NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
||||
return NS_RGB((unsigned int)([deviceColor redComponent] * 255.0),
|
||||
(unsigned int)([deviceColor greenComponent] * 255.0),
|
||||
(unsigned int)([deviceColor blueComponent] * 255.0));
|
||||
}
|
||||
|
||||
static nscolor GetColorFromNSColorWithAlpha(NSColor* aColor, float alpha)
|
||||
{
|
||||
NSColor* deviceColor = [aColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
|
||||
return NS_RGBA((unsigned int)([deviceColor redComponent] * 255.0),
|
||||
(unsigned int)([deviceColor greenComponent] * 255.0),
|
||||
(unsigned int)([deviceColor blueComponent] * 255.0),
|
||||
(unsigned int)(alpha * 255.0));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsresult res = NS_OK;
|
||||
|
||||
switch (aID) {
|
||||
case eColorID_WindowBackground:
|
||||
aColor = NS_RGB(0xff,0xff,0xff);
|
||||
break;
|
||||
case eColorID_WindowForeground:
|
||||
aColor = NS_RGB(0x00,0x00,0x00);
|
||||
break;
|
||||
case eColorID_WidgetBackground:
|
||||
aColor = NS_RGB(0xdd,0xdd,0xdd);
|
||||
break;
|
||||
case eColorID_WidgetForeground:
|
||||
aColor = NS_RGB(0x00,0x00,0x00);
|
||||
break;
|
||||
case eColorID_WidgetSelectBackground:
|
||||
aColor = NS_RGB(0x80,0x80,0x80);
|
||||
break;
|
||||
case eColorID_WidgetSelectForeground:
|
||||
aColor = NS_RGB(0x00,0x00,0x80);
|
||||
break;
|
||||
case eColorID_Widget3DHighlight:
|
||||
aColor = NS_RGB(0xa0,0xa0,0xa0);
|
||||
break;
|
||||
case eColorID_Widget3DShadow:
|
||||
aColor = NS_RGB(0x40,0x40,0x40);
|
||||
break;
|
||||
case eColorID_TextBackground:
|
||||
aColor = NS_RGB(0xff,0xff,0xff);
|
||||
break;
|
||||
case eColorID_TextForeground:
|
||||
aColor = NS_RGB(0x00,0x00,0x00);
|
||||
break;
|
||||
case eColorID_TextSelectBackground:
|
||||
aColor = GetColorFromNSColor([NSColor selectedTextBackgroundColor]);
|
||||
break;
|
||||
case eColorID_highlight: // CSS2 color
|
||||
aColor = GetColorFromNSColor([NSColor alternateSelectedControlColor]);
|
||||
break;
|
||||
case eColorID__moz_menuhover:
|
||||
aColor = GetColorFromNSColor([NSColor alternateSelectedControlColor]);
|
||||
break;
|
||||
case eColorID_TextSelectForeground:
|
||||
GetColor(eColorID_TextSelectBackground, aColor);
|
||||
if (aColor == 0x000000)
|
||||
aColor = NS_RGB(0xff,0xff,0xff);
|
||||
else
|
||||
aColor = NS_DONT_CHANGE_COLOR;
|
||||
break;
|
||||
case eColorID_highlighttext: // CSS2 color
|
||||
case eColorID__moz_menuhovertext:
|
||||
aColor = GetColorFromNSColor([NSColor alternateSelectedControlTextColor]);
|
||||
break;
|
||||
case eColorID_IMESelectedRawTextBackground:
|
||||
case eColorID_IMESelectedConvertedTextBackground:
|
||||
case eColorID_IMERawInputBackground:
|
||||
case eColorID_IMEConvertedTextBackground:
|
||||
aColor = NS_TRANSPARENT;
|
||||
break;
|
||||
case eColorID_IMESelectedRawTextForeground:
|
||||
case eColorID_IMESelectedConvertedTextForeground:
|
||||
case eColorID_IMERawInputForeground:
|
||||
case eColorID_IMEConvertedTextForeground:
|
||||
aColor = NS_SAME_AS_FOREGROUND_COLOR;
|
||||
break;
|
||||
case eColorID_IMERawInputUnderline:
|
||||
case eColorID_IMEConvertedTextUnderline:
|
||||
aColor = NS_40PERCENT_FOREGROUND_COLOR;
|
||||
break;
|
||||
case eColorID_IMESelectedRawTextUnderline:
|
||||
case eColorID_IMESelectedConvertedTextUnderline:
|
||||
aColor = NS_SAME_AS_FOREGROUND_COLOR;
|
||||
break;
|
||||
case eColorID_SpellCheckerUnderline:
|
||||
aColor = NS_RGB(0xff, 0, 0);
|
||||
break;
|
||||
|
||||
//
|
||||
// css2 system colors http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
|
||||
//
|
||||
// It's really hard to effectively map these to the Appearance Manager properly,
|
||||
// since they are modeled word for word after the win32 system colors and don't have any
|
||||
// real counterparts in the Mac world. I'm sure we'll be tweaking these for
|
||||
// years to come.
|
||||
//
|
||||
// Thanks to mpt26@student.canterbury.ac.nz for the hardcoded values that form the defaults
|
||||
// if querying the Appearance Manager fails ;)
|
||||
//
|
||||
case eColorID__moz_mac_buttonactivetext:
|
||||
case eColorID__moz_mac_defaultbuttontext:
|
||||
if (nsCocoaFeatures::OnYosemiteOrLater()) {
|
||||
aColor = NS_RGB(0xFF,0xFF,0xFF);
|
||||
break;
|
||||
}
|
||||
// Otherwise fall through and return the regular button text:
|
||||
|
||||
case eColorID_buttontext:
|
||||
case eColorID__moz_buttonhovertext:
|
||||
aColor = GetColorFromNSColor([NSColor controlTextColor]);
|
||||
break;
|
||||
case eColorID_captiontext:
|
||||
case eColorID_menutext:
|
||||
case eColorID_infotext:
|
||||
case eColorID__moz_menubartext:
|
||||
aColor = GetColorFromNSColor([NSColor textColor]);
|
||||
break;
|
||||
case eColorID_windowtext:
|
||||
aColor = GetColorFromNSColor([NSColor windowFrameTextColor]);
|
||||
break;
|
||||
case eColorID_activecaption:
|
||||
aColor = GetColorFromNSColor([NSColor gridColor]);
|
||||
break;
|
||||
case eColorID_activeborder:
|
||||
aColor = GetColorFromNSColor([NSColor keyboardFocusIndicatorColor]);
|
||||
break;
|
||||
case eColorID_appworkspace:
|
||||
aColor = NS_RGB(0xFF,0xFF,0xFF);
|
||||
break;
|
||||
case eColorID_background:
|
||||
aColor = NS_RGB(0x63,0x63,0xCE);
|
||||
break;
|
||||
case eColorID_buttonface:
|
||||
case eColorID__moz_buttonhoverface:
|
||||
aColor = NS_RGB(0xF0,0xF0,0xF0);
|
||||
break;
|
||||
case eColorID_buttonhighlight:
|
||||
aColor = NS_RGB(0xFF,0xFF,0xFF);
|
||||
break;
|
||||
case eColorID_buttonshadow:
|
||||
aColor = NS_RGB(0xDC,0xDC,0xDC);
|
||||
break;
|
||||
case eColorID_graytext:
|
||||
aColor = GetColorFromNSColor([NSColor disabledControlTextColor]);
|
||||
break;
|
||||
case eColorID_inactiveborder:
|
||||
aColor = GetColorFromNSColor([NSColor controlBackgroundColor]);
|
||||
break;
|
||||
case eColorID_inactivecaption:
|
||||
aColor = GetColorFromNSColor([NSColor controlBackgroundColor]);
|
||||
break;
|
||||
case eColorID_inactivecaptiontext:
|
||||
aColor = NS_RGB(0x45,0x45,0x45);
|
||||
break;
|
||||
case eColorID_scrollbar:
|
||||
aColor = GetColorFromNSColor([NSColor scrollBarColor]);
|
||||
break;
|
||||
case eColorID_threeddarkshadow:
|
||||
aColor = NS_RGB(0xDC,0xDC,0xDC);
|
||||
break;
|
||||
case eColorID_threedshadow:
|
||||
aColor = NS_RGB(0xE0,0xE0,0xE0);
|
||||
break;
|
||||
case eColorID_threedface:
|
||||
aColor = NS_RGB(0xF0,0xF0,0xF0);
|
||||
break;
|
||||
case eColorID_threedhighlight:
|
||||
aColor = GetColorFromNSColor([NSColor highlightColor]);
|
||||
break;
|
||||
case eColorID_threedlightshadow:
|
||||
aColor = NS_RGB(0xDA,0xDA,0xDA);
|
||||
break;
|
||||
case eColorID_menu:
|
||||
aColor = GetColorFromNSColor([NSColor alternateSelectedControlTextColor]);
|
||||
break;
|
||||
case eColorID_infobackground:
|
||||
aColor = NS_RGB(0xFF,0xFF,0xC7);
|
||||
break;
|
||||
case eColorID_windowframe:
|
||||
aColor = GetColorFromNSColor([NSColor gridColor]);
|
||||
break;
|
||||
case eColorID_window:
|
||||
case eColorID__moz_field:
|
||||
case eColorID__moz_combobox:
|
||||
aColor = NS_RGB(0xff,0xff,0xff);
|
||||
break;
|
||||
case eColorID__moz_fieldtext:
|
||||
case eColorID__moz_comboboxtext:
|
||||
aColor = GetColorFromNSColor([NSColor controlTextColor]);
|
||||
break;
|
||||
case eColorID__moz_dialog:
|
||||
aColor = GetColorFromNSColor([NSColor controlHighlightColor]);
|
||||
break;
|
||||
case eColorID__moz_dialogtext:
|
||||
case eColorID__moz_cellhighlighttext:
|
||||
case eColorID__moz_html_cellhighlighttext:
|
||||
aColor = GetColorFromNSColor([NSColor controlTextColor]);
|
||||
break;
|
||||
case eColorID__moz_dragtargetzone:
|
||||
aColor = GetColorFromNSColor([NSColor selectedControlColor]);
|
||||
break;
|
||||
case eColorID__moz_mac_chrome_active:
|
||||
case eColorID__moz_mac_chrome_inactive: {
|
||||
int grey = NativeGreyColorAsInt(toolbarFillGrey, (aID == eColorID__moz_mac_chrome_active));
|
||||
aColor = NS_RGB(grey, grey, grey);
|
||||
}
|
||||
break;
|
||||
case eColorID__moz_mac_focusring:
|
||||
aColor = GetColorFromNSColorWithAlpha([NSColor keyboardFocusIndicatorColor], 0.48);
|
||||
break;
|
||||
case eColorID__moz_mac_menushadow:
|
||||
aColor = NS_RGB(0xA3,0xA3,0xA3);
|
||||
break;
|
||||
case eColorID__moz_mac_menutextdisable:
|
||||
aColor = NS_RGB(0x98,0x98,0x98);
|
||||
break;
|
||||
case eColorID__moz_mac_menutextselect:
|
||||
aColor = GetColorFromNSColor([NSColor selectedMenuItemTextColor]);
|
||||
break;
|
||||
case eColorID__moz_mac_disabledtoolbartext:
|
||||
aColor = GetColorFromNSColor([NSColor disabledControlTextColor]);
|
||||
break;
|
||||
case eColorID__moz_mac_menuselect:
|
||||
aColor = GetColorFromNSColor([NSColor alternateSelectedControlColor]);
|
||||
break;
|
||||
case eColorID__moz_buttondefault:
|
||||
aColor = NS_RGB(0xDC,0xDC,0xDC);
|
||||
break;
|
||||
case eColorID__moz_cellhighlight:
|
||||
case eColorID__moz_html_cellhighlight:
|
||||
case eColorID__moz_mac_secondaryhighlight:
|
||||
// For inactive list selection
|
||||
aColor = GetColorFromNSColor([NSColor secondarySelectedControlColor]);
|
||||
break;
|
||||
case eColorID__moz_eventreerow:
|
||||
// Background color of even list rows.
|
||||
aColor = GetColorFromNSColor([[NSColor controlAlternatingRowBackgroundColors] objectAtIndex:0]);
|
||||
break;
|
||||
case eColorID__moz_oddtreerow:
|
||||
// Background color of odd list rows.
|
||||
aColor = GetColorFromNSColor([[NSColor controlAlternatingRowBackgroundColors] objectAtIndex:1]);
|
||||
break;
|
||||
case eColorID__moz_nativehyperlinktext:
|
||||
// There appears to be no available system defined color. HARDCODING to the appropriate color.
|
||||
aColor = NS_RGB(0x14,0x4F,0xAE);
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Someone asked nsILookAndFeel for a color I don't know about");
|
||||
aColor = NS_RGB(0xff,0xff,0xff);
|
||||
res = NS_ERROR_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsresult res = nsXPLookAndFeel::GetIntImpl(aID, aResult);
|
||||
if (NS_SUCCEEDED(res))
|
||||
return res;
|
||||
res = NS_OK;
|
||||
|
||||
switch (aID) {
|
||||
case eIntID_CaretBlinkTime:
|
||||
aResult = 567;
|
||||
break;
|
||||
case eIntID_CaretWidth:
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_ShowCaretDuringSelection:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_SelectTextfieldsOnKeyFocus:
|
||||
// Select textfield content when focused by kbd
|
||||
// used by EventStateManager::sTextfieldSelectModel
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_SubmenuDelay:
|
||||
aResult = 200;
|
||||
break;
|
||||
case eIntID_TooltipDelay:
|
||||
aResult = 500;
|
||||
break;
|
||||
case eIntID_MenusCanOverlapOSBar:
|
||||
// xul popups are not allowed to overlap the menubar.
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_SkipNavigatingDisabledMenuItem:
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_DragThresholdX:
|
||||
case eIntID_DragThresholdY:
|
||||
aResult = 4;
|
||||
break;
|
||||
case eIntID_ScrollArrowStyle:
|
||||
aResult = eScrollArrow_None;
|
||||
break;
|
||||
case eIntID_ScrollSliderStyle:
|
||||
aResult = eScrollThumbStyle_Proportional;
|
||||
break;
|
||||
case eIntID_UseOverlayScrollbars:
|
||||
if (!mUseOverlayScrollbarsCached) {
|
||||
mUseOverlayScrollbars = SystemWantsOverlayScrollbars() ? 1 : 0;
|
||||
mUseOverlayScrollbarsCached = true;
|
||||
}
|
||||
aResult = mUseOverlayScrollbars;
|
||||
break;
|
||||
case eIntID_AllowOverlayScrollbarsOverlap:
|
||||
if (!mAllowOverlayScrollbarsOverlapCached) {
|
||||
mAllowOverlayScrollbarsOverlap = AllowOverlayScrollbarsOverlap() ? 1 : 0;
|
||||
mAllowOverlayScrollbarsOverlapCached = true;
|
||||
}
|
||||
aResult = mAllowOverlayScrollbarsOverlap;
|
||||
break;
|
||||
case eIntID_ScrollbarDisplayOnMouseMove:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_ScrollbarFadeBeginDelay:
|
||||
aResult = 450;
|
||||
break;
|
||||
case eIntID_ScrollbarFadeDuration:
|
||||
aResult = 200;
|
||||
break;
|
||||
case eIntID_TreeOpenDelay:
|
||||
aResult = 1000;
|
||||
break;
|
||||
case eIntID_TreeCloseDelay:
|
||||
aResult = 1000;
|
||||
break;
|
||||
case eIntID_TreeLazyScrollDelay:
|
||||
aResult = 150;
|
||||
break;
|
||||
case eIntID_TreeScrollDelay:
|
||||
aResult = 100;
|
||||
break;
|
||||
case eIntID_TreeScrollLinesMax:
|
||||
aResult = 3;
|
||||
break;
|
||||
case eIntID_DWMCompositor:
|
||||
case eIntID_WindowsClassic:
|
||||
case eIntID_WindowsDefaultTheme:
|
||||
case eIntID_TouchEnabled:
|
||||
case eIntID_WindowsThemeIdentifier:
|
||||
case eIntID_OperatingSystemVersionIdentifier:
|
||||
aResult = 0;
|
||||
res = NS_ERROR_NOT_IMPLEMENTED;
|
||||
break;
|
||||
case eIntID_MacGraphiteTheme:
|
||||
aResult = [NSColor currentControlTint] == NSGraphiteControlTint;
|
||||
break;
|
||||
case eIntID_MacLionTheme:
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_MacYosemiteTheme:
|
||||
aResult = nsCocoaFeatures::OnYosemiteOrLater();
|
||||
break;
|
||||
case eIntID_AlertNotificationOrigin:
|
||||
aResult = NS_ALERT_TOP;
|
||||
break;
|
||||
case eIntID_TabFocusModel:
|
||||
aResult = [NSApp isFullKeyboardAccessEnabled] ?
|
||||
nsIContent::eTabFocus_any : nsIContent::eTabFocus_textControlsMask;
|
||||
break;
|
||||
case eIntID_ScrollToClick:
|
||||
{
|
||||
aResult = [[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"];
|
||||
}
|
||||
break;
|
||||
case eIntID_ChosenMenuItemsShouldBlink:
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_IMERawInputUnderlineStyle:
|
||||
case eIntID_IMEConvertedTextUnderlineStyle:
|
||||
case eIntID_IMESelectedRawTextUnderlineStyle:
|
||||
case eIntID_IMESelectedConvertedTextUnderline:
|
||||
aResult = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
|
||||
break;
|
||||
case eIntID_SpellCheckerUnderlineStyle:
|
||||
aResult = NS_STYLE_TEXT_DECORATION_STYLE_DOTTED;
|
||||
break;
|
||||
case eIntID_ScrollbarButtonAutoRepeatBehavior:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_SwipeAnimationEnabled:
|
||||
aResult = 0;
|
||||
if ([NSEvent respondsToSelector:@selector(
|
||||
isSwipeTrackingFromScrollEventsEnabled)]) {
|
||||
aResult = [NSEvent isSwipeTrackingFromScrollEventsEnabled] ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case eIntID_ColorPickerAvailable:
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_ContextMenuOffsetVertical:
|
||||
aResult = -6;
|
||||
break;
|
||||
case eIntID_ContextMenuOffsetHorizontal:
|
||||
aResult = 1;
|
||||
break;
|
||||
default:
|
||||
aResult = 0;
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
return res;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult)
|
||||
{
|
||||
nsresult res = nsXPLookAndFeel::GetFloatImpl(aID, aResult);
|
||||
if (NS_SUCCEEDED(res))
|
||||
return res;
|
||||
res = NS_OK;
|
||||
|
||||
switch (aID) {
|
||||
case eFloatID_IMEUnderlineRelativeSize:
|
||||
aResult = 2.0f;
|
||||
break;
|
||||
case eFloatID_SpellCheckerUnderlineRelativeSize:
|
||||
aResult = 2.0f;
|
||||
break;
|
||||
default:
|
||||
aResult = -1.0;
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool nsLookAndFeel::UseOverlayScrollbars()
|
||||
{
|
||||
return GetInt(eIntID_UseOverlayScrollbars) != 0;
|
||||
}
|
||||
|
||||
bool nsLookAndFeel::SystemWantsOverlayScrollbars()
|
||||
{
|
||||
return ([NSScroller respondsToSelector:@selector(preferredScrollerStyle)] &&
|
||||
[NSScroller preferredScrollerStyle] == mozNSScrollerStyleOverlay);
|
||||
}
|
||||
|
||||
bool nsLookAndFeel::AllowOverlayScrollbarsOverlap()
|
||||
{
|
||||
return (UseOverlayScrollbars());
|
||||
}
|
||||
|
||||
bool
|
||||
nsLookAndFeel::GetFontImpl(FontID aID, nsString &aFontName,
|
||||
gfxFontStyle &aFontStyle,
|
||||
float aDevPixPerCSSPixel)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
// hack for now
|
||||
if (aID == eFont_Window || aID == eFont_Document) {
|
||||
aFontStyle.style = NS_FONT_STYLE_NORMAL;
|
||||
aFontStyle.weight = NS_FONT_WEIGHT_NORMAL;
|
||||
aFontStyle.stretch = NS_FONT_STRETCH_NORMAL;
|
||||
aFontStyle.size = 14 * aDevPixPerCSSPixel;
|
||||
aFontStyle.systemFont = true;
|
||||
|
||||
aFontName.AssignLiteral("sans-serif");
|
||||
return true;
|
||||
}
|
||||
|
||||
gfxPlatformMac::LookupSystemFont(aID, aFontName, aFontStyle,
|
||||
aDevPixPerCSSPixel);
|
||||
|
||||
return true;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
|
||||
}
|
||||
|
||||
nsTArray<LookAndFeelInt>
|
||||
nsLookAndFeel::GetIntCacheImpl()
|
||||
{
|
||||
nsTArray<LookAndFeelInt> lookAndFeelIntCache =
|
||||
nsXPLookAndFeel::GetIntCacheImpl();
|
||||
|
||||
LookAndFeelInt useOverlayScrollbars;
|
||||
useOverlayScrollbars.id = eIntID_UseOverlayScrollbars;
|
||||
useOverlayScrollbars.value = GetInt(eIntID_UseOverlayScrollbars);
|
||||
lookAndFeelIntCache.AppendElement(useOverlayScrollbars);
|
||||
|
||||
LookAndFeelInt allowOverlayScrollbarsOverlap;
|
||||
allowOverlayScrollbarsOverlap.id = eIntID_AllowOverlayScrollbarsOverlap;
|
||||
allowOverlayScrollbarsOverlap.value = GetInt(eIntID_AllowOverlayScrollbarsOverlap);
|
||||
lookAndFeelIntCache.AppendElement(allowOverlayScrollbarsOverlap);
|
||||
|
||||
return lookAndFeelIntCache;
|
||||
}
|
||||
|
||||
void
|
||||
nsLookAndFeel::SetIntCacheImpl(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache)
|
||||
{
|
||||
for (auto entry : aLookAndFeelIntCache) {
|
||||
switch(entry.id) {
|
||||
case eIntID_UseOverlayScrollbars:
|
||||
mUseOverlayScrollbars = entry.value;
|
||||
mUseOverlayScrollbarsCached = true;
|
||||
break;
|
||||
case eIntID_AllowOverlayScrollbarsOverlap:
|
||||
mAllowOverlayScrollbarsOverlap = entry.value;
|
||||
mAllowOverlayScrollbarsOverlapCached = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsLookAndFeel::RefreshImpl()
|
||||
{
|
||||
// We should only clear the cache if we're in the main browser process.
|
||||
// Otherwise, we should wait for the parent to inform us of new values
|
||||
// to cache via LookAndFeel::SetIntCache.
|
||||
if (XRE_IsParentProcess()) {
|
||||
mUseOverlayScrollbarsCached = false;
|
||||
mAllowOverlayScrollbarsOverlapCached = false;
|
||||
}
|
||||
}
|
||||