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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||