2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: objc; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* 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/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-10-10 22:50:08 -07:00
|
|
|
#include "mozilla/Util.h"
|
|
|
|
|
2010-06-27 17:25:04 -07:00
|
|
|
#ifdef MOZ_LOGGING
|
|
|
|
#define FORCE_PR_LOG
|
|
|
|
#endif
|
|
|
|
#include "prlog.h"
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#include <unistd.h>
|
2011-08-11 10:42:23 -07:00
|
|
|
#include <math.h>
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsChildView.h"
|
2007-07-17 13:29:39 -07:00
|
|
|
#include "nsCocoaWindow.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-09-25 04:21:20 -07:00
|
|
|
#include "mozilla/MiscEvents.h"
|
2013-09-25 04:21:18 -07:00
|
|
|
#include "mozilla/MouseEvents.h"
|
2013-09-25 04:21:19 -07:00
|
|
|
#include "mozilla/TextEvents.h"
|
2013-09-25 04:21:16 -07:00
|
|
|
#include "mozilla/TouchEvents.h"
|
|
|
|
|
2008-02-20 15:47:05 -08:00
|
|
|
#include "nsObjCExceptions.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsToolkit.h"
|
|
|
|
#include "nsCRT.h"
|
|
|
|
|
2011-04-07 18:05:49 -07:00
|
|
|
#include "nsFontMetrics.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIRollupListener.h"
|
2013-01-04 19:12:24 -08:00
|
|
|
#include "nsViewManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIInterfaceRequestor.h"
|
2012-06-05 19:08:30 -07:00
|
|
|
#include "nsIFile.h"
|
2007-07-16 19:24:05 -07:00
|
|
|
#include "nsILocalFileMac.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsGfxCIID.h"
|
2009-06-17 20:39:22 -07:00
|
|
|
#include "nsIDOMSimpleGestureEvent.h"
|
2011-05-17 18:48:34 -07:00
|
|
|
#include "nsNPAPIPluginInstance.h"
|
2011-01-11 05:03:16 -08:00
|
|
|
#include "nsThemeConstants.h"
|
2012-08-15 11:52:42 -07:00
|
|
|
#include "nsIWidgetListener.h"
|
2012-10-17 12:50:06 -07:00
|
|
|
#include "nsIPresShell.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsDragService.h"
|
2009-03-17 19:04:01 -07:00
|
|
|
#include "nsClipboard.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsCursorManager.h"
|
|
|
|
#include "nsWindowMap.h"
|
2012-05-17 00:53:20 -07:00
|
|
|
#include "nsCocoaFeatures.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsCocoaUtils.h"
|
2008-10-29 22:36:01 -07:00
|
|
|
#include "nsMenuUtilsX.h"
|
2008-01-28 22:11:06 -08:00
|
|
|
#include "nsMenuBarX.h"
|
2010-06-09 17:56:17 -07:00
|
|
|
#ifdef __LP64__
|
|
|
|
#include "ComplexTextInputPanel.h"
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "gfxQuartzSurface.h"
|
2013-05-23 07:49:17 -07:00
|
|
|
#include "gfxUtils.h"
|
2009-11-09 17:00:36 -08:00
|
|
|
#include "nsRegion.h"
|
2010-04-27 15:29:29 -07:00
|
|
|
#include "Layers.h"
|
2013-05-09 14:02:50 -07:00
|
|
|
#include "ClientLayerManager.h"
|
2013-04-25 15:25:33 -07:00
|
|
|
#include "mozilla/layers/LayerManagerComposite.h"
|
2013-04-16 14:35:57 -07:00
|
|
|
#include "GLTextureImage.h"
|
2013-07-08 21:21:05 -07:00
|
|
|
#include "GLContextProvider.h"
|
2013-09-04 05:14:52 -07:00
|
|
|
#include "GLContext.h"
|
2013-12-03 10:44:38 -08:00
|
|
|
#include "GLUploadHelpers.h"
|
2013-04-16 14:35:57 -07:00
|
|
|
#include "mozilla/layers/GLManager.h"
|
Bug 825928: Land layers refactoring. r=jrmuizel,bas,nical,mattwoodrow,roc,nrc,benwa,bjacob,jgilbert,kchen CLOSED TREE
Please contact Bas Schouten <bschouten@mozilla.com>, Nicolas Silva <nsilva@mozilla.com> or Nicholas Cameron <ncameron@mozilla.com> with general questions. Below is a rough list of authors to contact with specific questions.
Authors:
gfx/layers/Compositor.* gfx/layers/Effects.h - Compositor Interface - bas,nrc,nical
gfx/layers/d3d* - D3D9/D3D10 - bas
gfx/layers/ThebesLayer* - ThebesLayers - nrc,bas
gfx/layers/composite/* - CompositeLayers - nrc,nical
gfx/layers/client/* - Client - nrc,nical,bas
gfx/layers/*Image* - nical
gfx/layers/ipc ipc - IPC - nical
gfx/layers/opengl - CompositorOGL - nrc,nical
gfx/2d - bas,nrc
gfx/gl - GLContext - bjacob
dom/* layout/* - DOM - mattwoodrow
2013-04-10 02:20:52 -07:00
|
|
|
#include "mozilla/layers/CompositorOGL.h"
|
2013-07-08 21:21:05 -07:00
|
|
|
#include "mozilla/layers/BasicCompositor.h"
|
|
|
|
#include "gfxUtils.h"
|
|
|
|
#include "mozilla/gfx/2D.h"
|
2013-09-22 20:28:16 -07:00
|
|
|
#include "mozilla/gfx/BorrowedContext.h"
|
2012-06-06 17:26:45 -07:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
#include "nsAccessibilityService.h"
|
2012-12-01 16:58:25 -08:00
|
|
|
#include "mozilla/a11y/Platform.h"
|
2012-06-06 17:26:45 -07:00
|
|
|
#endif
|
2013-07-19 14:21:25 -07:00
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
|
|
#include "nsExceptionHandler.h"
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-27 01:15:20 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
|
2008-05-08 15:03:46 -07:00
|
|
|
#include <dlfcn.h>
|
|
|
|
|
2009-04-21 16:53:52 -07:00
|
|
|
#include <ApplicationServices/ApplicationServices.h>
|
|
|
|
|
2013-03-18 07:25:50 -07:00
|
|
|
#include "GeckoProfiler.h"
|
2012-01-17 12:33:04 -08:00
|
|
|
|
2012-08-11 18:42:37 -07:00
|
|
|
#include "nsIDOMWheelEvent.h"
|
|
|
|
|
2011-10-10 22:50:08 -07:00
|
|
|
using namespace mozilla;
|
2010-04-27 15:29:29 -07:00
|
|
|
using namespace mozilla::layers;
|
2011-02-19 14:22:12 -08:00
|
|
|
using namespace mozilla::gl;
|
2011-05-08 03:19:15 -07:00
|
|
|
using namespace mozilla::widget;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#undef DEBUG_UPDATE
|
|
|
|
#undef INVALIDATE_DEBUGGING // flash areas as they are invalidated
|
|
|
|
|
2009-02-15 17:06:52 -08:00
|
|
|
// Don't put more than this many rects in the dirty region, just fluff
|
|
|
|
// out to the bounding-box if there are more
|
|
|
|
#define MAX_RECTS_IN_REGION 100
|
|
|
|
|
2007-07-16 19:24:05 -07:00
|
|
|
#ifdef PR_LOGGING
|
2012-07-30 07:20:58 -07:00
|
|
|
PRLogModuleInfo* sCocoaLog = nullptr;
|
2007-07-16 19:24:05 -07:00
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
extern "C" {
|
|
|
|
CG_EXTERN void CGContextResetCTM(CGContextRef);
|
|
|
|
CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
|
|
|
|
CG_EXTERN void CGContextResetClip(CGContextRef);
|
2013-03-27 08:49:02 -07:00
|
|
|
|
|
|
|
typedef CFTypeRef CGSRegionObj;
|
|
|
|
CGError CGSNewRegionWithRect(const CGRect *rect, CGSRegionObj *outRegion);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-08-16 20:26:17 -07:00
|
|
|
// defined in nsMenuBarX.mm
|
|
|
|
extern NSMenu* sApplicationMenu; // Application menu shared by all menubars
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool gChildViewMethodsSwizzled = false;
|
2009-02-06 09:36:04 -08:00
|
|
|
|
2007-07-17 16:02:40 -07:00
|
|
|
extern nsISupportsArray *gDraggedTransferables;
|
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
ChildView* ChildViewMouseTracker::sLastMouseEventView = nil;
|
2011-08-13 07:25:39 -07:00
|
|
|
NSEvent* ChildViewMouseTracker::sLastMouseMoveEvent = nil;
|
2011-08-08 07:43:13 -07:00
|
|
|
NSWindow* ChildViewMouseTracker::sWindowUnderMouse = nil;
|
2011-08-17 15:30:52 -07:00
|
|
|
NSPoint ChildViewMouseTracker::sLastScrollEventScreenLocation = NSZeroPoint;
|
2007-04-15 06:43:55 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef INVALIDATE_DEBUGGING
|
|
|
|
static void blinkRect(Rect* r);
|
|
|
|
static void blinkRgn(RgnHandle rgn);
|
|
|
|
#endif
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool gUserCancelledDrag = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t nsChildView::sLastInputEventCount = 0;
|
2009-04-21 16:53:52 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
@interface ChildView(Private)
|
|
|
|
|
|
|
|
// sets up our view, attaching it to its owning gecko view
|
2007-10-09 11:46:30 -07:00
|
|
|
- (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild;
|
2011-02-03 13:12:33 -08:00
|
|
|
- (void)forceRefreshOpenGL;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-06-12 13:28:26 -07:00
|
|
|
// set up a gecko mouse event based on a cocoa mouse event
|
2013-08-16 14:17:40 -07:00
|
|
|
- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
|
|
|
|
toGeckoEvent:(WidgetWheelEvent*)outWheelEvent;
|
2013-10-01 00:23:02 -07:00
|
|
|
- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
|
2013-10-10 14:22:02 -07:00
|
|
|
toGeckoEvent:(WidgetInputEvent*)outGeckoEvent;
|
2007-06-12 13:28:26 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
- (NSMenu*)contextMenu;
|
|
|
|
|
|
|
|
- (void)setIsPluginView:(BOOL)aIsPlugin;
|
2009-08-31 18:00:13 -07:00
|
|
|
- (void)setPluginEventModel:(NPEventModel)eventModel;
|
2010-09-17 10:55:39 -07:00
|
|
|
- (void)setPluginDrawingModel:(NPDrawingModel)drawingModel;
|
|
|
|
- (NPDrawingModel)pluginDrawingModel;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
- (BOOL)isRectObscuredBySubview:(NSRect)inRect;
|
|
|
|
|
|
|
|
- (void)processPendingRedraws;
|
|
|
|
|
2013-05-23 07:49:16 -07:00
|
|
|
- (void)drawRect:(NSRect)aRect inContext:(CGContextRef)aContext;
|
2013-06-20 05:59:16 -07:00
|
|
|
- (nsIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect;
|
2013-05-23 07:55:50 -07:00
|
|
|
- (BOOL)isUsingMainThreadOpenGL;
|
2013-03-05 07:21:28 -08:00
|
|
|
- (BOOL)isUsingOpenGL;
|
|
|
|
- (void)drawUsingOpenGL;
|
|
|
|
- (void)drawUsingOpenGLCallback;
|
|
|
|
|
2013-03-27 08:49:02 -07:00
|
|
|
- (BOOL)hasRoundedBottomCorners;
|
2013-05-23 07:49:17 -07:00
|
|
|
- (CGFloat)cornerRadius;
|
|
|
|
- (void)clearCorners;
|
|
|
|
|
|
|
|
// Overlay drawing functions for traditional CGContext drawing
|
|
|
|
- (void)drawTitlebarHighlight;
|
|
|
|
- (void)maskTopCornersInContext:(CGContextRef)aContext;
|
2013-03-27 08:49:02 -07:00
|
|
|
|
2011-01-25 13:21:35 -08:00
|
|
|
// Called using performSelector:withObject:afterDelay:0 to release
|
|
|
|
// aWidgetArray (and its contents) the next time through the run loop.
|
|
|
|
- (void)releaseWidgets:(NSArray*)aWidgetArray;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#if USE_CLICK_HOLD_CONTEXTMENU
|
|
|
|
// called on a timer two seconds after a mouse down to see if we should display
|
|
|
|
// a context menu (click-hold)
|
|
|
|
- (void)clickHoldCallback:(id)inEvent;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
- (id<mozAccessible>)accessible;
|
|
|
|
#endif
|
|
|
|
|
2010-07-16 05:48:02 -07:00
|
|
|
- (BOOL)inactiveWindowAcceptsMouseEvent:(NSEvent*)aEvent;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
@end
|
|
|
|
|
2013-03-27 08:49:02 -07:00
|
|
|
@interface NSView(NSThemeFrameCornerRadius)
|
|
|
|
- (float)roundedCornerRadius;
|
|
|
|
@end
|
|
|
|
|
|
|
|
// Starting with 10.7 the bottom corners of all windows are rounded.
|
|
|
|
// Unfortunately, the standard rounding that OS X applies to OpenGL views
|
|
|
|
// does not use anti-aliasing and looks very crude. Since we want a smooth,
|
|
|
|
// anti-aliased curve, we'll draw it ourselves.
|
|
|
|
// Additionally, we need to turn off the OS-supplied rounding because it
|
|
|
|
// eats into our corner's curve. We do that by overriding an NSSurface method.
|
|
|
|
@interface NSSurface @end
|
|
|
|
|
|
|
|
@implementation NSSurface(DontCutOffCorners)
|
|
|
|
- (CGSRegionObj)_createRoundedBottomRegionForRect:(CGRect)rect
|
|
|
|
{
|
|
|
|
// Create a normal rect region without rounded bottom corners.
|
|
|
|
CGSRegionObj region;
|
|
|
|
CGSNewRegionWithRect(&rect, ®ion);
|
|
|
|
return region;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
/* Convenience routines to go from a gecko rect to cocoa NSRects and back
|
|
|
|
*
|
|
|
|
* Gecko rects (nsRect) contain an origin (x,y) in a coordinate
|
|
|
|
* system with (0,0) in the top-left of the screen. Cocoa rects
|
|
|
|
* (NSRect) contain an origin (x,y) in a coordinate system with
|
|
|
|
* (0,0) in the bottom-left of the screen. Both nsRect and NSRect
|
|
|
|
* contain width/height info, with no difference in their use.
|
|
|
|
* If a Cocoa rect is from a flipped view, there is no need to
|
|
|
|
* convert coordinate systems.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline void
|
2009-01-14 19:27:09 -08:00
|
|
|
NSRectToGeckoRect(const NSRect & inCocoaRect, nsIntRect & outGeckoRect)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-01-14 19:27:09 -08:00
|
|
|
outGeckoRect.x = NSToIntRound(inCocoaRect.origin.x);
|
|
|
|
outGeckoRect.y = NSToIntRound(inCocoaRect.origin.y);
|
|
|
|
outGeckoRect.width = NSToIntRound(inCocoaRect.origin.x + inCocoaRect.size.width) - outGeckoRect.x;
|
|
|
|
outGeckoRect.height = NSToIntRound(inCocoaRect.origin.y + inCocoaRect.size.height) - outGeckoRect.y;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2009-01-14 19:27:09 -08:00
|
|
|
ConvertGeckoRectToMacRect(const nsIntRect& aRect, Rect& outMacRect)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
outMacRect.left = aRect.x;
|
|
|
|
outMacRect.top = aRect.y;
|
|
|
|
outMacRect.right = aRect.x + aRect.width;
|
|
|
|
outMacRect.bottom = aRect.y + aRect.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flips a screen coordinate from a point in the cocoa coordinate system (bottom-left rect) to a point
|
|
|
|
// that is a "flipped" cocoa coordinate system (starts in the top-left).
|
|
|
|
static inline void
|
2009-06-19 09:15:23 -07:00
|
|
|
FlipCocoaScreenCoordinate(NSPoint &inPoint)
|
2012-09-29 04:36:09 -07:00
|
|
|
{
|
2007-12-05 15:17:08 -08:00
|
|
|
inPoint.y = nsCocoaUtils::FlippedScreenY(inPoint.y);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-07-05 20:41:27 -07:00
|
|
|
void EnsureLogInitialized()
|
|
|
|
{
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
if (!sCocoaLog) {
|
|
|
|
sCocoaLog = PR_NewLogModule("nsCocoaWidgets");
|
|
|
|
}
|
|
|
|
#endif // PR_LOGGING
|
|
|
|
}
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// 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(GLContext* aGLContext)
|
|
|
|
: mGLContext(aGLContext)
|
|
|
|
, mTexture(0)
|
|
|
|
, mInUpdate(false)
|
|
|
|
{}
|
|
|
|
|
|
|
|
virtual ~RectTextureImage();
|
|
|
|
|
|
|
|
TemporaryRef<gfx::DrawTarget>
|
|
|
|
BeginUpdate(const nsIntSize& aNewSize,
|
|
|
|
const nsIntRegion& aDirtyRegion = nsIntRegion());
|
|
|
|
void EndUpdate(bool aKeepSurface = false);
|
|
|
|
|
|
|
|
void UpdateIfNeeded(const nsIntSize& aNewSize,
|
|
|
|
const nsIntRegion& aDirtyRegion,
|
|
|
|
void (^aCallback)(gfx::DrawTarget*, const nsIntRegion&))
|
|
|
|
{
|
|
|
|
RefPtr<gfx::DrawTarget> drawTarget = BeginUpdate(aNewSize, aDirtyRegion);
|
|
|
|
if (drawTarget) {
|
|
|
|
aCallback(drawTarget, GetUpdateRegion());
|
|
|
|
EndUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
void UpdateFromCGContext(const nsIntSize& aNewSize,
|
|
|
|
const nsIntRegion& aDirtyRegion,
|
|
|
|
CGContextRef aCGContext);
|
|
|
|
|
2013-07-08 21:21:06 -07:00
|
|
|
void UpdateFromDrawTarget(const nsIntSize& aNewSize,
|
|
|
|
const nsIntRegion& aDirtyRegion,
|
|
|
|
gfx::DrawTarget* aFromDrawTarget);
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
nsIntRegion GetUpdateRegion() {
|
|
|
|
MOZ_ASSERT(mInUpdate, "update region only valid during update");
|
|
|
|
return mUpdateRegion;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Draw(mozilla::layers::GLManager* aManager,
|
|
|
|
const nsIntPoint& aLocation,
|
|
|
|
const gfx3DMatrix& aTransform = gfx3DMatrix());
|
|
|
|
|
2013-07-08 21:21:06 -07:00
|
|
|
static nsIntSize TextureSizeForSize(const nsIntSize& aSize);
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
protected:
|
|
|
|
|
|
|
|
RefPtr<gfx::DrawTarget> mUpdateDrawTarget;
|
|
|
|
GLContext* mGLContext;
|
|
|
|
nsIntRegion mUpdateRegion;
|
|
|
|
nsIntSize mUsedSize;
|
|
|
|
nsIntSize mBufferSize;
|
|
|
|
nsIntSize mTextureSize;
|
|
|
|
GLuint mTexture;
|
|
|
|
bool mInUpdate;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Used for OpenGL drawing from the compositor thread for OMTC BasicLayers.
|
|
|
|
// We need to use OpenGL for this because there seems to be no other robust
|
|
|
|
// way of drawing from a secondary thread without locking, which would cause
|
|
|
|
// deadlocks in our setup. See bug 882523.
|
|
|
|
class GLPresenter : public GLManager
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static GLPresenter* CreateForWindow(nsIWidget* aWindow)
|
|
|
|
{
|
|
|
|
nsRefPtr<GLContext> context = gl::GLContextProvider::CreateForWindow(aWindow);
|
|
|
|
return context ? new GLPresenter(context) : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLPresenter(GLContext* aContext);
|
|
|
|
virtual ~GLPresenter();
|
|
|
|
|
|
|
|
virtual GLContext* gl() const MOZ_OVERRIDE { return mGLContext; }
|
|
|
|
virtual ShaderProgramOGL* GetProgram(ShaderProgramType aType) MOZ_OVERRIDE
|
|
|
|
{
|
2013-07-17 23:54:09 -07:00
|
|
|
MOZ_ASSERT(aType == RGBARectLayerProgramType, "unexpected program type");
|
|
|
|
return mRGBARectProgram;
|
2013-07-08 21:21:05 -07:00
|
|
|
}
|
|
|
|
virtual void BindAndDrawQuad(ShaderProgramOGL *aProg) MOZ_OVERRIDE;
|
|
|
|
|
|
|
|
void BeginFrame(nsIntSize aRenderSize);
|
|
|
|
void EndFrame();
|
|
|
|
|
|
|
|
NSOpenGLContext* GetNSOpenGLContext()
|
|
|
|
{
|
|
|
|
return static_cast<NSOpenGLContext*>(
|
|
|
|
mGLContext->GetNativeData(GLContext::NativeGLContext));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
nsRefPtr<mozilla::gl::GLContext> mGLContext;
|
2013-07-17 23:54:09 -07:00
|
|
|
nsAutoPtr<mozilla::layers::ShaderProgramOGL> mRGBARectProgram;
|
2013-07-08 21:21:05 -07:00
|
|
|
GLuint mQuadVBO;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // unnamed namespace
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
nsChildView::nsChildView() : nsBaseWidget()
|
2012-07-30 07:20:58 -07:00
|
|
|
, mView(nullptr)
|
|
|
|
, mParentView(nullptr)
|
|
|
|
, mParentWidget(nullptr)
|
2013-10-09 07:39:23 -07:00
|
|
|
, mViewTearDownLock("ChildViewTearDown")
|
2013-04-21 19:40:51 -07:00
|
|
|
, mEffectsLock("WidgetEffects")
|
|
|
|
, mShowsResizeIndicator(false)
|
|
|
|
, mHasRoundedBottomCorners(false)
|
2013-05-23 07:49:17 -07:00
|
|
|
, mIsCoveringTitlebar(false)
|
2013-11-26 21:49:45 -08:00
|
|
|
, mTitlebarCGContext(nullptr)
|
2013-04-21 19:40:51 -07:00
|
|
|
, mBackingScaleFactor(0.0)
|
2011-09-30 17:20:33 -07:00
|
|
|
, mVisible(false)
|
|
|
|
, mDrawing(false)
|
|
|
|
, mPluginDrawing(false)
|
|
|
|
, mIsDispatchPaint(false)
|
2012-07-30 07:20:58 -07:00
|
|
|
, mPluginInstanceOwner(nullptr)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-07-05 20:41:27 -07:00
|
|
|
EnsureLogInitialized();
|
2007-07-16 19:24:05 -07:00
|
|
|
|
2010-03-25 12:36:44 -07:00
|
|
|
memset(&mPluginCGContext, 0, sizeof(mPluginCGContext));
|
|
|
|
|
2007-09-04 23:58:16 -07:00
|
|
|
SetBackgroundColor(NS_RGB(255, 255, 255));
|
|
|
|
SetForegroundColor(NS_RGB(0, 0, 0));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsChildView::~nsChildView()
|
|
|
|
{
|
2013-11-26 21:49:45 -08:00
|
|
|
ReleaseTitlebarCGContext();
|
|
|
|
|
2009-07-20 08:02:31 -07:00
|
|
|
// Notify the children that we're gone. childView->ResetParent() can change
|
|
|
|
// our list of children while it's being iterated, so the way we iterate the
|
|
|
|
// list must allow for this.
|
|
|
|
for (nsIWidget* kid = mLastChild; kid;) {
|
2007-07-08 00:08:04 -07:00
|
|
|
nsChildView* childView = static_cast<nsChildView*>(kid);
|
2009-07-20 08:02:31 -07:00
|
|
|
kid = kid->GetPrevSibling();
|
2009-04-23 08:54:50 -07:00
|
|
|
childView->ResetParent();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2013-11-26 21:49:45 -08:00
|
|
|
|
2008-06-27 10:11:24 -07:00
|
|
|
NS_WARN_IF_FALSE(mOnDestroyCalled, "nsChildView object destroyed without calling Destroy()");
|
|
|
|
|
2013-04-21 19:40:51 -07:00
|
|
|
DestroyCompositor();
|
2011-02-19 14:23:02 -08:00
|
|
|
|
2008-06-27 10:11:24 -07:00
|
|
|
// An nsChildView object that was in use can be destroyed without Destroy()
|
|
|
|
// ever being called on it. So we also need to do a quick, safe cleanup
|
|
|
|
// here (it's too late to just call Destroy(), which can cause crashes).
|
|
|
|
// It's particularly important to make sure widgetDestroyed is called on our
|
|
|
|
// mView -- this method NULLs mView's mGeckoChild, and NULL checks on
|
|
|
|
// mGeckoChild are used throughout the ChildView class to tell if it's safe
|
|
|
|
// to use a ChildView object.
|
|
|
|
[mView widgetDestroyed]; // Safe if mView is nil.
|
|
|
|
mParentWidget = nil;
|
|
|
|
TearDownView(); // Safe if called twice.
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
void
|
|
|
|
nsChildView::ReleaseTitlebarCGContext()
|
|
|
|
{
|
|
|
|
if (mTitlebarCGContext) {
|
|
|
|
CGContextRelease(mTitlebarCGContext);
|
|
|
|
mTitlebarCGContext = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-13 19:56:18 -07:00
|
|
|
NS_IMPL_ISUPPORTS_INHERITED1(nsChildView, nsBaseWidget, nsIPluginWidget)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-09-23 23:18:10 -07:00
|
|
|
nsresult nsChildView::Create(nsIWidget *aParent,
|
|
|
|
nsNativeWidget aNativeParent,
|
|
|
|
const nsIntRect &aRect,
|
2011-04-16 18:22:44 -07:00
|
|
|
nsDeviceContext *aContext,
|
2009-09-23 23:18:10 -07:00
|
|
|
nsWidgetInitData *aInitData)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2010-04-13 13:36:03 -07:00
|
|
|
// Because the hidden window is created outside of an event loop,
|
|
|
|
// we need to provide an autorelease pool to avoid leaking cocoa objects
|
|
|
|
// (see bug 559075).
|
|
|
|
nsAutoreleasePool localPool;
|
|
|
|
|
2009-02-06 09:36:04 -08:00
|
|
|
// See NSView (MethodSwizzling) below.
|
2010-02-23 12:10:25 -08:00
|
|
|
if (!gChildViewMethodsSwizzled) {
|
2009-02-06 09:36:04 -08:00
|
|
|
nsToolkit::SwizzleMethods([NSView class], @selector(mouseDownCanMoveWindow),
|
|
|
|
@selector(nsChildView_NSView_mouseDownCanMoveWindow));
|
2011-08-18 13:39:54 -07:00
|
|
|
#ifdef __LP64__
|
2012-05-17 00:53:20 -07:00
|
|
|
if (nsCocoaFeatures::OnLionOrLater()) {
|
2011-08-18 13:39:54 -07:00
|
|
|
nsToolkit::SwizzleMethods([NSEvent class], @selector(addLocalMonitorForEventsMatchingMask:handler:),
|
|
|
|
@selector(nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:handler:),
|
2011-09-30 17:20:33 -07:00
|
|
|
true);
|
2011-08-18 13:39:54 -07:00
|
|
|
nsToolkit::SwizzleMethods([NSEvent class], @selector(removeMonitor:),
|
2011-09-30 17:20:33 -07:00
|
|
|
@selector(nsChildView_NSEvent_removeMonitor:), true);
|
2011-08-18 13:39:54 -07:00
|
|
|
}
|
2012-10-15 05:38:34 -07:00
|
|
|
#else
|
2011-02-23 20:48:12 -08:00
|
|
|
TextInputHandler::SwizzleMethods();
|
2011-01-20 17:08:11 -08:00
|
|
|
#endif
|
2011-09-30 17:20:33 -07:00
|
|
|
gChildViewMethodsSwizzled = true;
|
2009-02-06 09:36:04 -08:00
|
|
|
}
|
2008-02-13 07:57:12 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mBounds = aRect;
|
|
|
|
|
2011-10-25 08:05:32 -07:00
|
|
|
// Ensure that the toolkit is created.
|
|
|
|
nsToolkit::GetToolkit();
|
|
|
|
|
2012-08-15 11:53:09 -07:00
|
|
|
BaseCreate(aParent, aRect, aContext, aInitData);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// inherit things from the parent view and create our parallel
|
|
|
|
// NSView in the Cocoa display system
|
|
|
|
mParentView = nil;
|
|
|
|
if (aParent) {
|
2009-09-23 23:18:10 -07:00
|
|
|
// This is the case when we're the popup content view of a popup window.
|
2007-03-22 10:30:00 -07:00
|
|
|
SetBackgroundColor(aParent->GetBackgroundColor());
|
|
|
|
SetForegroundColor(aParent->GetForegroundColor());
|
|
|
|
|
|
|
|
// inherit the top-level window. NS_NATIVE_WIDGET is always a NSView
|
|
|
|
// regardless of if we're asking a window or a view (for compatibility
|
|
|
|
// with windows).
|
2012-06-20 12:48:50 -07:00
|
|
|
mParentView = (NSView<mozView>*)aParent->GetNativeData(NS_NATIVE_WIDGET);
|
2007-03-22 10:30:00 -07:00
|
|
|
mParentWidget = aParent;
|
2009-09-23 23:18:10 -07:00
|
|
|
} else {
|
|
|
|
// This is the normal case. When we're the root widget of the view hiararchy,
|
|
|
|
// aNativeParent will be the contentView of our window, since that's what
|
|
|
|
// nsCocoaWindow returns when asked for an NS_NATIVE_VIEW.
|
2012-06-20 12:48:50 -07:00
|
|
|
mParentView = reinterpret_cast<NSView<mozView>*>(aNativeParent);
|
2009-09-23 23:18:10 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// create our parallel NSView and hook it up to our parent. Recall
|
|
|
|
// that NS_NATIVE_WIDGET is the NSView.
|
2012-09-29 04:36:09 -07:00
|
|
|
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mParentView);
|
|
|
|
NSRect r = nsCocoaUtils::DevPixelsToCocoaPoints(mBounds, scaleFactor);
|
2012-06-20 12:48:50 -07:00
|
|
|
mView = [(NSView<mozView>*)CreateCocoaView(r) retain];
|
2012-09-29 04:36:09 -07:00
|
|
|
if (!mView) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-01-23 22:00:39 -08:00
|
|
|
[(ChildView*)mView setIsPluginView:(mWindowType == eWindowType_plugin)];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// If this view was created in a Gecko view hierarchy, the initial state
|
|
|
|
// is hidden. If the view is attached only to a native NSView but has
|
|
|
|
// no Gecko parent (as in embedding), the initial state is visible.
|
|
|
|
if (mParentWidget)
|
|
|
|
[mView setHidden:YES];
|
|
|
|
else
|
2011-09-30 17:20:33 -07:00
|
|
|
mVisible = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Hook it up in the NSView hierarchy.
|
|
|
|
if (mParentView) {
|
|
|
|
[mParentView addSubview:mView];
|
|
|
|
}
|
|
|
|
|
|
|
|
// if this is a ChildView, make sure that our per-window data
|
|
|
|
// is set up
|
|
|
|
if ([mView isKindOfClass:[ChildView class]])
|
2009-06-17 11:13:12 -07:00
|
|
|
[[WindowDataMap sharedWindowDataMap] ensureDataForWindow:[mView window]];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ASSERTION(!mTextInputHandler, "mTextInputHandler has already existed");
|
|
|
|
mTextInputHandler = new TextInputHandler(this, mView);
|
2009-09-30 19:52:50 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Creates the appropriate child view. Override to create something other than
|
|
|
|
// our |ChildView| object. Autoreleases, so caller must retain.
|
|
|
|
NSView*
|
|
|
|
nsChildView::CreateCocoaView(NSRect inFrame)
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-10-09 11:46:30 -07:00
|
|
|
return [[[ChildView alloc] initWithFrame:inFrame geckoChild:this] autorelease];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void nsChildView::TearDownView()
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!mView)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NSWindow* win = [mView window];
|
|
|
|
NSResponder* responder = [win firstResponder];
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// We're being unhooked from the view hierarchy, don't leave our view
|
|
|
|
// or a child view as the window first responder.
|
|
|
|
if (responder && [responder isKindOfClass:[NSView class]] &&
|
|
|
|
[(NSView*)responder isDescendantOf:mView]) {
|
2008-01-15 15:11:55 -08:00
|
|
|
[win makeFirstResponder:[mView superview]];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-05-30 11:25:44 -07:00
|
|
|
|
|
|
|
// If mView is win's contentView, win (mView's NSWindow) "owns" mView --
|
|
|
|
// win has retained mView, and will detach it from the view hierarchy and
|
|
|
|
// release it when necessary (when win is itself destroyed (in a call to
|
|
|
|
// [win dealloc])). So all we need to do here is call [mView release] (to
|
|
|
|
// match the call to [mView retain] in nsChildView::StandardCreate()).
|
|
|
|
// Also calling [mView removeFromSuperviewWithoutNeedingDisplay] causes
|
|
|
|
// mView to be released again and dealloced, while remaining win's
|
|
|
|
// contentView. So if we do that here, win will (for a short while) have
|
|
|
|
// an invalid contentView (for the consequences see bmo bugs 381087 and
|
|
|
|
// 374260).
|
|
|
|
if ([mView isEqual:[win contentView]]) {
|
|
|
|
[mView release];
|
|
|
|
} else {
|
|
|
|
// Stop NSView hierarchy being changed during [ChildView drawRect:]
|
|
|
|
[mView performSelectorOnMainThread:@selector(delayedTearDown) withObject:nil waitUntilDone:false];
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
mView = nil;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-08-13 15:06:49 -07:00
|
|
|
nsCocoaWindow*
|
|
|
|
nsChildView::GetXULWindowWidget()
|
|
|
|
{
|
2009-09-15 14:56:44 -07:00
|
|
|
id windowDelegate = [[mView window] delegate];
|
2009-08-13 15:06:49 -07:00
|
|
|
if (windowDelegate && [windowDelegate isKindOfClass:[WindowDelegate class]]) {
|
|
|
|
return [(WindowDelegate *)windowDelegate geckoWidget];
|
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2009-08-13 15:06:49 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP nsChildView::Destroy()
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2013-10-09 07:39:23 -07:00
|
|
|
// Make sure that no composition is in progress while disconnecting
|
|
|
|
// ourselves from the view.
|
|
|
|
MutexAutoLock lock(mViewTearDownLock);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mOnDestroyCalled)
|
|
|
|
return NS_OK;
|
2011-09-30 17:20:33 -07:00
|
|
|
mOnDestroyCalled = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
[mView widgetDestroyed];
|
|
|
|
|
|
|
|
nsBaseWidget::Destroy();
|
|
|
|
|
2012-08-15 11:52:41 -07:00
|
|
|
NotifyWindowDestroyed();
|
2007-03-22 10:30:00 -07:00
|
|
|
mParentWidget = nil;
|
|
|
|
|
|
|
|
TearDownView();
|
|
|
|
|
2009-03-09 09:59:29 -07:00
|
|
|
nsBaseWidget::OnDestroy();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static void PrintViewHierarchy(NSView *view)
|
|
|
|
{
|
|
|
|
while (view) {
|
|
|
|
NSLog(@" view is %x, frame %@", view, NSStringFromRect([view frame]));
|
|
|
|
view = [view superview];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Return native data according to aDataType
|
2012-08-22 08:56:38 -07:00
|
|
|
void* nsChildView::GetNativeData(uint32_t aDataType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL;
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
void* retVal = nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
switch (aDataType)
|
|
|
|
{
|
2007-09-17 15:55:20 -07:00
|
|
|
case NS_NATIVE_WIDGET:
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_NATIVE_DISPLAY:
|
|
|
|
retVal = (void*)mView;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_NATIVE_WINDOW:
|
2009-09-15 14:56:44 -07:00
|
|
|
retVal = [mView window];
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
2007-09-17 15:55:20 -07:00
|
|
|
|
|
|
|
case NS_NATIVE_GRAPHIC:
|
2009-08-14 07:09:00 -07:00
|
|
|
NS_ERROR("Requesting NS_NATIVE_GRAPHIC on a Mac OS X child view!");
|
2012-07-30 07:20:58 -07:00
|
|
|
retVal = nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
2007-09-17 15:55:20 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
case NS_NATIVE_OFFSETX:
|
|
|
|
retVal = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_NATIVE_OFFSETY:
|
|
|
|
retVal = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_NATIVE_PLUGIN_PORT:
|
2007-03-26 18:07:57 -07:00
|
|
|
case NS_NATIVE_PLUGIN_PORT_CG:
|
|
|
|
{
|
2010-01-23 22:00:39 -08:00
|
|
|
// The NP_CGContext pointer should always be NULL in the Cocoa event model.
|
|
|
|
if ([(ChildView*)mView pluginEventModel] == NPEventModelCocoa)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2007-03-26 18:07:57 -07:00
|
|
|
|
2009-07-22 01:57:39 -07:00
|
|
|
UpdatePluginPort();
|
2010-09-17 10:55:39 -07:00
|
|
|
retVal = (void*)&mPluginCGContext;
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retVal;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
nsTransparencyMode nsChildView::GetTransparencyMode()
|
2007-12-19 11:40:18 -08:00
|
|
|
{
|
2009-11-13 14:58:15 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2009-11-13 14:58:15 -08:00
|
|
|
nsCocoaWindow* windowWidget = GetXULWindowWidget();
|
|
|
|
return windowWidget ? windowWidget->GetTransparencyMode() : eTransparencyOpaque;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2009-11-13 14:58:15 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(eTransparencyOpaque);
|
2007-12-19 11:40:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// This is called by nsContainerFrame on the root widget for all window types
|
2008-08-12 17:44:14 -07:00
|
|
|
// except popup windows (when nsCocoaWindow::SetTransparencyMode is used instead).
|
|
|
|
void nsChildView::SetTransparencyMode(nsTransparencyMode aMode)
|
2007-12-19 11:40:18 -08:00
|
|
|
{
|
2008-08-12 17:44:14 -07:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2009-11-13 14:58:15 -08:00
|
|
|
nsCocoaWindow* windowWidget = GetXULWindowWidget();
|
|
|
|
if (windowWidget) {
|
|
|
|
windowWidget->SetTransparencyMode(aMode);
|
2007-12-19 11:40:18 -08:00
|
|
|
}
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2008-08-12 17:44:14 -07:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-12-19 11:40:18 -08:00
|
|
|
}
|
|
|
|
|
2012-07-19 01:57:50 -07:00
|
|
|
bool nsChildView::IsVisible() const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-19 01:57:50 -07:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!mVisible) {
|
2012-07-19 01:57:50 -07:00
|
|
|
return mVisible;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-19 01:57:50 -07:00
|
|
|
// mVisible does not accurately reflect the state of a hidden tabbed view
|
|
|
|
// so verify that the view has a window as well
|
|
|
|
// then check native widget hierarchy visibility
|
|
|
|
return ([mView window] != nil) && !NSIsEmptyRect([mView visibleRect]);
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2012-07-19 01:57:50 -07:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-04-23 15:56:40 -07:00
|
|
|
void nsChildView::HidePlugin()
|
|
|
|
{
|
2009-09-24 02:32:20 -07:00
|
|
|
NS_ASSERTION(mWindowType == eWindowType_plugin,
|
|
|
|
"HidePlugin called on non-plugin view");
|
2008-04-23 15:56:40 -07:00
|
|
|
}
|
|
|
|
|
2009-07-22 01:57:39 -07:00
|
|
|
void nsChildView::UpdatePluginPort()
|
|
|
|
{
|
2009-09-24 02:32:20 -07:00
|
|
|
NS_ASSERTION(mWindowType == eWindowType_plugin,
|
|
|
|
"UpdatePluginPort called on non-plugin view");
|
2009-07-22 01:57:39 -07:00
|
|
|
|
2012-08-30 12:10:55 -07:00
|
|
|
// [NSGraphicsContext currentContext] is supposed to "return the
|
|
|
|
// current graphics context of the current thread." But sometimes
|
|
|
|
// (when called while mView isn't focused for drawing) it returns a
|
|
|
|
// graphics context for the wrong window. [window graphicsContext]
|
|
|
|
// (which "provides the graphics context associated with the window
|
|
|
|
// for the current thread") seems always to return the "right"
|
|
|
|
// graphics context. See bug 500130.
|
|
|
|
mPluginCGContext.context = NULL;
|
|
|
|
mPluginCGContext.window = NULL;
|
2009-07-22 01:57:39 -07:00
|
|
|
}
|
|
|
|
|
2008-04-23 15:56:40 -07:00
|
|
|
static void HideChildPluginViews(NSView* aView)
|
|
|
|
{
|
|
|
|
NSArray* subviews = [aView subviews];
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < [subviews count]; ++i) {
|
|
|
|
NSView* view = [subviews objectAtIndex: i];
|
|
|
|
|
|
|
|
if (![view isKindOfClass:[ChildView class]])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ChildView* childview = static_cast<ChildView*>(view);
|
|
|
|
if ([childview isPluginView]) {
|
|
|
|
nsChildView* widget = static_cast<nsChildView*>([childview widget]);
|
|
|
|
if (widget) {
|
|
|
|
widget->HidePlugin();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
HideChildPluginViews(view);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Hide or show this component
|
2011-09-28 23:19:26 -07:00
|
|
|
NS_IMETHODIMP nsChildView::Show(bool aState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aState != mVisible) {
|
2010-04-13 13:36:03 -07:00
|
|
|
// Provide an autorelease pool because this gets called during startup
|
|
|
|
// on the "hidden window", resulting in cocoa object leakage if there's
|
|
|
|
// no pool in place.
|
|
|
|
nsAutoreleasePool localPool;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
[mView setHidden:!aState];
|
|
|
|
mVisible = aState;
|
2010-09-07 10:20:03 -07:00
|
|
|
if (!mVisible && IsPluginView())
|
|
|
|
HidePlugin();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-04-23 08:54:50 -07:00
|
|
|
// Change the parent of this widget
|
2008-10-28 22:19:42 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsChildView::SetParent(nsIWidget* aNewParent)
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
|
|
|
if (mOnDestroyCalled)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
|
|
|
|
|
2011-11-21 12:15:38 -08:00
|
|
|
if (mParentWidget) {
|
2008-10-28 22:19:42 -07:00
|
|
|
mParentWidget->RemoveChild(this);
|
2011-11-21 12:15:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aNewParent) {
|
|
|
|
ReparentNativeWidget(aNewParent);
|
|
|
|
} else {
|
|
|
|
[mView removeFromSuperview];
|
|
|
|
mParentView = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
mParentWidget = aNewParent;
|
2010-09-18 04:28:50 -07:00
|
|
|
|
2011-11-21 12:15:38 -08:00
|
|
|
if (mParentWidget) {
|
|
|
|
mParentWidget->AddChild(this);
|
|
|
|
}
|
2010-09-18 04:28:50 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
2011-11-21 12:15:38 -08:00
|
|
|
|
2010-09-18 04:28:50 -07:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsChildView::ReparentNativeWidget(nsIWidget* aNewParent)
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aNewParent, "");
|
|
|
|
|
|
|
|
if (mOnDestroyCalled)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
NSView<mozView>* newParentView =
|
2012-06-20 12:48:50 -07:00
|
|
|
(NSView<mozView>*)aNewParent->GetNativeData(NS_NATIVE_WIDGET);
|
2010-09-18 04:28:50 -07:00
|
|
|
NS_ENSURE_TRUE(newParentView, NS_ERROR_FAILURE);
|
|
|
|
|
2008-10-28 22:19:42 -07:00
|
|
|
// we hold a ref to mView, so this is safe
|
|
|
|
[mView removeFromSuperview];
|
2011-11-21 12:15:38 -08:00
|
|
|
mParentView = newParentView;
|
2008-10-28 22:19:42 -07:00
|
|
|
[mParentView addSubview:mView];
|
|
|
|
return NS_OK;
|
2010-09-18 04:28:50 -07:00
|
|
|
|
2008-10-28 22:19:42 -07:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-04-23 08:54:50 -07:00
|
|
|
void nsChildView::ResetParent()
|
|
|
|
{
|
|
|
|
if (!mOnDestroyCalled) {
|
|
|
|
if (mParentWidget)
|
|
|
|
mParentWidget->RemoveChild(this);
|
|
|
|
if (mView)
|
|
|
|
[mView removeFromSuperview];
|
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
mParentWidget = nullptr;
|
2009-04-23 08:54:50 -07:00
|
|
|
}
|
|
|
|
|
2008-10-21 07:56:35 -07:00
|
|
|
nsIWidget*
|
2010-04-25 13:58:03 -07:00
|
|
|
nsChildView::GetParent()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return mParentWidget;
|
|
|
|
}
|
|
|
|
|
2010-08-13 02:57:55 -07:00
|
|
|
float
|
|
|
|
nsChildView::GetDPI()
|
|
|
|
{
|
|
|
|
NSWindow* window = [mView window];
|
2010-08-19 02:35:08 -07:00
|
|
|
if (window && [window isKindOfClass:[BaseWindow class]]) {
|
|
|
|
return [(BaseWindow*)window getDPI];
|
|
|
|
}
|
|
|
|
|
|
|
|
return 96.0;
|
2010-08-13 02:57:55 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
NS_IMETHODIMP nsChildView::Enable(bool aState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-07-22 22:19:08 -07:00
|
|
|
bool nsChildView::IsEnabled() const
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-22 22:19:08 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
NS_IMETHODIMP nsChildView::SetFocus(bool aRaise)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2010-09-07 10:20:03 -07:00
|
|
|
NSWindow* window = [mView window];
|
|
|
|
if (window)
|
|
|
|
[window makeFirstResponder:mView];
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Override to set the cursor on the mac
|
|
|
|
NS_IMETHODIMP nsChildView::SetCursor(nsCursor aCursor)
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2010-03-08 04:35:25 -08:00
|
|
|
if ([mView isDragInProgress])
|
|
|
|
return NS_OK; // Don't change the cursor during dragging.
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsBaseWidget::SetCursor(aCursor);
|
2010-03-11 08:44:31 -08:00
|
|
|
return [[nsCursorManager sharedInstance] setCursor:aCursor];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// implement to fix "hidden virtual function" warning
|
|
|
|
NS_IMETHODIMP nsChildView::SetCursor(imgIContainer* aCursor,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aHotspotX, uint32_t aHotspotY)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-03-11 08:44:31 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
|
|
|
nsBaseWidget::SetCursor(aCursor, aHotspotX, aHotspotY);
|
2013-12-04 14:46:19 -08:00
|
|
|
return [[nsCursorManager sharedInstance] setCursorWithImage:aCursor hotSpotX:aHotspotX hotSpotY:aHotspotY scaleFactor:BackingScaleFactor()];
|
2010-03-11 08:44:31 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
// Get this component dimension
|
2009-01-14 19:27:09 -08:00
|
|
|
NS_IMETHODIMP nsChildView::GetBounds(nsIntRect &aRect)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2010-09-16 09:30:28 -07:00
|
|
|
if (!mView) {
|
|
|
|
aRect = mBounds;
|
|
|
|
} else {
|
2012-09-29 04:36:09 -07:00
|
|
|
aRect = CocoaPointsToDevPixels([mView frame]);
|
2010-09-16 09:30:28 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-01-15 12:47:42 -08:00
|
|
|
NS_IMETHODIMP nsChildView::GetClientBounds(nsIntRect &aRect)
|
|
|
|
{
|
|
|
|
GetBounds(aRect);
|
|
|
|
if (!mParentWidget) {
|
|
|
|
// For top level widgets we want the position on screen, not the position
|
|
|
|
// of this view inside the window.
|
|
|
|
MOZ_ASSERT(mWindowType != eWindowType_plugin, "plugin widgets should have parents");
|
|
|
|
aRect.MoveTo(WidgetToScreenOffset());
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-02-10 14:31:00 -08:00
|
|
|
NS_IMETHODIMP nsChildView::GetScreenBounds(nsIntRect &aRect)
|
|
|
|
{
|
|
|
|
GetBounds(aRect);
|
|
|
|
aRect.MoveTo(WidgetToScreenOffset());
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-09-29 04:36:09 -07:00
|
|
|
double
|
2012-10-30 17:31:35 -07:00
|
|
|
nsChildView::GetDefaultScaleInternal()
|
2012-09-29 04:36:09 -07:00
|
|
|
{
|
|
|
|
return BackingScaleFactor();
|
|
|
|
}
|
|
|
|
|
|
|
|
CGFloat
|
|
|
|
nsChildView::BackingScaleFactor()
|
|
|
|
{
|
|
|
|
if (mBackingScaleFactor > 0.0) {
|
|
|
|
return mBackingScaleFactor;
|
|
|
|
}
|
|
|
|
if (!mView) {
|
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
mBackingScaleFactor = nsCocoaUtils::GetBackingScaleFactor(mView);
|
|
|
|
return mBackingScaleFactor;
|
|
|
|
}
|
|
|
|
|
2012-10-16 12:41:20 -07:00
|
|
|
void
|
|
|
|
nsChildView::BackingScaleFactorChanged()
|
|
|
|
{
|
|
|
|
CGFloat newScale = nsCocoaUtils::GetBackingScaleFactor(mView);
|
|
|
|
|
|
|
|
// ignore notification if it hasn't really changed (or maybe we have
|
|
|
|
// disabled HiDPI mode via prefs)
|
|
|
|
if (mBackingScaleFactor == newScale) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mBackingScaleFactor = newScale;
|
|
|
|
|
2012-10-16 12:41:21 -07:00
|
|
|
if (mWidgetListener && !mWidgetListener->GetXULWindow()) {
|
|
|
|
nsIPresShell* presShell = mWidgetListener->GetPresShell();
|
|
|
|
if (presShell) {
|
|
|
|
presShell->BackingScaleFactorChanged();
|
|
|
|
}
|
2012-10-16 12:41:20 -07:00
|
|
|
}
|
|
|
|
|
2012-10-16 12:41:21 -07:00
|
|
|
if (IsPluginView()) {
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
2013-10-01 20:46:03 -07:00
|
|
|
WidgetGUIEvent guiEvent(true, NS_PLUGIN_RESOLUTION_CHANGED, this);
|
2012-10-16 12:41:21 -07:00
|
|
|
guiEvent.time = PR_IntervalNow();
|
|
|
|
DispatchEvent(&guiEvent, status);
|
2012-10-16 12:41:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-30 09:22:41 -07:00
|
|
|
int32_t
|
|
|
|
nsChildView::RoundsWidgetCoordinatesTo()
|
|
|
|
{
|
|
|
|
if (BackingScaleFactor() == 2.0) {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
NS_IMETHODIMP nsChildView::ConstrainPosition(bool aAllowSlop,
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t *aX, int32_t *aY)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move this component, aX and aY are in the parent widget coordinate system
|
2012-12-12 01:57:38 -08:00
|
|
|
NS_IMETHODIMP nsChildView::Move(double aX, double aY)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2012-12-12 01:57:38 -08:00
|
|
|
int32_t x = NSToIntRound(aX);
|
|
|
|
int32_t y = NSToIntRound(aY);
|
|
|
|
|
|
|
|
if (!mView || (mBounds.x == x && mBounds.y == y))
|
2007-11-06 23:36:10 -08:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-12-12 01:57:38 -08:00
|
|
|
mBounds.x = x;
|
|
|
|
mBounds.y = y;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-09-29 04:36:09 -07:00
|
|
|
[mView setFrame:DevPixelsToCocoaPoints(mBounds)];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-11-06 23:36:10 -08:00
|
|
|
if (mVisible)
|
|
|
|
[mView setNeedsDisplay:YES];
|
|
|
|
|
2012-10-26 06:15:22 -07:00
|
|
|
NotifyRollupGeometryChange();
|
2007-11-06 23:36:10 -08:00
|
|
|
ReportMoveEvent();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-12-12 01:57:38 -08:00
|
|
|
NS_IMETHODIMP nsChildView::Resize(double aWidth, double aHeight, bool aRepaint)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2012-12-12 01:57:38 -08:00
|
|
|
int32_t width = NSToIntRound(aWidth);
|
|
|
|
int32_t height = NSToIntRound(aHeight);
|
|
|
|
|
|
|
|
if (!mView || (mBounds.width == width && mBounds.height == height))
|
2007-11-06 23:36:10 -08:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-12-12 01:57:38 -08:00
|
|
|
mBounds.width = width;
|
|
|
|
mBounds.height = height;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-09-29 04:36:09 -07:00
|
|
|
[mView setFrame:DevPixelsToCocoaPoints(mBounds)];
|
2007-11-06 23:36:10 -08:00
|
|
|
|
|
|
|
if (mVisible && aRepaint)
|
|
|
|
[mView setNeedsDisplay:YES];
|
|
|
|
|
2012-10-26 06:15:22 -07:00
|
|
|
NotifyRollupGeometryChange();
|
2007-11-06 23:36:10 -08:00
|
|
|
ReportSizeEvent();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-12-12 01:57:38 -08:00
|
|
|
NS_IMETHODIMP nsChildView::Resize(double aX, double aY,
|
|
|
|
double aWidth, double aHeight, bool aRepaint)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2012-12-12 01:57:38 -08:00
|
|
|
int32_t x = NSToIntRound(aX);
|
|
|
|
int32_t y = NSToIntRound(aY);
|
|
|
|
int32_t width = NSToIntRound(aWidth);
|
|
|
|
int32_t height = NSToIntRound(aHeight);
|
|
|
|
|
|
|
|
BOOL isMoving = (mBounds.x != x || mBounds.y != y);
|
|
|
|
BOOL isResizing = (mBounds.width != width || mBounds.height != height);
|
2007-11-06 23:36:10 -08:00
|
|
|
if (!mView || (!isMoving && !isResizing))
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
if (isMoving) {
|
2012-12-12 01:57:38 -08:00
|
|
|
mBounds.x = x;
|
|
|
|
mBounds.y = y;
|
2007-11-06 23:36:10 -08:00
|
|
|
}
|
|
|
|
if (isResizing) {
|
2012-12-12 01:57:38 -08:00
|
|
|
mBounds.width = width;
|
|
|
|
mBounds.height = height;
|
2007-11-06 23:36:10 -08:00
|
|
|
}
|
|
|
|
|
2012-09-29 04:36:09 -07:00
|
|
|
[mView setFrame:DevPixelsToCocoaPoints(mBounds)];
|
2007-11-06 23:36:10 -08:00
|
|
|
|
|
|
|
if (mVisible && aRepaint)
|
|
|
|
[mView setNeedsDisplay:YES];
|
|
|
|
|
2012-10-26 06:15:22 -07:00
|
|
|
NotifyRollupGeometryChange();
|
2008-01-15 15:11:55 -08:00
|
|
|
if (isMoving) {
|
2007-11-06 23:36:10 -08:00
|
|
|
ReportMoveEvent();
|
2008-01-15 15:11:55 -08:00
|
|
|
if (mOnDestroyCalled)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-11-06 23:36:10 -08:00
|
|
|
if (isResizing)
|
|
|
|
ReportSizeEvent();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
static const int32_t resizeIndicatorWidth = 15;
|
|
|
|
static const int32_t resizeIndicatorHeight = 15;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool nsChildView::ShowsResizeIndicator(nsIntRect* aResizerRect)
|
2008-08-08 09:11:54 -07:00
|
|
|
{
|
|
|
|
NSView *topLevelView = mView, *superView = nil;
|
2008-08-19 21:23:19 -07:00
|
|
|
while ((superView = [topLevelView superview]))
|
2008-08-08 09:11:54 -07:00
|
|
|
topLevelView = superView;
|
|
|
|
|
2009-09-07 14:52:59 -07:00
|
|
|
if (![[topLevelView window] showsResizeIndicator] ||
|
|
|
|
!([[topLevelView window] styleMask] & NSResizableWindowMask))
|
2011-09-30 17:20:33 -07:00
|
|
|
return false;
|
2008-08-08 09:11:54 -07:00
|
|
|
|
|
|
|
if (aResizerRect) {
|
|
|
|
NSSize bounds = [topLevelView bounds].size;
|
|
|
|
NSPoint corner = NSMakePoint(bounds.width, [topLevelView isFlipped] ? bounds.height : 0);
|
|
|
|
corner = [topLevelView convertPoint:corner toView:mView];
|
|
|
|
aResizerRect->SetRect(NSToIntRound(corner.x) - resizeIndicatorWidth,
|
|
|
|
NSToIntRound(corner.y) - resizeIndicatorHeight,
|
|
|
|
resizeIndicatorWidth, resizeIndicatorHeight);
|
|
|
|
}
|
2011-09-30 17:20:33 -07:00
|
|
|
return true;
|
2008-08-08 09:11:54 -07:00
|
|
|
}
|
|
|
|
|
2009-02-05 15:31:00 -08:00
|
|
|
// In QuickDraw mode the coordinate system used here should be that of the
|
|
|
|
// browser window's content region (defined as everything but the 22-pixel
|
|
|
|
// high titlebar). But in CoreGraphics mode the coordinate system should be
|
|
|
|
// that of the browser window as a whole (including its titlebar). Both
|
|
|
|
// coordinate systems have a top-left origin. See bmo bug 474491.
|
|
|
|
//
|
|
|
|
// There's a bug in this method's code -- it currently uses the QuickDraw
|
|
|
|
// coordinate system for both the QuickDraw and CoreGraphics drawing modes.
|
|
|
|
// This bug is fixed by the patch for bug 474491. But the Flash plugin (both
|
|
|
|
// version 10.0.12.36 from Adobe and version 9.0 r151 from Apple) has Mozilla-
|
|
|
|
// specific code to work around this bug, which breaks when we fix it (see bmo
|
|
|
|
// bug 477077). So we'll need to coordinate releasing a fix for this bug with
|
|
|
|
// Adobe and other major plugin vendors that support the CoreGraphics mode.
|
2013-01-04 14:39:22 -08:00
|
|
|
//
|
|
|
|
// outClipRect and outOrigin are in display pixels, not device pixels.
|
2011-09-28 23:19:26 -07:00
|
|
|
NS_IMETHODIMP nsChildView::GetPluginClipRect(nsIntRect& outClipRect, nsIntPoint& outOrigin, bool& outWidgetVisible)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2009-09-24 02:32:20 -07:00
|
|
|
NS_ASSERTION(mWindowType == eWindowType_plugin,
|
|
|
|
"GetPluginClipRect must only be called on a plugin widget");
|
|
|
|
if (mWindowType != eWindowType_plugin) return NS_ERROR_FAILURE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-09-15 14:56:44 -07:00
|
|
|
NSWindow* window = [mView window];
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil];
|
2009-02-05 15:05:53 -08:00
|
|
|
NSRect frame = [[window contentView] frame];
|
2007-03-22 10:30:00 -07:00
|
|
|
viewOrigin.y = frame.size.height - viewOrigin.y;
|
|
|
|
|
|
|
|
// set up the clipping region for plugins.
|
|
|
|
NSRect visibleBounds = [mView visibleRect];
|
|
|
|
NSPoint clipOrigin = [mView convertPoint:visibleBounds.origin toView:nil];
|
|
|
|
|
2009-02-05 15:05:53 -08:00
|
|
|
// Convert from cocoa to QuickDraw coordinates
|
2007-03-22 10:30:00 -07:00
|
|
|
clipOrigin.y = frame.size.height - clipOrigin.y;
|
|
|
|
|
2009-01-14 19:27:09 -08:00
|
|
|
outClipRect.x = NSToIntRound(clipOrigin.x);
|
|
|
|
outClipRect.y = NSToIntRound(clipOrigin.y);
|
2009-07-21 17:44:55 -07:00
|
|
|
|
|
|
|
// need to convert view's origin to window coordinates.
|
|
|
|
// then, encode as "SetOrigin" ready values.
|
|
|
|
outOrigin.x = -NSToIntRound(viewOrigin.x);
|
|
|
|
outOrigin.y = -NSToIntRound(viewOrigin.y);
|
|
|
|
|
2012-07-19 01:57:50 -07:00
|
|
|
if (IsVisible() && [mView window] != nil) {
|
2009-01-14 19:27:09 -08:00
|
|
|
outClipRect.width = NSToIntRound(visibleBounds.origin.x + visibleBounds.size.width) - NSToIntRound(visibleBounds.origin.x);
|
|
|
|
outClipRect.height = NSToIntRound(visibleBounds.origin.y + visibleBounds.size.height) - NSToIntRound(visibleBounds.origin.y);
|
2009-07-21 17:44:55 -07:00
|
|
|
|
|
|
|
if (mClipRects) {
|
|
|
|
nsIntRect clipBounds;
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < mClipRectCount; ++i) {
|
2013-01-04 14:39:22 -08:00
|
|
|
NSRect cocoaPoints = DevPixelsToCocoaPoints(mClipRects[i]);
|
|
|
|
clipBounds.UnionRect(clipBounds, nsIntRect(NSToIntRound(cocoaPoints.origin.x),
|
|
|
|
NSToIntRound(cocoaPoints.origin.y),
|
|
|
|
NSToIntRound(cocoaPoints.size.width),
|
|
|
|
NSToIntRound(cocoaPoints.size.height)));
|
2009-07-21 17:44:55 -07:00
|
|
|
}
|
|
|
|
outClipRect.IntersectRect(outClipRect, clipBounds - outOrigin);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXXroc should this be !outClipRect.IsEmpty()?
|
2011-09-30 17:20:33 -07:00
|
|
|
outWidgetVisible = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
outClipRect.width = 0;
|
|
|
|
outClipRect.height = 0;
|
2011-09-30 17:20:33 -07:00
|
|
|
outWidgetVisible = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsChildView::StartDrawPlugin()
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2009-09-24 02:32:20 -07:00
|
|
|
NS_ASSERTION(mWindowType == eWindowType_plugin,
|
|
|
|
"StartDrawPlugin must only be called on a plugin widget");
|
|
|
|
if (mWindowType != eWindowType_plugin) return NS_ERROR_FAILURE;
|
2007-03-26 18:07:57 -07:00
|
|
|
|
2012-08-30 12:10:55 -07:00
|
|
|
// This code is necessary for CoreGraphics in 32-bit builds.
|
2009-08-31 18:00:13 -07:00
|
|
|
// See comments below about why. In 64-bit CoreGraphics mode we will not keep
|
|
|
|
// this region up to date, plugins should not depend on it.
|
|
|
|
#ifndef __LP64__
|
2009-09-15 14:56:44 -07:00
|
|
|
NSWindow* window = [mView window];
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window)
|
|
|
|
return NS_ERROR_FAILURE;
|
2009-08-26 17:29:47 -07:00
|
|
|
|
2012-08-30 12:10:55 -07:00
|
|
|
// In QuickDraw drawing mode we used to prevent reentrant handling of any
|
|
|
|
// plugin event. But in CoreGraphics drawing mode only do this if the current
|
2009-08-26 17:29:47 -07:00
|
|
|
// plugin event isn't an update/paint event. This allows popupcontextmenu()
|
|
|
|
// to work properly from a plugin that supports the Cocoa event model,
|
|
|
|
// without regressing bug 409615. See bug 435041. (StartDrawPlugin() and
|
|
|
|
// EndDrawPlugin() wrap every call to nsIPluginInstance::HandleEvent() --
|
|
|
|
// not just calls that "draw" or paint.)
|
2012-08-30 12:10:55 -07:00
|
|
|
if (mIsDispatchPaint && mPluginDrawing) {
|
|
|
|
return NS_ERROR_FAILURE;
|
2009-08-26 17:29:47 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// It appears that the WindowRef from which we get the plugin port undergoes the
|
|
|
|
// traditional BeginUpdate/EndUpdate cycle, which, if you recall, sets the visible
|
|
|
|
// region to the intersection of the visible region and the update region. Since
|
|
|
|
// we don't know here if we're being drawn inside a BeginUpdate/EndUpdate pair
|
|
|
|
// (which seem to occur in [NSWindow display]), and we don't want to have the burden
|
|
|
|
// of correctly doing Carbon invalidates of the plugin rect, we manually set the
|
2008-04-07 22:45:06 -07:00
|
|
|
// visible region to be the entire port every time. It is necessary to set up our
|
|
|
|
// window's port even for CoreGraphics plugins, because they may still use Carbon
|
|
|
|
// internally (see bug #420527 for details).
|
2011-06-11 00:12:58 -07:00
|
|
|
//
|
|
|
|
// Don't use this code if any of the QuickDraw APIs it currently requires are
|
|
|
|
// missing (as they probably will be on OS X 10.8 and up).
|
|
|
|
if (::NewRgn && ::GetQDGlobalsThePort && ::GetGWorld && ::SetGWorld &&
|
|
|
|
::IsPortOffscreen && ::GetMainDevice && ::SetOrigin && ::RectRgn &&
|
|
|
|
::SetPortVisibleRegion && ::SetPortClipRegion && ::DisposeRgn) {
|
|
|
|
RgnHandle pluginRegion = ::NewRgn();
|
|
|
|
if (pluginRegion) {
|
2012-08-30 12:10:55 -07:00
|
|
|
CGrafPtr port = ::GetWindowPort(WindowRef([window windowRef]));
|
2011-09-28 23:19:26 -07:00
|
|
|
bool portChanged = (port != CGrafPtr(::GetQDGlobalsThePort()));
|
2011-06-11 00:12:58 -07:00
|
|
|
CGrafPtr oldPort;
|
|
|
|
GDHandle oldDevice;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-06-11 00:12:58 -07:00
|
|
|
if (portChanged) {
|
|
|
|
::GetGWorld(&oldPort, &oldDevice);
|
2012-07-30 07:20:58 -07:00
|
|
|
::SetGWorld(port, ::IsPortOffscreen(port) ? nullptr : ::GetMainDevice());
|
2011-06-11 00:12:58 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-06-11 00:12:58 -07:00
|
|
|
::SetOrigin(0, 0);
|
|
|
|
|
|
|
|
nsIntRect clipRect; // this is in native window coordinates
|
|
|
|
nsIntPoint origin;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool visible;
|
2011-06-11 00:12:58 -07:00
|
|
|
GetPluginClipRect(clipRect, origin, visible);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-06-11 00:12:58 -07:00
|
|
|
// XXX if we're not visible, set an empty clip region?
|
|
|
|
Rect pluginRect;
|
|
|
|
ConvertGeckoRectToMacRect(clipRect, pluginRect);
|
|
|
|
|
|
|
|
::RectRgn(pluginRegion, &pluginRect);
|
|
|
|
::SetPortVisibleRegion(port, pluginRegion);
|
|
|
|
::SetPortClipRegion(port, pluginRegion);
|
|
|
|
|
|
|
|
// now set up the origin for the plugin
|
|
|
|
::SetOrigin(origin.x, origin.y);
|
|
|
|
|
|
|
|
::DisposeRgn(pluginRegion);
|
|
|
|
|
|
|
|
if (portChanged) {
|
|
|
|
::SetGWorld(oldPort, oldDevice);
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-08-31 18:00:13 -07:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-30 17:20:33 -07:00
|
|
|
mPluginDrawing = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsChildView::EndDrawPlugin()
|
|
|
|
{
|
2009-09-24 02:32:20 -07:00
|
|
|
NS_ASSERTION(mWindowType == eWindowType_plugin,
|
|
|
|
"EndDrawPlugin must only be called on a plugin widget");
|
|
|
|
if (mWindowType != eWindowType_plugin) return NS_ERROR_FAILURE;
|
2007-03-26 18:07:57 -07:00
|
|
|
|
2011-09-30 17:20:33 -07:00
|
|
|
mPluginDrawing = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-04-23 15:56:40 -07:00
|
|
|
NS_IMETHODIMP nsChildView::SetPluginInstanceOwner(nsIPluginInstanceOwner* aInstanceOwner)
|
|
|
|
{
|
|
|
|
mPluginInstanceOwner = aInstanceOwner;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
NS_IMETHODIMP nsChildView::SetPluginEventModel(int inEventModel)
|
|
|
|
{
|
2009-08-31 18:00:13 -07:00
|
|
|
[(ChildView*)mView setPluginEventModel:(NPEventModel)inEventModel];
|
2009-08-26 17:29:47 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsChildView::GetPluginEventModel(int* outEventModel)
|
|
|
|
{
|
2009-08-31 18:00:13 -07:00
|
|
|
*outEventModel = [(ChildView*)mView pluginEventModel];
|
2009-08-26 17:29:47 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-09-17 10:55:39 -07:00
|
|
|
NS_IMETHODIMP nsChildView::SetPluginDrawingModel(int inDrawingModel)
|
|
|
|
{
|
|
|
|
[(ChildView*)mView setPluginDrawingModel:(NPDrawingModel)inDrawingModel];
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-06-09 17:56:17 -07:00
|
|
|
NS_IMETHODIMP nsChildView::StartComplexTextInputForCurrentEvent()
|
|
|
|
{
|
2011-02-23 20:48:12 -08:00
|
|
|
return mTextInputHandler->StartComplexTextInputForCurrentEvent();
|
2010-06-09 17:56:17 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
nsresult nsChildView::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
|
|
|
|
int32_t aNativeKeyCode,
|
|
|
|
uint32_t aModifierFlags,
|
2008-05-06 22:17:40 -07:00
|
|
|
const nsAString& aCharacters,
|
|
|
|
const nsAString& aUnmodifiedCharacters)
|
2008-05-05 16:01:07 -07:00
|
|
|
{
|
2011-02-23 09:25:11 -08:00
|
|
|
return mTextInputHandler->SynthesizeNativeKeyEvent(aNativeKeyboardLayout,
|
|
|
|
aNativeKeyCode,
|
|
|
|
aModifierFlags,
|
|
|
|
aCharacters,
|
|
|
|
aUnmodifiedCharacters);
|
2008-05-05 16:01:07 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
nsresult nsChildView::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aNativeMessage,
|
|
|
|
uint32_t aModifierFlags)
|
2009-09-22 19:31:37 -07:00
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2013-03-06 09:16:44 -08:00
|
|
|
NSPoint pt =
|
|
|
|
nsCocoaUtils::DevPixelsToCocoaPoints(aPoint, BackingScaleFactor());
|
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
// Move the mouse cursor to the requested position and reconnect it to the mouse.
|
2013-03-06 09:16:44 -08:00
|
|
|
CGWarpMouseCursorPosition(NSPointToCGPoint(pt));
|
2009-09-22 19:31:37 -07:00
|
|
|
CGAssociateMouseAndMouseCursorPosition(true);
|
|
|
|
|
|
|
|
// aPoint is given with the origin on the top left, but convertScreenToBase
|
|
|
|
// expects a point in a coordinate system that has its origin on the bottom left.
|
2013-03-06 09:16:44 -08:00
|
|
|
NSPoint screenPoint = NSMakePoint(pt.x, nsCocoaUtils::FlippedScreenY(pt.y));
|
2009-09-22 19:31:37 -07:00
|
|
|
NSPoint windowPoint = [[mView window] convertScreenToBase:screenPoint];
|
|
|
|
|
2009-10-21 08:09:19 -07:00
|
|
|
NSEvent* event = [NSEvent mouseEventWithType:aNativeMessage
|
|
|
|
location:windowPoint
|
|
|
|
modifierFlags:aModifierFlags
|
|
|
|
timestamp:[NSDate timeIntervalSinceReferenceDate]
|
|
|
|
windowNumber:[[mView window] windowNumber]
|
|
|
|
context:nil
|
|
|
|
eventNumber:0
|
|
|
|
clickCount:1
|
|
|
|
pressure:0.0];
|
2009-09-22 19:31:37 -07:00
|
|
|
|
|
|
|
if (!event)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2011-08-08 07:43:13 -07:00
|
|
|
if ([[mView window] isKindOfClass:[BaseWindow class]]) {
|
|
|
|
// Tracking area events don't end up in their tracking areas when sent
|
|
|
|
// through [NSApp sendEvent:], so pass them directly to the right methods.
|
|
|
|
BaseWindow* window = (BaseWindow*)[mView window];
|
|
|
|
if (aNativeMessage == NSMouseEntered) {
|
|
|
|
[window mouseEntered:event];
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (aNativeMessage == NSMouseExited) {
|
|
|
|
[window mouseExited:event];
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (aNativeMessage == NSMouseMoved) {
|
|
|
|
[window mouseMoved:event];
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
[NSApp sendEvent:event];
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
}
|
|
|
|
|
2008-10-29 22:36:01 -07:00
|
|
|
// First argument has to be an NSMenu representing the application's top-level
|
|
|
|
// menu bar. The returned item is *not* retained.
|
|
|
|
static NSMenuItem* NativeMenuItemWithLocation(NSMenu* menubar, NSString* locationString)
|
|
|
|
{
|
|
|
|
NSArray* indexes = [locationString componentsSeparatedByString:@"|"];
|
2008-06-28 00:55:30 -07:00
|
|
|
unsigned int indexCount = [indexes count];
|
|
|
|
if (indexCount == 0)
|
2008-10-29 22:36:01 -07:00
|
|
|
return nil;
|
|
|
|
|
2008-06-28 00:55:30 -07:00
|
|
|
NSMenu* currentSubmenu = [NSApp mainMenu];
|
2008-10-29 22:36:01 -07:00
|
|
|
for (unsigned int i = 0; i < indexCount; i++) {
|
2008-06-28 00:55:30 -07:00
|
|
|
int targetIndex;
|
|
|
|
// We remove the application menu from consideration for the top-level menu
|
|
|
|
if (i == 0)
|
|
|
|
targetIndex = [[indexes objectAtIndex:i] intValue] + 1;
|
|
|
|
else
|
|
|
|
targetIndex = [[indexes objectAtIndex:i] intValue];
|
|
|
|
int itemCount = [currentSubmenu numberOfItems];
|
|
|
|
if (targetIndex < itemCount) {
|
|
|
|
NSMenuItem* menuItem = [currentSubmenu itemAtIndex:targetIndex];
|
2008-10-29 22:36:01 -07:00
|
|
|
// if this is the last index just return the menu item
|
|
|
|
if (i == (indexCount - 1))
|
|
|
|
return menuItem;
|
|
|
|
// if this is not the last index find the submenu and keep going
|
2008-06-28 00:55:30 -07:00
|
|
|
if ([menuItem hasSubmenu])
|
2008-10-29 22:36:01 -07:00
|
|
|
currentSubmenu = [menuItem submenu];
|
|
|
|
else
|
|
|
|
return nil;
|
2008-06-28 00:55:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-29 22:36:01 -07:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used for testing native menu system structure and event handling.
|
|
|
|
NS_IMETHODIMP nsChildView::ActivateNativeMenuItemAt(const nsAString& indexString)
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2013-10-10 09:59:40 -07:00
|
|
|
NSString* locationString = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(indexString.BeginReading())
|
|
|
|
length:indexString.Length()];
|
2008-10-29 22:36:01 -07:00
|
|
|
NSMenuItem* item = NativeMenuItemWithLocation([NSApp mainMenu], locationString);
|
2008-07-27 21:46:33 -07:00
|
|
|
// We can't perform an action on an item with a submenu, that will raise
|
|
|
|
// an obj-c exception.
|
2008-10-29 22:36:01 -07:00
|
|
|
if (item && ![item hasSubmenu]) {
|
|
|
|
NSMenu* parent = [item menu];
|
|
|
|
if (parent) {
|
2008-07-27 21:46:33 -07:00
|
|
|
// NSLog(@"Performing action for native menu item titled: %@\n",
|
|
|
|
// [[currentSubmenu itemAtIndex:targetIndex] title]);
|
2008-10-29 22:36:01 -07:00
|
|
|
[parent performActionForItemAtIndex:[parent indexOfItem:item]];
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2008-06-28 00:55:30 -07:00
|
|
|
}
|
2008-10-29 22:36:01 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
2008-07-27 21:46:33 -07:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
}
|
|
|
|
|
2008-10-29 22:36:01 -07:00
|
|
|
// Used for testing native menu system structure and event handling.
|
|
|
|
NS_IMETHODIMP nsChildView::ForceUpdateNativeMenuAt(const nsAString& indexString)
|
2008-07-27 21:46:33 -07:00
|
|
|
{
|
2008-10-29 22:36:01 -07:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2009-08-13 15:06:49 -07:00
|
|
|
nsCocoaWindow *widget = GetXULWindowWidget();
|
|
|
|
if (widget) {
|
|
|
|
nsMenuBarX* mb = widget->GetMenuBar();
|
|
|
|
if (mb) {
|
|
|
|
if (indexString.IsEmpty())
|
|
|
|
mb->ForceNativeMenuReload();
|
|
|
|
else
|
|
|
|
mb->ForceUpdateNativeMenuAt(indexString);
|
2008-07-27 21:46:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2008-10-29 22:36:01 -07:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2008-06-28 00:55:30 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
#ifdef INVALIDATE_DEBUGGING
|
|
|
|
|
|
|
|
static Boolean KeyDown(const UInt8 theKey)
|
|
|
|
{
|
|
|
|
KeyMap map;
|
|
|
|
GetKeys(map);
|
|
|
|
return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Boolean caps_lock()
|
|
|
|
{
|
|
|
|
return KeyDown(0x39);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void blinkRect(Rect* r)
|
|
|
|
{
|
|
|
|
StRegionFromPool oldClip;
|
|
|
|
if (oldClip != NULL)
|
|
|
|
::GetClip(oldClip);
|
|
|
|
|
|
|
|
::ClipRect(r);
|
|
|
|
::InvertRect(r);
|
|
|
|
UInt32 end = ::TickCount() + 5;
|
|
|
|
while (::TickCount() < end) ;
|
|
|
|
::InvertRect(r);
|
|
|
|
|
|
|
|
if (oldClip != NULL)
|
|
|
|
::SetClip(oldClip);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void blinkRgn(RgnHandle rgn)
|
|
|
|
{
|
|
|
|
StRegionFromPool oldClip;
|
|
|
|
if (oldClip != NULL)
|
|
|
|
::GetClip(oldClip);
|
|
|
|
|
|
|
|
::SetClip(rgn);
|
|
|
|
::InvertRgn(rgn);
|
|
|
|
UInt32 end = ::TickCount() + 5;
|
|
|
|
while (::TickCount() < end) ;
|
|
|
|
::InvertRgn(rgn);
|
|
|
|
|
|
|
|
if (oldClip != NULL)
|
|
|
|
::SetClip(oldClip);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Invalidate this component's visible area
|
2011-12-23 19:52:21 -08:00
|
|
|
NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!mView || !mVisible)
|
|
|
|
return NS_OK;
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
NS_ASSERTION(GetLayerManager()->GetBackendType() != LAYERS_CLIENT,
|
2013-06-18 00:59:00 -07:00
|
|
|
"Shouldn't need to invalidate with accelerated OMTC layers!");
|
|
|
|
|
2011-12-23 19:52:21 -08:00
|
|
|
if ([NSView focusView]) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
|
|
|
|
// don't lose it.
|
2012-09-29 04:36:09 -07:00
|
|
|
[mView setNeedsPendingDisplayInRect:DevPixelsToCocoaPoints(aRect)];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
else {
|
2012-09-29 04:36:09 -07:00
|
|
|
[mView setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2012-11-15 10:55:15 -08:00
|
|
|
nsChildView::ComputeShouldAccelerate(bool aDefault)
|
2010-09-29 11:38:39 -07:00
|
|
|
{
|
2011-02-08 04:42:06 -08:00
|
|
|
// Don't use OpenGL for transparent windows or for popup windows.
|
|
|
|
if (!mView || ![[mView window] isOpaque] ||
|
|
|
|
[[mView window] isKindOfClass:[PopupWindow class]])
|
2011-09-30 17:20:33 -07:00
|
|
|
return false;
|
2010-09-29 11:38:39 -07:00
|
|
|
|
2012-11-15 10:55:15 -08:00
|
|
|
return nsBaseWidget::ComputeShouldAccelerate(aDefault);
|
2010-09-29 11:38:39 -07:00
|
|
|
}
|
|
|
|
|
2012-06-13 12:53:11 -07:00
|
|
|
bool
|
2013-03-04 10:32:20 -08:00
|
|
|
nsChildView::ShouldUseOffMainThreadCompositing()
|
2012-06-13 12:53:11 -07:00
|
|
|
{
|
2013-08-19 00:13:32 -07:00
|
|
|
// Don't use OMTC for transparent windows or for popup windows.
|
2013-07-08 21:21:05 -07:00
|
|
|
if (!mView || ![[mView window] isOpaque] ||
|
|
|
|
[[mView window] isKindOfClass:[PopupWindow class]])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return nsBaseWidget::ShouldUseOffMainThreadCompositing();
|
2012-06-13 12:53:11 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
inline uint16_t COLOR8TOCOLOR16(uint8_t color8)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// return (color8 == 0xFF ? 0xFFFF : (color8 << 8));
|
|
|
|
return (color8 << 8) | color8; /* (color8 * 257) == (color8 * 0x0101) */
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
2009-07-21 17:44:55 -07:00
|
|
|
nsresult nsChildView::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
|
|
|
|
{
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
|
2010-10-10 17:58:21 -07:00
|
|
|
const Configuration& config = aConfigurations[i];
|
|
|
|
nsChildView* child = static_cast<nsChildView*>(config.mChild);
|
|
|
|
#ifdef DEBUG
|
|
|
|
nsWindowType kidType;
|
|
|
|
child->GetWindowType(kidType);
|
|
|
|
#endif
|
|
|
|
NS_ASSERTION(kidType == eWindowType_plugin,
|
|
|
|
"Configured widget is not a plugin type");
|
|
|
|
NS_ASSERTION(child->GetParent() == this,
|
|
|
|
"Configured widget is not a child of the right widget");
|
|
|
|
|
|
|
|
// nsIWidget::Show() doesn't get called on plugin widgets unless we call
|
|
|
|
// it from here. See bug 592563.
|
|
|
|
child->Show(!config.mClipRegion.IsEmpty());
|
|
|
|
|
|
|
|
child->Resize(
|
|
|
|
config.mBounds.x, config.mBounds.y,
|
|
|
|
config.mBounds.width, config.mBounds.height,
|
2012-08-30 12:10:55 -07:00
|
|
|
false);
|
2010-10-10 17:58:21 -07:00
|
|
|
|
|
|
|
// Store the clip region here in case GetPluginClipRect needs it.
|
|
|
|
child->StoreWindowClipRegion(config.mClipRegion);
|
2009-07-21 17:44:55 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
2010-10-10 17:58:21 -07:00
|
|
|
}
|
2009-07-21 17:44:55 -07:00
|
|
|
|
2007-09-19 15:15:48 -07:00
|
|
|
// Invokes callback and ProcessEvent methods on Event Listener object
|
2013-10-01 20:46:03 -07:00
|
|
|
NS_IMETHODIMP nsChildView::DispatchEvent(WidgetGUIEvent* event,
|
|
|
|
nsEventStatus& aStatus)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-03-12 15:44:45 -07:00
|
|
|
#ifdef DEBUG
|
2012-09-01 19:35:17 -07:00
|
|
|
debug_DumpEvent(stdout, event->widget, event, nsAutoCString("something"), 0);
|
2008-03-12 15:44:45 -07:00
|
|
|
#endif
|
|
|
|
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ASSERTION(!(mTextInputHandler && mTextInputHandler->IsIMEComposing() &&
|
2013-09-24 03:04:16 -07:00
|
|
|
event->HasKeyEventMessage()),
|
2008-12-06 01:23:55 -08:00
|
|
|
"Any key events should not be fired during IME composing");
|
|
|
|
|
2013-10-17 23:10:24 -07:00
|
|
|
if (event->mFlags.mIsSynthesizedForTests) {
|
|
|
|
WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
|
|
|
|
if (keyEvent) {
|
|
|
|
nsresult rv = mTextInputHandler->AttachNativeKeyEvent(*keyEvent);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2013-07-10 07:12:40 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
aStatus = nsEventStatus_eIgnore;
|
|
|
|
|
2012-08-15 11:53:09 -07:00
|
|
|
nsIWidgetListener* listener = mWidgetListener;
|
|
|
|
|
|
|
|
// If the listener is NULL, check if the parent is a popup. If it is, then
|
|
|
|
// this child is the popup content view attached to a popup. Get the
|
|
|
|
// listener from the parent popup instead.
|
2009-07-01 11:41:34 -07:00
|
|
|
nsCOMPtr<nsIWidget> kungFuDeathGrip = do_QueryInterface(mParentWidget ? mParentWidget : this);
|
2012-08-15 11:53:09 -07:00
|
|
|
if (!listener && mParentWidget) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsWindowType type;
|
|
|
|
mParentWidget->GetWindowType(type);
|
|
|
|
if (type == eWindowType_popup) {
|
2012-08-15 11:53:09 -07:00
|
|
|
// Check just in case event->widget isn't this widget
|
2007-08-02 11:43:31 -07:00
|
|
|
if (event->widget)
|
2012-08-15 11:52:42 -07:00
|
|
|
listener = event->widget->GetWidgetListener();
|
2012-08-15 11:53:09 -07:00
|
|
|
if (!listener) {
|
2007-08-02 11:43:31 -07:00
|
|
|
event->widget = mParentWidget;
|
2012-08-15 11:53:09 -07:00
|
|
|
listener = mParentWidget->GetWidgetListener();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2007-09-20 01:56:42 -07:00
|
|
|
|
2012-08-15 11:53:09 -07:00
|
|
|
if (listener)
|
|
|
|
aStatus = listener->HandleEvent(event, mUseAttachedEvents);
|
2007-09-20 01:56:42 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-10-01 20:46:03 -07:00
|
|
|
bool nsChildView::DispatchWindowEvent(WidgetGUIEvent& event)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&event, status);
|
|
|
|
return ConvertStatus(status);
|
|
|
|
}
|
|
|
|
|
2013-02-25 13:18:48 -08:00
|
|
|
nsIWidget*
|
|
|
|
nsChildView::GetWidgetForListenerEvents()
|
2012-08-15 11:52:42 -07:00
|
|
|
{
|
|
|
|
// If there is no listener, use the parent popup's listener if that exists.
|
2013-01-28 11:34:03 -08:00
|
|
|
if (!mWidgetListener && mParentWidget) {
|
2012-08-15 11:52:42 -07:00
|
|
|
nsWindowType type;
|
|
|
|
mParentWidget->GetWindowType(type);
|
|
|
|
if (type == eWindowType_popup) {
|
2013-02-25 13:18:48 -08:00
|
|
|
return mParentWidget;
|
2012-08-15 11:52:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-25 13:18:48 -08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsChildView::WillPaintWindow()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIWidget> widget = GetWidgetForListenerEvents();
|
|
|
|
|
|
|
|
nsIWidgetListener* listener = widget->GetWidgetListener();
|
|
|
|
if (listener) {
|
|
|
|
listener->WillPaintWindow(widget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-23 07:49:16 -07:00
|
|
|
bool nsChildView::PaintWindow(nsIntRegion aRegion)
|
2013-02-25 13:18:48 -08:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIWidget> widget = GetWidgetForListenerEvents();
|
|
|
|
|
2013-01-28 11:34:03 -08:00
|
|
|
nsIWidgetListener* listener = widget->GetWidgetListener();
|
2012-08-15 11:52:42 -07:00
|
|
|
if (!listener)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool returnValue = false;
|
|
|
|
bool oldDispatchPaint = mIsDispatchPaint;
|
|
|
|
mIsDispatchPaint = true;
|
2013-05-23 07:49:18 -07:00
|
|
|
returnValue = listener->PaintWindow(widget, aRegion);
|
2013-01-28 11:34:03 -08:00
|
|
|
|
|
|
|
listener = widget->GetWidgetListener();
|
|
|
|
if (listener) {
|
|
|
|
listener->DidPaintWindow();
|
|
|
|
}
|
|
|
|
|
2012-08-15 11:52:42 -07:00
|
|
|
mIsDispatchPaint = oldDispatchPaint;
|
|
|
|
return returnValue;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
2012-08-15 11:52:42 -07:00
|
|
|
void nsChildView::ReportMoveEvent()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-08-15 11:52:42 -07:00
|
|
|
if (mWidgetListener)
|
|
|
|
mWidgetListener->WindowMoved(this, mBounds.x, mBounds.y);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-08-15 11:52:42 -07:00
|
|
|
void nsChildView::ReportSizeEvent()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-08-15 11:52:42 -07:00
|
|
|
if (mWidgetListener)
|
|
|
|
mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
2009-02-18 16:11:49 -08:00
|
|
|
// Return the offset between this child view and the screen.
|
2012-09-29 04:36:09 -07:00
|
|
|
// @return -- widget origin in device-pixel coords
|
2009-02-18 16:11:49 -08:00
|
|
|
nsIntPoint nsChildView::WidgetToScreenOffset()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-02-18 16:11:49 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2012-09-29 04:36:09 -07:00
|
|
|
NSPoint origin = NSMakePoint(0, 0);
|
|
|
|
|
|
|
|
// 1. First translate view origin point into window coords.
|
|
|
|
// The returned point is in bottom-left coordinates.
|
|
|
|
origin = [mView convertPoint:origin toView:nil];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// 2. We turn the window-coord rect's origin into screen (still bottom-left) coords.
|
2012-09-29 04:36:09 -07:00
|
|
|
origin = [[mView window] convertBaseToScreen:origin];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// 3. Since we're dealing in bottom-left coords, we need to make it top-left coords
|
|
|
|
// before we pass it back to Gecko.
|
2012-09-29 04:36:09 -07:00
|
|
|
FlipCocoaScreenCoordinate(origin);
|
|
|
|
|
|
|
|
// convert to device pixels
|
|
|
|
return CocoaPointsToDevPixels(origin);
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2009-02-18 16:11:49 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nsIntPoint(0,0));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-10-26 06:15:22 -07:00
|
|
|
NS_IMETHODIMP nsChildView::CaptureRollupEvents(nsIRollupListener * aListener,
|
|
|
|
bool aDoCapture)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// this never gets called, only top-level windows can be rollup widgets
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsChildView::SetTitle(const nsAString& title)
|
|
|
|
{
|
2007-07-18 17:56:33 -07:00
|
|
|
// child views don't have titles
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
NS_IMETHODIMP nsChildView::GetAttention(int32_t aCycleCount)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
[NSApp requestUserAttention:NSInformationalRequest];
|
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-04-21 16:53:52 -07:00
|
|
|
/* static */
|
2011-09-28 23:19:26 -07:00
|
|
|
bool nsChildView::DoHasPendingInputEvent()
|
2009-04-21 16:53:52 -07:00
|
|
|
{
|
|
|
|
return sLastInputEventCount != GetCurrentInputEventCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t nsChildView::GetCurrentInputEventCount()
|
2009-04-21 16:53:52 -07:00
|
|
|
{
|
|
|
|
// Can't use kCGAnyInputEventType because that updates too rarely for us (and
|
|
|
|
// always in increments of 30+!) and because apparently it's sort of broken
|
|
|
|
// on Tiger. So just go ahead and query the counters we care about.
|
|
|
|
static const CGEventType eventTypes[] = {
|
|
|
|
kCGEventLeftMouseDown,
|
|
|
|
kCGEventLeftMouseUp,
|
|
|
|
kCGEventRightMouseDown,
|
|
|
|
kCGEventRightMouseUp,
|
|
|
|
kCGEventMouseMoved,
|
|
|
|
kCGEventLeftMouseDragged,
|
|
|
|
kCGEventRightMouseDragged,
|
|
|
|
kCGEventKeyDown,
|
|
|
|
kCGEventKeyUp,
|
|
|
|
kCGEventScrollWheel,
|
|
|
|
kCGEventTabletPointer,
|
|
|
|
kCGEventOtherMouseDown,
|
|
|
|
kCGEventOtherMouseUp,
|
|
|
|
kCGEventOtherMouseDragged
|
|
|
|
};
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t eventCount = 0;
|
|
|
|
for (uint32_t i = 0; i < ArrayLength(eventTypes); ++i) {
|
2009-04-21 16:53:52 -07:00
|
|
|
eventCount +=
|
|
|
|
CGEventSourceCounterForEventType(kCGEventSourceStateCombinedSessionState,
|
|
|
|
eventTypes[i]);
|
|
|
|
}
|
|
|
|
return eventCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
void nsChildView::UpdateCurrentInputEventCount()
|
|
|
|
{
|
|
|
|
sLastInputEventCount = GetCurrentInputEventCount();
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool nsChildView::HasPendingInputEvent()
|
2009-04-21 16:53:52 -07:00
|
|
|
{
|
|
|
|
return DoHasPendingInputEvent();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
2013-03-05 22:14:34 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsChildView::NotifyIME(NotificationToIME aNotification)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-03-05 22:14:34 -08:00
|
|
|
switch (aNotification) {
|
|
|
|
case REQUEST_TO_COMMIT_COMPOSITION:
|
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
mTextInputHandler->CommitIMEComposition();
|
|
|
|
return NS_OK;
|
|
|
|
case REQUEST_TO_CANCEL_COMPOSITION:
|
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
mTextInputHandler->CancelIMEComposition();
|
|
|
|
return NS_OK;
|
|
|
|
case NOTIFY_IME_OF_FOCUS:
|
2013-05-24 09:27:52 -07:00
|
|
|
if (mInputContext.IsPasswordEditor()) {
|
|
|
|
TextInputHandler::EnableSecureEventInput();
|
|
|
|
}
|
|
|
|
|
2013-03-05 22:14:34 -08:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
mTextInputHandler->OnFocusChangeInGecko(true);
|
|
|
|
return NS_OK;
|
|
|
|
case NOTIFY_IME_OF_BLUR:
|
2013-05-24 09:27:52 -07:00
|
|
|
// When we're going to be deactive, we must disable the secure event input
|
|
|
|
// mode, see the Carbon Event Manager Reference.
|
|
|
|
TextInputHandler::EnsureSecureEventInputDisabled();
|
|
|
|
|
2013-03-05 22:14:34 -08:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
mTextInputHandler->OnFocusChangeInGecko(false);
|
|
|
|
return NS_OK;
|
2013-07-11 00:46:35 -07:00
|
|
|
case NOTIFY_IME_OF_SELECTION_CHANGE:
|
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
mTextInputHandler->OnSelectionChange();
|
2013-03-05 22:14:34 -08:00
|
|
|
default:
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-11-27 03:51:52 -08:00
|
|
|
NS_IMETHODIMP_(void)
|
|
|
|
nsChildView::SetInputContext(const InputContext& aContext,
|
|
|
|
const InputContextAction& aAction)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-08-06 19:49:21 -07:00
|
|
|
NS_ENSURE_TRUE_VOID(mTextInputHandler);
|
|
|
|
|
|
|
|
if (mTextInputHandler->IsFocused()) {
|
|
|
|
if (aContext.IsPasswordEditor()) {
|
|
|
|
TextInputHandler::EnableSecureEventInput();
|
|
|
|
} else {
|
|
|
|
TextInputHandler::EnsureSecureEventInputDisabled();
|
|
|
|
}
|
2013-05-24 09:27:52 -07:00
|
|
|
}
|
|
|
|
|
2011-11-27 03:51:52 -08:00
|
|
|
mInputContext = aContext;
|
2011-11-27 03:51:53 -08:00
|
|
|
switch (aContext.mIMEState.mEnabled) {
|
|
|
|
case IMEState::ENABLED:
|
|
|
|
case IMEState::PLUGIN:
|
2011-09-30 17:20:33 -07:00
|
|
|
mTextInputHandler->SetASCIICapableOnly(false);
|
|
|
|
mTextInputHandler->EnableIME(true);
|
2011-11-27 03:51:53 -08:00
|
|
|
if (mInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE) {
|
|
|
|
mTextInputHandler->SetIMEOpenState(
|
|
|
|
mInputContext.mIMEState.mOpen == IMEState::OPEN);
|
|
|
|
}
|
2007-04-15 06:43:55 -07:00
|
|
|
break;
|
2011-11-27 03:51:53 -08:00
|
|
|
case IMEState::DISABLED:
|
2011-09-30 17:20:33 -07:00
|
|
|
mTextInputHandler->SetASCIICapableOnly(false);
|
|
|
|
mTextInputHandler->EnableIME(false);
|
2007-04-15 06:43:55 -07:00
|
|
|
break;
|
2011-11-27 03:51:53 -08:00
|
|
|
case IMEState::PASSWORD:
|
2011-09-30 17:20:33 -07:00
|
|
|
mTextInputHandler->SetASCIICapableOnly(true);
|
|
|
|
mTextInputHandler->EnableIME(false);
|
2007-04-15 06:43:55 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NS_ERROR("not implemented!");
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-11-27 03:51:52 -08:00
|
|
|
NS_IMETHODIMP_(InputContext)
|
|
|
|
nsChildView::GetInputContext()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-11-27 03:51:53 -08:00
|
|
|
switch (mInputContext.mIMEState.mEnabled) {
|
|
|
|
case IMEState::ENABLED:
|
|
|
|
case IMEState::PLUGIN:
|
|
|
|
if (mTextInputHandler) {
|
|
|
|
mInputContext.mIMEState.mOpen =
|
|
|
|
mTextInputHandler->IsIMEOpened() ? IMEState::OPEN : IMEState::CLOSED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// If mTextInputHandler is null, set CLOSED instead...
|
|
|
|
default:
|
|
|
|
mInputContext.mIMEState.mOpen = IMEState::CLOSED;
|
|
|
|
break;
|
|
|
|
}
|
2012-10-26 16:35:21 -07:00
|
|
|
mInputContext.mNativeIMEContext = [mView inputContext];
|
|
|
|
// If input context isn't available on this widget, we should set |this|
|
|
|
|
// instead of nullptr since nullptr means that the platform has only one
|
|
|
|
// context per process.
|
|
|
|
if (!mInputContext.mNativeIMEContext) {
|
|
|
|
mInputContext.mNativeIMEContext = this;
|
|
|
|
}
|
2011-11-27 03:51:52 -08:00
|
|
|
return mInputContext;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-07-11 00:46:35 -07:00
|
|
|
nsIMEUpdatePreference
|
|
|
|
nsChildView::GetIMEUpdatePreference()
|
|
|
|
{
|
|
|
|
return nsIMEUpdatePreference(nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
NS_IMETHODIMP nsChildView::GetToggledKeyState(uint32_t aKeyCode,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool* aLEDState)
|
2007-06-16 12:19:46 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2007-06-16 12:19:46 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(aLEDState);
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t key;
|
2007-06-16 12:19:46 -07:00
|
|
|
switch (aKeyCode) {
|
|
|
|
case NS_VK_CAPS_LOCK:
|
|
|
|
key = alphaLock;
|
|
|
|
break;
|
|
|
|
case NS_VK_NUM_LOCK:
|
|
|
|
key = kEventKeyModifierNumLockMask;
|
|
|
|
break;
|
|
|
|
// Mac doesn't support SCROLL_LOCK state.
|
|
|
|
default:
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t modifierFlags = ::GetCurrentKeyModifiers();
|
2007-06-16 12:19:46 -07:00
|
|
|
*aLEDState = (modifierFlags & key) != 0;
|
|
|
|
return NS_OK;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-06-16 12:19:46 -07:00
|
|
|
}
|
|
|
|
|
2009-09-30 19:52:50 -07:00
|
|
|
NSView<mozView>* nsChildView::GetEditorView()
|
|
|
|
{
|
|
|
|
NSView<mozView>* editorView = mView;
|
|
|
|
// We need to get editor's view. E.g., when the focus is in the bookmark
|
|
|
|
// dialog, the view is <panel> element of the dialog. At this time, the key
|
|
|
|
// events are processed the parent window's view that has native focus.
|
2013-10-01 00:23:00 -07:00
|
|
|
WidgetQueryContentEvent textContent(true, NS_QUERY_TEXT_CONTENT, this);
|
2009-09-30 19:52:50 -07:00
|
|
|
textContent.InitForQueryTextContent(0, 0);
|
|
|
|
DispatchWindowEvent(textContent);
|
|
|
|
if (textContent.mSucceeded && textContent.mReply.mFocusedWidget) {
|
|
|
|
NSView<mozView>* view = static_cast<NSView<mozView>*>(
|
|
|
|
textContent.mReply.mFocusedWidget->GetNativeData(NS_NATIVE_WIDGET));
|
|
|
|
if (view)
|
|
|
|
editorView = view;
|
|
|
|
}
|
|
|
|
return editorView;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
2012-01-19 06:45:37 -08:00
|
|
|
void
|
|
|
|
nsChildView::CreateCompositor()
|
|
|
|
{
|
|
|
|
nsBaseWidget::CreateCompositor();
|
|
|
|
if (mCompositorChild) {
|
|
|
|
[(ChildView *)mView setUsingOMTCompositor:true];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
gfxASurface*
|
|
|
|
nsChildView::GetThebesSurface()
|
|
|
|
{
|
|
|
|
if (!mTempThebesSurface) {
|
2013-09-24 13:45:13 -07:00
|
|
|
mTempThebesSurface = new gfxQuartzSurface(gfxSize(1, 1), gfxImageFormatARGB32);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-16 23:52:35 -07:00
|
|
|
return mTempThebesSurface;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
void
|
|
|
|
nsChildView::NotifyDirtyRegion(const nsIntRegion& aDirtyRegion)
|
|
|
|
{
|
|
|
|
if ([(ChildView*)mView isCoveringTitlebar]) {
|
|
|
|
// We store the dirty region so that we know what to repaint in the titlebar.
|
|
|
|
mDirtyTitlebarRegion.Or(mDirtyTitlebarRegion, aDirtyRegion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const CGFloat kTitlebarHighlightHeight = 6;
|
|
|
|
|
|
|
|
nsIntRect
|
|
|
|
nsChildView::RectContainingTitlebarControls()
|
|
|
|
{
|
|
|
|
// Start with a 6px high strip at the top of the window for the highlight line.
|
|
|
|
NSRect rect = NSMakeRect(0, 0, [mView bounds].size.width,
|
|
|
|
kTitlebarHighlightHeight);
|
|
|
|
|
|
|
|
// Add the rects of the titlebar controls.
|
|
|
|
for (id view in [(BaseWindow*)[mView window] titlebarControls]) {
|
|
|
|
rect = NSUnionRect(rect, [mView convertRect:[view bounds] fromView:view]);
|
|
|
|
}
|
|
|
|
return CocoaPointsToDevPixels(rect);
|
|
|
|
}
|
|
|
|
|
2013-04-21 19:40:51 -07:00
|
|
|
void
|
|
|
|
nsChildView::PrepareWindowEffects()
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mEffectsLock);
|
|
|
|
mShowsResizeIndicator = ShowsResizeIndicator(&mResizeIndicatorRect);
|
2013-05-23 07:49:17 -07:00
|
|
|
mHasRoundedBottomCorners = [(ChildView*)mView hasRoundedBottomCorners];
|
|
|
|
CGFloat cornerRadius = [(ChildView*)mView cornerRadius];
|
2013-04-21 19:40:51 -07:00
|
|
|
mDevPixelCornerRadius = cornerRadius * BackingScaleFactor();
|
2013-05-23 07:49:17 -07:00
|
|
|
mIsCoveringTitlebar = [(ChildView*)mView isCoveringTitlebar];
|
|
|
|
if (mIsCoveringTitlebar) {
|
|
|
|
mTitlebarRect = RectContainingTitlebarControls();
|
2013-11-26 21:49:45 -08:00
|
|
|
UpdateTitlebarCGContext();
|
2013-05-23 07:49:17 -07:00
|
|
|
}
|
2013-04-21 19:40:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsChildView::CleanupWindowEffects()
|
|
|
|
{
|
|
|
|
mResizerImage = nullptr;
|
|
|
|
mCornerMaskImage = nullptr;
|
2013-05-23 07:49:17 -07:00
|
|
|
mTitlebarImage = nullptr;
|
2013-04-21 19:40:51 -07:00
|
|
|
}
|
|
|
|
|
2013-10-09 07:39:22 -07:00
|
|
|
bool
|
2013-10-09 11:33:01 -07:00
|
|
|
nsChildView::PreRender(LayerManager* aManager)
|
2013-10-09 07:39:23 -07:00
|
|
|
{
|
|
|
|
nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager));
|
|
|
|
if (!manager) {
|
2013-10-09 07:39:22 -07:00
|
|
|
return true;
|
2013-10-09 07:39:23 -07:00
|
|
|
}
|
2013-10-09 07:39:23 -07:00
|
|
|
|
|
|
|
// The lock makes sure that we don't attempt to tear down the view while
|
|
|
|
// compositing. That would make us unable to call postRender on it when the
|
|
|
|
// composition is done, thus keeping the GL context locked forever.
|
|
|
|
mViewTearDownLock.Lock();
|
|
|
|
|
2013-10-09 07:39:23 -07:00
|
|
|
NSOpenGLContext *glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(GLContext::NativeGLContext);
|
2013-10-09 07:39:23 -07:00
|
|
|
|
|
|
|
if (![(ChildView*)mView preRender:glContext]) {
|
|
|
|
mViewTearDownLock.Unlock();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2013-10-09 07:39:23 -07:00
|
|
|
}
|
|
|
|
|
2013-10-09 07:39:23 -07:00
|
|
|
void
|
|
|
|
nsChildView::PostRender(LayerManager* aManager)
|
|
|
|
{
|
|
|
|
nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager));
|
|
|
|
if (!manager) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NSOpenGLContext *glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(GLContext::NativeGLContext);
|
|
|
|
[(ChildView*)mView postRender:glContext];
|
2013-10-09 07:39:23 -07:00
|
|
|
mViewTearDownLock.Unlock();
|
2013-10-09 07:39:23 -07:00
|
|
|
}
|
|
|
|
|
2013-03-27 08:49:02 -07:00
|
|
|
void
|
|
|
|
nsChildView::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
|
|
|
|
{
|
2013-04-30 17:42:05 -07:00
|
|
|
nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager));
|
2013-07-08 21:21:05 -07:00
|
|
|
if (manager) {
|
|
|
|
DrawWindowOverlay(manager, aRect);
|
2013-03-27 08:49:02 -07:00
|
|
|
}
|
2013-07-08 21:21:05 -07:00
|
|
|
}
|
2013-03-27 08:49:02 -07:00
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
void
|
|
|
|
nsChildView::DrawWindowOverlay(GLManager* aManager, nsIntRect aRect)
|
|
|
|
{
|
|
|
|
MaybeDrawTitlebar(aManager, aRect);
|
|
|
|
MaybeDrawResizeIndicator(aManager, aRect);
|
|
|
|
MaybeDrawRoundedCorners(aManager, aRect);
|
2013-05-23 07:49:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-07-08 21:21:05 -07:00
|
|
|
ClearRegion(gfx::DrawTarget *aDT, nsIntRegion aRegion)
|
2013-05-23 07:49:17 -07:00
|
|
|
{
|
2013-07-08 21:21:05 -07:00
|
|
|
gfxUtils::ClipToRegion(aDT, aRegion);
|
|
|
|
aDT->ClearRect(gfx::Rect(0, 0, aDT->GetSize().width, aDT->GetSize().height));
|
|
|
|
aDT->PopClip();
|
2013-03-27 08:49:02 -07:00
|
|
|
}
|
|
|
|
|
2011-02-19 14:23:02 -08:00
|
|
|
static void
|
|
|
|
DrawResizer(CGContextRef aCtx)
|
2011-01-07 12:32:42 -08:00
|
|
|
{
|
2011-02-19 14:23:02 -08:00
|
|
|
CGContextSetShouldAntialias(aCtx, false);
|
2011-02-19 14:22:12 -08:00
|
|
|
CGPoint points[6];
|
|
|
|
points[0] = CGPointMake(13.0f, 4.0f);
|
|
|
|
points[1] = CGPointMake(3.0f, 14.0f);
|
|
|
|
points[2] = CGPointMake(13.0f, 8.0f);
|
|
|
|
points[3] = CGPointMake(7.0f, 14.0f);
|
|
|
|
points[4] = CGPointMake(13.0f, 12.0f);
|
|
|
|
points[5] = CGPointMake(11.0f, 14.0f);
|
2011-02-19 14:23:02 -08:00
|
|
|
CGContextSetRGBStrokeColor(aCtx, 0.00f, 0.00f, 0.00f, 0.15f);
|
|
|
|
CGContextStrokeLineSegments(aCtx, points, 6);
|
2011-02-19 14:22:12 -08:00
|
|
|
|
|
|
|
points[0] = CGPointMake(13.0f, 5.0f);
|
|
|
|
points[1] = CGPointMake(4.0f, 14.0f);
|
|
|
|
points[2] = CGPointMake(13.0f, 9.0f);
|
|
|
|
points[3] = CGPointMake(8.0f, 14.0f);
|
|
|
|
points[4] = CGPointMake(13.0f, 13.0f);
|
|
|
|
points[5] = CGPointMake(12.0f, 14.0f);
|
2011-02-19 14:23:02 -08:00
|
|
|
CGContextSetRGBStrokeColor(aCtx, 0.13f, 0.13f, 0.13f, 0.54f);
|
|
|
|
CGContextStrokeLineSegments(aCtx, points, 6);
|
2011-02-19 14:22:12 -08:00
|
|
|
|
|
|
|
points[0] = CGPointMake(13.0f, 6.0f);
|
|
|
|
points[1] = CGPointMake(5.0f, 14.0f);
|
|
|
|
points[2] = CGPointMake(13.0f, 10.0f);
|
|
|
|
points[3] = CGPointMake(9.0f, 14.0f);
|
|
|
|
points[5] = CGPointMake(13.0f, 13.9f);
|
|
|
|
points[4] = CGPointMake(13.0f, 14.0f);
|
2011-02-19 14:23:02 -08:00
|
|
|
CGContextSetRGBStrokeColor(aCtx, 0.84f, 0.84f, 0.84f, 0.55f);
|
|
|
|
CGContextStrokeLineSegments(aCtx, points, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-05-23 07:49:17 -07:00
|
|
|
nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, const nsIntRect& aRect)
|
2011-02-19 14:23:02 -08:00
|
|
|
{
|
2013-05-23 07:49:17 -07:00
|
|
|
MutexAutoLock lock(mEffectsLock);
|
2013-07-08 21:21:05 -07:00
|
|
|
if (!mShowsResizeIndicator) {
|
2011-02-19 14:23:02 -08:00
|
|
|
return;
|
|
|
|
}
|
2011-02-19 14:22:12 -08:00
|
|
|
|
2011-02-19 14:23:02 -08:00
|
|
|
if (!mResizerImage) {
|
2013-07-08 21:21:05 -07:00
|
|
|
mResizerImage = new RectTextureImage(aManager->gl());
|
2011-02-19 14:23:02 -08:00
|
|
|
}
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
nsIntSize size = mResizeIndicatorRect.Size();
|
|
|
|
mResizerImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
|
|
|
|
ClearRegion(drawTarget, updateRegion);
|
2013-07-12 14:19:29 -07:00
|
|
|
gfx::BorrowedCGContext borrow(drawTarget);
|
|
|
|
DrawResizer(borrow.cg);
|
|
|
|
borrow.Finish();
|
2013-07-08 21:21:05 -07:00
|
|
|
});
|
2011-02-19 14:23:02 -08:00
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
mResizerImage->Draw(aManager, mResizeIndicatorRect.TopLeft());
|
2013-03-27 08:49:02 -07:00
|
|
|
}
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
// Draw the highlight line at the top of the titlebar.
|
|
|
|
// This function draws into the current NSGraphicsContext and assumes flippedness.
|
|
|
|
static void
|
|
|
|
DrawTitlebarHighlight(NSSize aWindowSize, CGFloat aRadius, CGFloat aDevicePixelWidth)
|
|
|
|
{
|
|
|
|
[NSGraphicsContext saveGraphicsState];
|
|
|
|
|
|
|
|
// Set up the clip path. We start with the outer rectangle and cut out a
|
|
|
|
// slightly smaller inner rectangle with rounded corners.
|
|
|
|
// The outer corners of the resulting path will be square, but they will be
|
|
|
|
// masked away in a later step.
|
|
|
|
NSBezierPath* path = [NSBezierPath bezierPath];
|
|
|
|
[path setWindingRule:NSEvenOddWindingRule];
|
|
|
|
NSRect pathRect = NSMakeRect(0, 0, aWindowSize.width, kTitlebarHighlightHeight + 2);
|
|
|
|
[path appendBezierPathWithRect:pathRect];
|
|
|
|
pathRect = NSInsetRect(pathRect, aDevicePixelWidth, aDevicePixelWidth);
|
|
|
|
CGFloat innerRadius = aRadius - aDevicePixelWidth;
|
|
|
|
[path appendBezierPathWithRoundedRect:pathRect xRadius:innerRadius yRadius:innerRadius];
|
|
|
|
[path addClip];
|
|
|
|
|
|
|
|
// Now we fill the path with a subtle highlight gradient.
|
|
|
|
NSColor* topColor = [NSColor colorWithDeviceWhite:1.0 alpha:0.4];
|
|
|
|
NSColor* bottomColor = [NSColor colorWithDeviceWhite:1.0 alpha:0.0];
|
|
|
|
NSGradient* gradient = [[NSGradient alloc] initWithStartingColor:topColor endingColor:bottomColor];
|
|
|
|
[gradient drawInRect:NSMakeRect(0, 0, aWindowSize.width, kTitlebarHighlightHeight) angle:90];
|
|
|
|
[gradient release];
|
|
|
|
|
|
|
|
[NSGraphicsContext restoreGraphicsState];
|
|
|
|
}
|
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
static CGContextRef
|
|
|
|
CreateCGContext(const nsIntSize& aSize)
|
|
|
|
{
|
|
|
|
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
|
|
|
|
CGContextRef ctx =
|
|
|
|
CGBitmapContextCreate(NULL,
|
|
|
|
aSize.width,
|
|
|
|
aSize.height,
|
|
|
|
8 /* bitsPerComponent */,
|
|
|
|
aSize.width * 4,
|
|
|
|
cs,
|
|
|
|
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
|
|
|
|
CGColorSpaceRelease(cs);
|
|
|
|
|
|
|
|
CGContextTranslateCTM(ctx, 0, aSize.height);
|
|
|
|
CGContextScaleCTM(ctx, 1, -1);
|
|
|
|
CGContextSetInterpolationQuality(ctx, kCGInterpolationLow);
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
// When this method is entered, mEffectsLock is already being held.
|
|
|
|
void
|
2013-11-26 21:49:45 -08:00
|
|
|
nsChildView::UpdateTitlebarCGContext()
|
2013-05-23 07:49:17 -07:00
|
|
|
{
|
2013-11-25 09:59:28 -08:00
|
|
|
nsIntRegion dirtyTitlebarRegion;
|
|
|
|
dirtyTitlebarRegion.And(mDirtyTitlebarRegion, mTitlebarRect);
|
2013-05-23 07:49:17 -07:00
|
|
|
mDirtyTitlebarRegion.SetEmpty();
|
|
|
|
|
2013-07-08 21:21:06 -07:00
|
|
|
nsIntSize texSize = RectTextureImage::TextureSizeForSize(mTitlebarRect.Size());
|
2013-11-26 21:49:45 -08:00
|
|
|
if (!mTitlebarCGContext ||
|
|
|
|
CGBitmapContextGetWidth(mTitlebarCGContext) != size_t(texSize.width) ||
|
|
|
|
CGBitmapContextGetHeight(mTitlebarCGContext) != size_t(texSize.height)) {
|
2013-05-23 07:49:17 -07:00
|
|
|
dirtyTitlebarRegion = mTitlebarRect;
|
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
ReleaseTitlebarCGContext();
|
|
|
|
|
|
|
|
mTitlebarCGContext = CreateCGContext(texSize);
|
2013-05-23 07:49:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dirtyTitlebarRegion.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
CGContextRef ctx = mTitlebarCGContext;
|
2013-05-23 07:49:17 -07:00
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
CGContextSaveGState(ctx);
|
|
|
|
|
|
|
|
std::vector<CGRect> rects;
|
|
|
|
nsIntRegionRectIterator iter(dirtyTitlebarRegion);
|
|
|
|
for (;;) {
|
|
|
|
const nsIntRect* r = iter.Next();
|
|
|
|
if (!r)
|
|
|
|
break;
|
|
|
|
rects.push_back(CGRectMake(r->x, r->y, r->width, r->height));
|
|
|
|
}
|
|
|
|
CGContextClipToRects(ctx, rects.data(), rects.size());
|
|
|
|
|
|
|
|
CGContextClearRect(ctx, CGRectMake(0, 0, texSize.width, texSize.height));
|
2013-05-23 07:49:17 -07:00
|
|
|
|
|
|
|
double scale = BackingScaleFactor();
|
|
|
|
CGContextScaleCTM(ctx, scale, scale);
|
|
|
|
NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
|
|
|
|
|
|
|
|
CGContextSaveGState(ctx);
|
|
|
|
|
|
|
|
BaseWindow* window = (BaseWindow*)[mView window];
|
|
|
|
NSView* frameView = [[window contentView] superview];
|
|
|
|
if (![frameView isFlipped]) {
|
|
|
|
CGContextTranslateCTM(ctx, 0, [frameView bounds].size.height);
|
|
|
|
CGContextScaleCTM(ctx, 1, -1);
|
|
|
|
}
|
2013-06-28 17:59:07 -07:00
|
|
|
NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[frameView isFlipped]];
|
|
|
|
[NSGraphicsContext setCurrentContext:context];
|
2013-05-23 07:49:17 -07:00
|
|
|
|
|
|
|
// Draw the titlebar controls into the titlebar image.
|
|
|
|
for (id view in [window titlebarControls]) {
|
|
|
|
NSRect viewFrame = [view frame];
|
|
|
|
nsIntRect viewRect = CocoaPointsToDevPixels([mView convertRect:viewFrame fromView:frameView]);
|
2013-11-20 08:21:24 -08:00
|
|
|
if (!dirtyTitlebarRegion.Intersects(viewRect)) {
|
2013-05-23 07:49:17 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// All of the titlebar controls we're interested in are subclasses of
|
|
|
|
// NSButton.
|
|
|
|
if (![view isKindOfClass:[NSButton class]]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
NSButton *button = (NSButton *) view;
|
|
|
|
id cellObject = [button cell];
|
|
|
|
if (![cellObject isKindOfClass:[NSCell class]]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
NSCell *cell = (NSCell *) cellObject;
|
|
|
|
|
|
|
|
CGContextSaveGState(ctx);
|
|
|
|
CGContextTranslateCTM(ctx, viewFrame.origin.x, viewFrame.origin.y);
|
|
|
|
|
2013-06-28 17:59:07 -07:00
|
|
|
if ([context isFlipped] != [view isFlipped]) {
|
2013-05-23 07:49:17 -07:00
|
|
|
CGContextTranslateCTM(ctx, 0, viewFrame.size.height);
|
|
|
|
CGContextScaleCTM(ctx, 1, -1);
|
|
|
|
}
|
|
|
|
|
2013-06-28 17:59:07 -07:00
|
|
|
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[view isFlipped]]];
|
|
|
|
|
2013-11-20 08:21:24 -08:00
|
|
|
[cell drawWithFrame:[button bounds] inView:button];
|
2013-05-23 07:49:17 -07:00
|
|
|
|
2013-06-28 17:59:07 -07:00
|
|
|
[NSGraphicsContext setCurrentContext:context];
|
2013-05-23 07:49:17 -07:00
|
|
|
CGContextRestoreGState(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
CGContextRestoreGState(ctx);
|
|
|
|
|
|
|
|
DrawTitlebarHighlight([frameView bounds].size, [(ChildView*)mView cornerRadius],
|
|
|
|
DevPixelsToCocoaPoints(1));
|
|
|
|
|
|
|
|
[NSGraphicsContext setCurrentContext:oldContext];
|
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
CGContextRestoreGState(ctx);
|
2013-11-20 08:21:24 -08:00
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
mUpdatedTitlebarRegion.Or(mUpdatedTitlebarRegion, dirtyTitlebarRegion);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This method draws an overlay in the top of the window which contains the
|
|
|
|
// titlebar controls (e.g. close, min, zoom, fullscreen) and the titlebar
|
|
|
|
// highlight effect.
|
|
|
|
// This is necessary because the real titlebar controls are covered by our
|
|
|
|
// OpenGL context. Note that in terms of the NSView hierarchy, our ChildView
|
|
|
|
// is actually below the titlebar controls - that's why hovering and clicking
|
|
|
|
// them works as expected - but their visual representation is only drawn into
|
|
|
|
// the normal window buffer, and the window buffer surface lies below the
|
|
|
|
// GLContext surface. In order to make the titlebar controls visible, we have
|
|
|
|
// to redraw them inside the OpenGL context surface.
|
|
|
|
void
|
|
|
|
nsChildView::MaybeDrawTitlebar(GLManager* aManager, const nsIntRect& aRect)
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mEffectsLock);
|
|
|
|
if (!mIsCoveringTitlebar) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
nsIntRegion updatedTitlebarRegion;
|
|
|
|
updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect);
|
|
|
|
mUpdatedTitlebarRegion.SetEmpty();
|
2013-05-23 07:49:17 -07:00
|
|
|
|
|
|
|
if (!mTitlebarImage) {
|
2013-07-08 21:21:05 -07:00
|
|
|
mTitlebarImage = new RectTextureImage(aManager->gl());
|
2013-05-23 07:49:17 -07:00
|
|
|
}
|
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
mTitlebarImage->UpdateFromCGContext(mTitlebarRect.Size(),
|
|
|
|
updatedTitlebarRegion,
|
|
|
|
mTitlebarCGContext);
|
2013-05-23 07:49:17 -07:00
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
mTitlebarImage->Draw(aManager, mTitlebarRect.TopLeft());
|
2013-05-23 07:49:17 -07:00
|
|
|
}
|
|
|
|
|
2013-03-27 08:49:02 -07:00
|
|
|
static void
|
|
|
|
DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius)
|
|
|
|
{
|
|
|
|
CGContextSetRGBFillColor(aCtx, 1.0, 1.0, 1.0, 1.0);
|
|
|
|
CGContextFillEllipseInRect(aCtx, CGRectMake(0, 0, aRadius * 2, aRadius * 2));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-05-23 07:49:17 -07:00
|
|
|
nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, const nsIntRect& aRect)
|
2013-03-27 08:49:02 -07:00
|
|
|
{
|
2013-04-21 19:40:51 -07:00
|
|
|
MutexAutoLock lock(mEffectsLock);
|
2013-07-03 07:14:11 -07:00
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
if (!mCornerMaskImage) {
|
|
|
|
mCornerMaskImage = new RectTextureImage(aManager->gl());
|
2013-07-03 07:14:11 -07:00
|
|
|
}
|
2013-07-08 21:21:05 -07:00
|
|
|
|
|
|
|
nsIntSize size(mDevPixelCornerRadius, mDevPixelCornerRadius);
|
|
|
|
mCornerMaskImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) {
|
|
|
|
ClearRegion(drawTarget, updateRegion);
|
2013-11-26 21:50:33 -08:00
|
|
|
RefPtr<gfx::PathBuilder> builder = drawTarget->CreatePathBuilder();
|
|
|
|
builder->Arc(gfx::Point(mDevPixelCornerRadius, mDevPixelCornerRadius), mDevPixelCornerRadius, 0, 2.0f * M_PI);
|
|
|
|
RefPtr<gfx::Path> path = builder->Finish();
|
|
|
|
drawTarget->Fill(path,
|
|
|
|
gfx::ColorPattern(gfx::Color(1.0, 1.0, 1.0, 1.0)),
|
|
|
|
gfx::DrawOptions(1.0f, gfx::OP_SOURCE));
|
2013-07-08 21:21:05 -07:00
|
|
|
});
|
2013-05-23 07:49:17 -07:00
|
|
|
|
2013-03-27 08:49:02 -07:00
|
|
|
// Use operator destination in: multiply all 4 channels with source alpha.
|
|
|
|
aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA,
|
|
|
|
LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA);
|
2013-07-08 21:21:05 -07:00
|
|
|
|
|
|
|
gfx3DMatrix flipX = gfx3DMatrix::ScalingMatrix(-1, 1, 1);
|
|
|
|
gfx3DMatrix flipY = gfx3DMatrix::ScalingMatrix(1, -1, 1);
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
if (mIsCoveringTitlebar) {
|
|
|
|
// Mask the top corners.
|
2013-07-08 21:21:05 -07:00
|
|
|
mCornerMaskImage->Draw(aManager, aRect.TopLeft());
|
|
|
|
mCornerMaskImage->Draw(aManager, aRect.TopRight(), flipX);
|
2013-05-23 07:49:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mHasRoundedBottomCorners) {
|
|
|
|
// Mask the bottom corners.
|
2013-07-08 21:21:05 -07:00
|
|
|
mCornerMaskImage->Draw(aManager, aRect.BottomLeft(), flipY);
|
|
|
|
mCornerMaskImage->Draw(aManager, aRect.BottomRight(), flipY * flipX);
|
2013-05-23 07:49:17 -07:00
|
|
|
}
|
|
|
|
|
2013-03-27 08:49:02 -07:00
|
|
|
// Reset blend mode.
|
|
|
|
aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
|
|
|
|
LOCAL_GL_ONE, LOCAL_GL_ONE);
|
2011-01-07 12:32:42 -08:00
|
|
|
}
|
|
|
|
|
2013-05-22 02:50:57 -07:00
|
|
|
static int32_t
|
|
|
|
FindTitlebarBottom(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries,
|
|
|
|
int32_t aWindowWidth)
|
2011-01-11 05:03:16 -08:00
|
|
|
{
|
2013-05-22 02:50:57 -07:00
|
|
|
int32_t titlebarBottom = 0;
|
|
|
|
for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) {
|
|
|
|
const nsIWidget::ThemeGeometry& g = aThemeGeometries[i];
|
|
|
|
if ((g.mWidgetType == NS_THEME_WINDOW_TITLEBAR) &&
|
|
|
|
g.mRect.X() <= 0 &&
|
|
|
|
g.mRect.XMost() >= aWindowWidth &&
|
|
|
|
g.mRect.Y() <= 0) {
|
|
|
|
titlebarBottom = std::max(titlebarBottom, g.mRect.YMost());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return titlebarBottom;
|
|
|
|
}
|
2011-01-11 05:03:16 -08:00
|
|
|
|
2013-05-22 02:50:57 -07:00
|
|
|
static int32_t
|
|
|
|
FindUnifiedToolbarBottom(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries,
|
|
|
|
int32_t aWindowWidth, int32_t aTitlebarBottom)
|
|
|
|
{
|
|
|
|
int32_t unifiedToolbarBottom = aTitlebarBottom;
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) {
|
2013-05-22 02:50:57 -07:00
|
|
|
const nsIWidget::ThemeGeometry& g = aThemeGeometries[i];
|
2011-01-11 05:03:16 -08:00
|
|
|
if ((g.mWidgetType == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
|
|
|
|
g.mWidgetType == NS_THEME_TOOLBAR) &&
|
2013-05-22 02:48:47 -07:00
|
|
|
g.mRect.X() <= 0 &&
|
2013-05-22 02:50:57 -07:00
|
|
|
g.mRect.XMost() >= aWindowWidth &&
|
|
|
|
g.mRect.Y() <= aTitlebarBottom) {
|
|
|
|
unifiedToolbarBottom = std::max(unifiedToolbarBottom, g.mRect.YMost());
|
2011-01-11 05:03:16 -08:00
|
|
|
}
|
|
|
|
}
|
2013-05-22 02:50:57 -07:00
|
|
|
return unifiedToolbarBottom;
|
|
|
|
}
|
2013-06-12 14:42:00 -07:00
|
|
|
|
|
|
|
static nsIntRect
|
|
|
|
FindFirstRectOfType(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries,
|
|
|
|
uint8_t aWidgetType)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) {
|
|
|
|
const nsIWidget::ThemeGeometry& g = aThemeGeometries[i];
|
|
|
|
if (g.mWidgetType == aWidgetType) {
|
|
|
|
return g.mRect;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nsIntRect();
|
|
|
|
}
|
2013-05-22 02:48:47 -07:00
|
|
|
|
2013-05-22 02:50:57 -07:00
|
|
|
void
|
|
|
|
nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries)
|
|
|
|
{
|
|
|
|
if (![mView window] || ![[mView window] isKindOfClass:[ToolbarWindow class]])
|
|
|
|
return;
|
|
|
|
|
2013-06-12 14:42:00 -07:00
|
|
|
// Update unified toolbar height.
|
2013-05-22 02:50:57 -07:00
|
|
|
int32_t windowWidth = mBounds.width;
|
|
|
|
int32_t titlebarBottom = FindTitlebarBottom(aThemeGeometries, windowWidth);
|
|
|
|
int32_t unifiedToolbarBottom =
|
|
|
|
FindUnifiedToolbarBottom(aThemeGeometries, windowWidth, titlebarBottom);
|
|
|
|
|
|
|
|
ToolbarWindow* win = (ToolbarWindow*)[mView window];
|
|
|
|
bool drawsContentsIntoWindowFrame = [win drawsContentsIntoWindowFrame];
|
|
|
|
int32_t titlebarHeight = CocoaPointsToDevPixels([win titlebarHeight]);
|
|
|
|
int32_t contentOffset = drawsContentsIntoWindowFrame ? titlebarHeight : 0;
|
|
|
|
int32_t devUnifiedHeight = titlebarHeight + unifiedToolbarBottom - contentOffset;
|
|
|
|
[win setUnifiedToolbarHeight:DevPixelsToCocoaPoints(devUnifiedHeight)];
|
2013-06-12 14:42:00 -07:00
|
|
|
|
|
|
|
// Update titlebar control offsets.
|
|
|
|
nsIntRect windowButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_WINDOW_BUTTON_BOX);
|
|
|
|
[win placeWindowButtons:[mView convertRect:DevPixelsToCocoaPoints(windowButtonRect) toView:nil]];
|
|
|
|
nsIntRect fullScreenButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON);
|
|
|
|
[win placeFullScreenButton:[mView convertRect:DevPixelsToCocoaPoints(fullScreenButtonRect) toView:nil]];
|
2011-01-11 05:03:16 -08:00
|
|
|
}
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
TemporaryRef<gfx::DrawTarget>
|
|
|
|
nsChildView::StartRemoteDrawing()
|
|
|
|
{
|
|
|
|
if (!mGLPresenter) {
|
|
|
|
mGLPresenter = GLPresenter::CreateForWindow(this);
|
|
|
|
|
|
|
|
if (!mGLPresenter) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIntRegion dirtyRegion = mBounds;
|
|
|
|
nsIntSize renderSize = mBounds.Size();
|
|
|
|
|
|
|
|
if (!mBasicCompositorImage) {
|
|
|
|
mBasicCompositorImage = new RectTextureImage(mGLPresenter->gl());
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<gfx::DrawTarget> drawTarget =
|
|
|
|
mBasicCompositorImage->BeginUpdate(renderSize, dirtyRegion);
|
|
|
|
|
|
|
|
if (!drawTarget) {
|
|
|
|
// Composite unchanged textures.
|
|
|
|
DoRemoteComposition(mBounds);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return drawTarget;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsChildView::EndRemoteDrawing()
|
|
|
|
{
|
|
|
|
mBasicCompositorImage->EndUpdate(true);
|
|
|
|
DoRemoteComposition(mBounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsChildView::CleanupRemoteDrawing()
|
|
|
|
{
|
|
|
|
mBasicCompositorImage = nullptr;
|
|
|
|
mCornerMaskImage = nullptr;
|
|
|
|
mResizerImage = nullptr;
|
|
|
|
mTitlebarImage = nullptr;
|
|
|
|
mGLPresenter = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsChildView::DoRemoteComposition(const nsIntRect& aRenderRect)
|
|
|
|
{
|
2013-10-09 07:39:22 -07:00
|
|
|
if (![(ChildView*)mView preRender:mGLPresenter->GetNSOpenGLContext()]) {
|
|
|
|
return;
|
|
|
|
}
|
2013-07-08 21:21:05 -07:00
|
|
|
mGLPresenter->BeginFrame(aRenderRect.Size());
|
|
|
|
|
|
|
|
// Draw the result from the basic compositor.
|
|
|
|
mBasicCompositorImage->Draw(mGLPresenter, nsIntPoint(0, 0));
|
|
|
|
|
|
|
|
// DrawWindowOverlay doesn't do anything for non-GL, so it didn't paint
|
|
|
|
// anything during the basic compositor transaction. Draw the overlay now.
|
|
|
|
DrawWindowOverlay(mGLPresenter, aRenderRect);
|
|
|
|
|
|
|
|
mGLPresenter->EndFrame();
|
2013-10-09 07:39:23 -07:00
|
|
|
|
|
|
|
[(ChildView*)mView postRender:mGLPresenter->GetNSOpenGLContext()];
|
2013-07-08 21:21:05 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef ACCESSIBILITY
|
2012-11-17 18:01:44 -08:00
|
|
|
already_AddRefed<a11y::Accessible>
|
2010-05-11 23:47:35 -07:00
|
|
|
nsChildView::GetDocumentAccessible()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-06-06 17:26:45 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2012-06-06 17:26:45 -07:00
|
|
|
|
2010-05-11 23:47:35 -07:00
|
|
|
if (mAccessible) {
|
2013-04-28 04:52:10 -07:00
|
|
|
nsRefPtr<a11y::Accessible> ret;
|
|
|
|
CallQueryReferent(mAccessible.get(),
|
|
|
|
static_cast<a11y::Accessible**>(getter_AddRefs(ret)));
|
|
|
|
return ret.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-05-11 23:47:35 -07:00
|
|
|
// need to fetch the accessible anew, because it has gone away.
|
|
|
|
// cache the accessible in our weak ptr
|
2013-06-27 08:03:58 -07:00
|
|
|
nsRefPtr<a11y::Accessible> acc = GetRootAccessible();
|
2013-04-28 04:52:10 -07:00
|
|
|
mAccessible = do_GetWeakReference(static_cast<nsIAccessible *>(acc.get()));
|
2010-05-11 23:47:35 -07:00
|
|
|
|
2013-04-28 04:52:10 -07:00
|
|
|
return acc.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
// RectTextureImage implementation
|
|
|
|
|
|
|
|
RectTextureImage::~RectTextureImage()
|
|
|
|
{
|
|
|
|
if (mTexture) {
|
|
|
|
mGLContext->MakeCurrent();
|
|
|
|
mGLContext->fDeleteTextures(1, &mTexture);
|
|
|
|
mTexture = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIntSize
|
|
|
|
RectTextureImage::TextureSizeForSize(const nsIntSize& aSize)
|
|
|
|
{
|
|
|
|
return nsIntSize(gfx::NextPowerOfTwo(aSize.width),
|
|
|
|
gfx::NextPowerOfTwo(aSize.height));
|
|
|
|
}
|
|
|
|
|
|
|
|
TemporaryRef<gfx::DrawTarget>
|
|
|
|
RectTextureImage::BeginUpdate(const nsIntSize& aNewSize,
|
|
|
|
const nsIntRegion& aDirtyRegion)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!mInUpdate, "Beginning update during update!");
|
|
|
|
mUpdateRegion = aDirtyRegion;
|
|
|
|
if (aNewSize != mUsedSize) {
|
|
|
|
mUsedSize = aNewSize;
|
|
|
|
mUpdateRegion = nsIntRect(nsIntPoint(0, 0), aNewSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mUpdateRegion.IsEmpty()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIntSize neededBufferSize = TextureSizeForSize(mUsedSize);
|
|
|
|
if (!mUpdateDrawTarget || mBufferSize != neededBufferSize) {
|
|
|
|
gfx::IntSize size(neededBufferSize.width, neededBufferSize.height);
|
|
|
|
mUpdateDrawTarget =
|
|
|
|
gfx::Factory::CreateDrawTarget(gfx::BACKEND_COREGRAPHICS, size,
|
|
|
|
gfx::FORMAT_B8G8R8A8);
|
|
|
|
mBufferSize = neededBufferSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
mInUpdate = true;
|
|
|
|
|
|
|
|
RefPtr<gfx::DrawTarget> drawTarget = mUpdateDrawTarget;
|
|
|
|
return drawTarget;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define NSFoundationVersionWithProperStrideSupportForSubtextureUpload NSFoundationVersionNumber10_6_3
|
|
|
|
|
|
|
|
static bool
|
|
|
|
CanUploadSubtextures()
|
|
|
|
{
|
|
|
|
return NSFoundationVersionNumber >= NSFoundationVersionWithProperStrideSupportForSubtextureUpload;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RectTextureImage::EndUpdate(bool aKeepSurface)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mInUpdate, "Ending update while not in update");
|
|
|
|
|
|
|
|
bool overwriteTexture = false;
|
|
|
|
nsIntRegion updateRegion = mUpdateRegion;
|
|
|
|
if (!mTexture || (mTextureSize != mBufferSize)) {
|
|
|
|
overwriteTexture = true;
|
|
|
|
mTextureSize = mBufferSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (overwriteTexture || !CanUploadSubtextures()) {
|
|
|
|
updateRegion = nsIntRect(nsIntPoint(0, 0), mTextureSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<gfx::SourceSurface> snapshot = mUpdateDrawTarget->Snapshot();
|
|
|
|
RefPtr<gfx::DataSourceSurface> dataSnapshot = snapshot->GetDataSurface();
|
|
|
|
|
2013-12-03 10:44:38 -08:00
|
|
|
UploadSurfaceToTexture(mGLContext,
|
|
|
|
dataSnapshot,
|
|
|
|
updateRegion,
|
|
|
|
mTexture,
|
|
|
|
overwriteTexture,
|
|
|
|
updateRegion.GetBounds().TopLeft(),
|
|
|
|
false,
|
|
|
|
LOCAL_GL_TEXTURE0,
|
|
|
|
LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
2013-07-08 21:21:05 -07:00
|
|
|
|
|
|
|
if (!aKeepSurface) {
|
|
|
|
mUpdateDrawTarget = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
mInUpdate = false;
|
|
|
|
}
|
|
|
|
|
2013-11-26 21:49:45 -08:00
|
|
|
void
|
|
|
|
RectTextureImage::UpdateFromCGContext(const nsIntSize& aNewSize,
|
|
|
|
const nsIntRegion& aDirtyRegion,
|
|
|
|
CGContextRef aCGContext)
|
|
|
|
{
|
|
|
|
gfx::IntSize size = gfx::IntSize(CGBitmapContextGetWidth(aCGContext),
|
|
|
|
CGBitmapContextGetHeight(aCGContext));
|
|
|
|
mBufferSize.SizeTo(size.width, size.height);
|
|
|
|
RefPtr<gfx::DrawTarget> dt = BeginUpdate(aNewSize, aDirtyRegion);
|
|
|
|
if (dt) {
|
|
|
|
gfx::Rect rect(0, 0, size.width, size.height);
|
|
|
|
gfxUtils::ClipToRegion(dt, GetUpdateRegion());
|
|
|
|
RefPtr<gfx::SourceSurface> sourceSurface =
|
|
|
|
dt->CreateSourceSurfaceFromData(static_cast<uint8_t *>(CGBitmapContextGetData(aCGContext)),
|
|
|
|
size,
|
|
|
|
CGBitmapContextGetBytesPerRow(aCGContext),
|
|
|
|
gfx::FORMAT_B8G8R8A8);
|
|
|
|
dt->DrawSurface(sourceSurface, rect, rect,
|
|
|
|
gfx::DrawSurfaceOptions(),
|
|
|
|
gfx::DrawOptions(1.0, gfx::OP_SOURCE));
|
|
|
|
dt->PopClip();
|
|
|
|
EndUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-08 21:21:06 -07:00
|
|
|
void
|
|
|
|
RectTextureImage::UpdateFromDrawTarget(const nsIntSize& aNewSize,
|
|
|
|
const nsIntRegion& aDirtyRegion,
|
|
|
|
gfx::DrawTarget* aFromDrawTarget)
|
|
|
|
{
|
|
|
|
mUpdateDrawTarget = aFromDrawTarget;
|
|
|
|
mBufferSize.SizeTo(aFromDrawTarget->GetSize().width, aFromDrawTarget->GetSize().height);
|
|
|
|
RefPtr<gfx::DrawTarget> drawTarget = BeginUpdate(aNewSize, aDirtyRegion);
|
|
|
|
if (drawTarget) {
|
|
|
|
if (drawTarget != aFromDrawTarget) {
|
|
|
|
RefPtr<gfx::SourceSurface> source = aFromDrawTarget->Snapshot();
|
|
|
|
gfx::Rect rect(0, 0, aFromDrawTarget->GetSize().width, aFromDrawTarget->GetSize().height);
|
|
|
|
gfxUtils::ClipToRegion(drawTarget, GetUpdateRegion());
|
|
|
|
drawTarget->DrawSurface(source, rect, rect,
|
|
|
|
gfx::DrawSurfaceOptions(),
|
|
|
|
gfx::DrawOptions(1.0, gfx::OP_SOURCE));
|
|
|
|
drawTarget->PopClip();
|
|
|
|
}
|
|
|
|
EndUpdate();
|
|
|
|
}
|
|
|
|
mUpdateDrawTarget = nullptr;
|
|
|
|
}
|
|
|
|
|
2013-07-08 21:21:05 -07:00
|
|
|
void
|
|
|
|
RectTextureImage::Draw(GLManager* aManager,
|
|
|
|
const nsIntPoint& aLocation,
|
|
|
|
const gfx3DMatrix& aTransform)
|
|
|
|
{
|
2013-07-11 19:32:49 -07:00
|
|
|
ShaderProgramOGL* program = aManager->GetProgram(RGBARectLayerProgramType);
|
2013-07-08 21:21:05 -07:00
|
|
|
|
|
|
|
aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture);
|
|
|
|
|
|
|
|
program->Activate();
|
|
|
|
program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mUsedSize));
|
|
|
|
program->SetLayerTransform(aTransform * gfx3DMatrix::Translation(aLocation.x, aLocation.y, 0));
|
2013-07-18 20:05:06 -07:00
|
|
|
program->SetTextureTransform(gfx3DMatrix());
|
2013-07-08 21:21:05 -07:00
|
|
|
program->SetLayerOpacity(1.0);
|
|
|
|
program->SetRenderOffset(nsIntPoint(0, 0));
|
|
|
|
program->SetTexCoordMultiplier(mUsedSize.width, mUsedSize.height);
|
|
|
|
program->SetTextureUnit(0);
|
|
|
|
|
|
|
|
aManager->BindAndDrawQuad(program);
|
|
|
|
|
|
|
|
aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// GLPresenter implementation
|
|
|
|
|
|
|
|
GLPresenter::GLPresenter(GLContext* aContext)
|
|
|
|
: mGLContext(aContext)
|
|
|
|
{
|
|
|
|
mGLContext->SetFlipped(true);
|
|
|
|
mGLContext->MakeCurrent();
|
2013-07-17 23:54:09 -07:00
|
|
|
mRGBARectProgram = new ShaderProgramOGL(mGLContext,
|
|
|
|
ProgramProfileOGL::GetProfileFor(RGBARectLayerProgramType, MaskNone));
|
2013-07-08 21:21:05 -07:00
|
|
|
|
|
|
|
// Create mQuadVBO.
|
|
|
|
mGLContext->fGenBuffers(1, &mQuadVBO);
|
|
|
|
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
|
|
|
|
|
|
|
|
GLfloat vertices[] = {
|
|
|
|
/* First quad vertices */
|
|
|
|
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
|
|
|
/* Then quad texcoords */
|
|
|
|
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
|
|
|
};
|
|
|
|
mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
|
|
|
|
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
GLPresenter::~GLPresenter()
|
|
|
|
{
|
|
|
|
if (mQuadVBO) {
|
|
|
|
mGLContext->MakeCurrent();
|
|
|
|
mGLContext->fDeleteBuffers(1, &mQuadVBO);
|
|
|
|
mQuadVBO = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
GLPresenter::BindAndDrawQuad(ShaderProgramOGL* aProgram)
|
|
|
|
{
|
|
|
|
mGLContext->MakeCurrent();
|
|
|
|
|
|
|
|
GLuint vertAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
|
|
|
|
GLuint texCoordAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
|
|
|
|
|
|
|
|
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
|
|
|
|
mGLContext->fVertexAttribPointer(vertAttribIndex, 2,
|
|
|
|
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
|
|
|
|
(GLvoid*)0);
|
|
|
|
mGLContext->fEnableVertexAttribArray(vertAttribIndex);
|
|
|
|
mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2,
|
|
|
|
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
|
|
|
|
(GLvoid*) (sizeof(float)*4*2));
|
|
|
|
mGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
|
|
|
|
mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
mGLContext->fDisableVertexAttribArray(vertAttribIndex);
|
|
|
|
mGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
GLPresenter::BeginFrame(nsIntSize aRenderSize)
|
|
|
|
{
|
|
|
|
mGLContext->MakeCurrent();
|
|
|
|
|
|
|
|
mGLContext->fViewport(0, 0, aRenderSize.width, aRenderSize.height);
|
|
|
|
|
|
|
|
// Matrix to transform (0, 0, width, height) to viewport space (-1.0, 1.0,
|
|
|
|
// 2, 2) and flip the contents.
|
|
|
|
gfxMatrix viewMatrix;
|
|
|
|
viewMatrix.Translate(-gfxPoint(1.0, -1.0));
|
|
|
|
viewMatrix.Scale(2.0f / float(aRenderSize.width), 2.0f / float(aRenderSize.height));
|
|
|
|
viewMatrix.Scale(1.0f, -1.0f);
|
|
|
|
|
|
|
|
gfx3DMatrix matrix3d = gfx3DMatrix::From2D(viewMatrix);
|
|
|
|
matrix3d._33 = 0.0f;
|
|
|
|
|
2013-07-17 23:54:09 -07:00
|
|
|
mRGBARectProgram->CheckAndSetProjectionMatrix(matrix3d);
|
2013-07-08 21:21:05 -07:00
|
|
|
|
|
|
|
// Default blend function implements "OVER"
|
|
|
|
mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
|
|
|
|
LOCAL_GL_ONE, LOCAL_GL_ONE);
|
|
|
|
mGLContext->fEnable(LOCAL_GL_BLEND);
|
|
|
|
|
|
|
|
mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
|
|
|
|
mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
|
|
|
mGLContext->fEnable(LOCAL_GL_TEXTURE_RECTANGLE_ARB);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
GLPresenter::EndFrame()
|
|
|
|
{
|
|
|
|
mGLContext->SwapBuffers();
|
|
|
|
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
@implementation ChildView
|
|
|
|
|
|
|
|
// globalDragPboard is non-null during native drag sessions that did not originate
|
|
|
|
// in our native NSView (it is set in |draggingEntered:|). It is unset when the
|
|
|
|
// drag session ends for this view, either with the mouse exiting or when a drop
|
|
|
|
// occurs in this view.
|
|
|
|
NSPasteboard* globalDragPboard = nil;
|
|
|
|
|
2009-11-06 02:21:41 -08:00
|
|
|
// gLastDragView and gLastDragMouseDownEvent are used to communicate information
|
|
|
|
// to the drag service during drag invocation (starting a drag in from the view).
|
|
|
|
// gLastDragView is only non-null while mouseDragged is on the call stack.
|
2007-09-23 17:01:04 -07:00
|
|
|
NSView* gLastDragView = nil;
|
2009-11-06 02:21:41 -08:00
|
|
|
NSEvent* gLastDragMouseDownEvent = nil;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-12-15 12:56:29 -08:00
|
|
|
+ (void)initialize
|
|
|
|
{
|
|
|
|
static BOOL initialized = NO;
|
|
|
|
|
|
|
|
if (!initialized) {
|
|
|
|
// Inform the OS about the types of services (from the "Services" menu)
|
|
|
|
// that we can handle.
|
2009-03-17 19:04:01 -07:00
|
|
|
|
|
|
|
NSArray *sendTypes = [[NSArray alloc] initWithObjects:NSStringPboardType,NSHTMLPboardType,nil];
|
2010-01-10 17:45:45 -08:00
|
|
|
NSArray *returnTypes = [[NSArray alloc] initWithObjects:NSStringPboardType,NSHTMLPboardType,nil];
|
|
|
|
|
2008-12-15 12:56:29 -08:00
|
|
|
[NSApp registerServicesMenuSendTypes:sendTypes returnTypes:returnTypes];
|
|
|
|
|
2009-03-17 19:04:01 -07:00
|
|
|
[sendTypes release];
|
|
|
|
[returnTypes release];
|
|
|
|
|
2008-12-15 12:56:29 -08:00
|
|
|
initialized = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-05 13:40:34 -08:00
|
|
|
+ (void)registerViewForDraggedTypes:(NSView*)aView
|
|
|
|
{
|
|
|
|
[aView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
|
|
|
|
NSStringPboardType,
|
|
|
|
NSHTMLPboardType,
|
|
|
|
NSURLPboardType,
|
|
|
|
NSFilesPromisePboardType,
|
|
|
|
kWildcardPboardType,
|
|
|
|
kCorePboardType_url,
|
|
|
|
kCorePboardType_urld,
|
|
|
|
kCorePboardType_urln,
|
|
|
|
nil]];
|
|
|
|
}
|
|
|
|
|
2007-10-09 11:46:30 -07:00
|
|
|
// initWithFrame:geckoChild:
|
|
|
|
- (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if ((self = [super initWithFrame:inFrame])) {
|
|
|
|
mGeckoChild = inChild;
|
|
|
|
mIsPluginView = NO;
|
2009-08-31 18:00:13 -07:00
|
|
|
#ifndef NP_NO_CARBON
|
2012-10-15 05:38:34 -07:00
|
|
|
// We don't support the Carbon event model but it's still the default
|
|
|
|
// model for i386 per NPAPI.
|
2009-08-31 18:00:13 -07:00
|
|
|
mPluginEventModel = NPEventModelCarbon;
|
|
|
|
#else
|
|
|
|
mPluginEventModel = NPEventModelCocoa;
|
2010-09-17 10:55:39 -07:00
|
|
|
#endif
|
|
|
|
#ifndef NP_NO_QUICKDRAW
|
2012-08-30 12:10:55 -07:00
|
|
|
// We don't support the Quickdraw drawing model any more but it's still
|
|
|
|
// the default model for i386 per NPAPI.
|
2010-09-17 10:55:39 -07:00
|
|
|
mPluginDrawingModel = NPDrawingModelQuickDraw;
|
|
|
|
#else
|
|
|
|
mPluginDrawingModel = NPDrawingModelCoreGraphics;
|
2009-08-31 18:00:13 -07:00
|
|
|
#endif
|
2010-06-08 21:11:42 -07:00
|
|
|
mPendingDisplay = NO;
|
2010-07-16 05:48:02 -07:00
|
|
|
mBlockedLastMouseDown = NO;
|
2013-08-16 14:17:40 -07:00
|
|
|
mExpectingWheelStop = NO;
|
2008-02-28 21:47:41 -08:00
|
|
|
|
2008-04-06 16:52:05 -07:00
|
|
|
mLastMouseDownEvent = nil;
|
2010-07-16 05:48:02 -07:00
|
|
|
mClickThroughMouseDownEvent = nil;
|
2012-07-30 07:20:58 -07:00
|
|
|
mDragService = nullptr;
|
2008-06-30 09:30:22 -07:00
|
|
|
|
2008-10-23 13:15:20 -07:00
|
|
|
mGestureState = eGestureState_None;
|
|
|
|
mCumulativeMagnification = 0.0;
|
|
|
|
mCumulativeRotation = 0.0;
|
2009-09-16 15:06:16 -07:00
|
|
|
|
2011-02-03 13:12:33 -08:00
|
|
|
// We can't call forceRefreshOpenGL here because, in order to work around
|
|
|
|
// the bug, it seems we need to have a draw already happening. Therefore,
|
|
|
|
// we call it in drawRect:inContext:, when we know that a draw is in
|
|
|
|
// progress.
|
|
|
|
mDidForceRefreshOpenGL = NO;
|
|
|
|
|
2009-09-16 15:06:16 -07:00
|
|
|
[self setFocusRingType:NSFocusRingTypeNone];
|
2011-08-11 10:42:23 -07:00
|
|
|
|
|
|
|
#ifdef __LP64__
|
2013-04-09 12:44:01 -07:00
|
|
|
mCancelSwipeAnimation = nil;
|
2013-10-11 12:48:53 -07:00
|
|
|
mCurrentSwipeDir = 0;
|
2011-08-11 10:42:23 -07:00
|
|
|
#endif
|
2013-05-23 07:49:17 -07:00
|
|
|
|
|
|
|
mTopLeftCornerMask = NULL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2013-04-09 12:44:01 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// register for things we'll take from other applications
|
2013-02-05 13:40:34 -08:00
|
|
|
[ChildView registerViewForDraggedTypes:self];
|
|
|
|
|
2010-04-20 23:21:46 -07:00
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(windowBecameMain:)
|
|
|
|
name:NSWindowDidBecomeMainNotification
|
|
|
|
object:nil];
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(windowResignedMain:)
|
|
|
|
name:NSWindowDidResignMainNotification
|
|
|
|
object:nil];
|
2008-09-17 09:26:57 -07:00
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
2008-10-14 06:31:09 -07:00
|
|
|
selector:@selector(systemMetricsChanged)
|
2008-09-17 09:26:57 -07:00
|
|
|
name:NSControlTintDidChangeNotification
|
|
|
|
object:nil];
|
2008-09-22 02:09:32 -07:00
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
2008-10-14 06:31:09 -07:00
|
|
|
selector:@selector(systemMetricsChanged)
|
2008-09-22 02:09:32 -07:00
|
|
|
name:NSSystemColorsDidChangeNotification
|
|
|
|
object:nil];
|
2013-05-02 07:58:00 -07:00
|
|
|
// TODO: replace the string with the constant once we build with the 10.7 SDK
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
2013-07-16 05:58:44 -07:00
|
|
|
selector:@selector(scrollbarSystemMetricChanged)
|
2013-05-02 07:58:00 -07:00
|
|
|
name:@"NSPreferredScrollerStyleDidChangeNotification"
|
|
|
|
object:nil];
|
2008-10-14 06:31:09 -07:00
|
|
|
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(systemMetricsChanged)
|
|
|
|
name:@"AppleAquaScrollBarVariantChanged"
|
|
|
|
object:nil
|
|
|
|
suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
|
2010-04-27 15:29:29 -07:00
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(_surfaceNeedsUpdate:)
|
|
|
|
name:NSViewGlobalFrameDidChangeNotification
|
|
|
|
object:self];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return self;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-05-08 03:19:23 -07:00
|
|
|
- (void)installTextInputHandler:(TextInputHandler*)aHandler
|
|
|
|
{
|
|
|
|
mTextInputHandler = aHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)uninstallTextInputHandler
|
|
|
|
{
|
2012-07-30 07:20:58 -07:00
|
|
|
mTextInputHandler = nullptr;
|
2011-05-08 03:19:23 -07:00
|
|
|
}
|
|
|
|
|
2011-02-03 13:12:33 -08:00
|
|
|
// Work around bug 603134.
|
|
|
|
// OS X has a bug that causes new OpenGL windows to only paint once or twice,
|
|
|
|
// then stop painting altogether. By clearing the drawable from the GL context,
|
|
|
|
// and then resetting the view to ourselves, we convince OS X to start updating
|
|
|
|
// again.
|
|
|
|
// This can cause a flash in new windows - bug 631339 - but it's very hard to
|
|
|
|
// fix that while maintaining this workaround.
|
|
|
|
- (void)forceRefreshOpenGL
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
[mGLContext clearDrawable];
|
2013-10-09 07:39:22 -07:00
|
|
|
[self updateGLContext];
|
2011-02-03 13:12:33 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2012-01-19 06:45:37 -08:00
|
|
|
- (void)setGLContext:(NSOpenGLContext *)aGLContext
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
mGLContext = aGLContext;
|
|
|
|
[mGLContext retain];
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2013-10-09 07:39:22 -07:00
|
|
|
- (bool)preRender:(NSOpenGLContext *)aGLContext
|
2013-05-09 14:02:49 -07:00
|
|
|
{
|
2013-10-09 07:39:22 -07:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
2013-10-09 07:39:22 -07:00
|
|
|
|
2013-10-09 07:39:23 -07:00
|
|
|
if (![self window] ||
|
|
|
|
([[self window] isKindOfClass:[BaseWindow class]] &&
|
|
|
|
![(BaseWindow*)[self window] isVisibleOrBeingShown])) {
|
2013-10-09 07:39:22 -07:00
|
|
|
// Before the window is shown, our GL context's front FBO is not
|
|
|
|
// framebuffer complete, so we refuse to render.
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-09 07:39:22 -07:00
|
|
|
|
|
|
|
if (!mGLContext) {
|
|
|
|
[self setGLContext:aGLContext];
|
|
|
|
[self updateGLContext];
|
|
|
|
}
|
2013-10-09 07:39:23 -07:00
|
|
|
|
2013-10-09 07:39:23 -07:00
|
|
|
CGLLockContext((CGLContextObj)[aGLContext CGLContextObj]);
|
|
|
|
|
2013-10-09 07:39:22 -07:00
|
|
|
return true;
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
|
2013-10-09 07:39:23 -07:00
|
|
|
}
|
|
|
|
|
2013-10-09 07:39:23 -07:00
|
|
|
- (void)postRender:(NSOpenGLContext *)aGLContext
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
CGLUnlockContext((CGLContextObj)[aGLContext CGLContextObj]);
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
- (void)dealloc
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2010-06-18 02:22:01 -07:00
|
|
|
[mGLContext release];
|
2007-03-22 10:30:00 -07:00
|
|
|
[mPendingDirtyRects release];
|
2008-04-06 16:52:05 -07:00
|
|
|
[mLastMouseDownEvent release];
|
2010-07-16 05:48:02 -07:00
|
|
|
[mClickThroughMouseDownEvent release];
|
2013-05-23 07:49:17 -07:00
|
|
|
CGImageRelease(mTopLeftCornerMask);
|
2009-10-21 00:02:13 -07:00
|
|
|
ChildViewMouseTracker::OnDestroyView(self);
|
2007-09-17 15:55:20 -07:00
|
|
|
|
2008-09-17 09:26:57 -07:00
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
2008-10-14 06:31:09 -07:00
|
|
|
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
|
2008-09-17 09:26:57 -07:00
|
|
|
|
2012-08-30 12:10:55 -07:00
|
|
|
[super dealloc];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-04-20 23:21:46 -07:00
|
|
|
- (void)updatePluginTopLevelWindowStatus:(BOOL)hasMain
|
|
|
|
{
|
2010-04-25 13:58:03 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2013-09-26 23:20:54 -07:00
|
|
|
WidgetPluginEvent pluginEvent(true, NS_PLUGIN_FOCUS_EVENT, mGeckoChild);
|
2010-04-20 23:21:46 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
2011-07-20 17:33:16 -07:00
|
|
|
nsCocoaUtils::InitNPCocoaEvent(&cocoaEvent);
|
2010-04-20 23:21:46 -07:00
|
|
|
cocoaEvent.type = NPCocoaEventWindowFocusChanged;
|
|
|
|
cocoaEvent.data.focus.hasFocus = hasMain;
|
2011-07-20 17:33:16 -07:00
|
|
|
nsCocoaUtils::InitPluginEvent(pluginEvent, cocoaEvent);
|
2010-04-20 23:21:46 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(pluginEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)windowBecameMain:(NSNotification*)inNotification
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
if (mIsPluginView && mPluginEventModel == NPEventModelCocoa) {
|
|
|
|
if ((NSWindow*)[inNotification object] == [self window]) {
|
|
|
|
[self updatePluginTopLevelWindowStatus:YES];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)windowResignedMain:(NSNotification*)inNotification
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
if (mIsPluginView && mPluginEventModel == NPEventModelCocoa) {
|
|
|
|
if ((NSWindow*)[inNotification object] == [self window]) {
|
|
|
|
[self updatePluginTopLevelWindowStatus:NO];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
- (void)widgetDestroyed
|
|
|
|
{
|
2011-05-08 03:19:23 -07:00
|
|
|
if (mTextInputHandler) {
|
|
|
|
mTextInputHandler->OnDestroyWidget(mGeckoChild);
|
2012-07-30 07:20:58 -07:00
|
|
|
mTextInputHandler = nullptr;
|
2011-05-08 03:19:23 -07:00
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
mGeckoChild = nullptr;
|
2008-10-21 15:15:08 -07:00
|
|
|
|
2007-10-10 05:19:47 -07:00
|
|
|
// Just in case we're destroyed abruptly and missed the draggingExited
|
|
|
|
// or performDragOperation message.
|
|
|
|
NS_IF_RELEASE(mDragService);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// mozView method, return our gecko child view widget. Note this does not AddRef.
|
|
|
|
- (nsIWidget*) widget
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
return static_cast<nsIWidget*>(mGeckoChild);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-10-14 06:31:09 -07:00
|
|
|
- (void)systemMetricsChanged
|
2008-09-17 09:26:57 -07:00
|
|
|
{
|
2012-08-15 11:52:35 -07:00
|
|
|
if (mGeckoChild)
|
|
|
|
mGeckoChild->NotifyThemeChanged();
|
2008-09-17 09:26:57 -07:00
|
|
|
}
|
|
|
|
|
2013-07-16 05:58:44 -07:00
|
|
|
- (void)scrollbarSystemMetricChanged
|
|
|
|
{
|
|
|
|
[self systemMetricsChanged];
|
|
|
|
|
|
|
|
if (mGeckoChild) {
|
|
|
|
nsIWidgetListener* listener = mGeckoChild->GetWidgetListener();
|
|
|
|
if (listener) {
|
|
|
|
listener->GetPresShell()->ReconstructFrames();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
- (void)setNeedsPendingDisplay
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mPendingFullDisplay = YES;
|
2010-06-08 21:11:42 -07:00
|
|
|
if (!mPendingDisplay) {
|
|
|
|
[self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
|
|
|
|
mPendingDisplay = YES;
|
|
|
|
}
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setNeedsPendingDisplayInRect:(NSRect)invalidRect
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!mPendingDirtyRects)
|
|
|
|
mPendingDirtyRects = [[NSMutableArray alloc] initWithCapacity:1];
|
|
|
|
[mPendingDirtyRects addObject:[NSValue valueWithRect:invalidRect]];
|
2010-06-08 21:11:42 -07:00
|
|
|
if (!mPendingDisplay) {
|
|
|
|
[self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0];
|
|
|
|
mPendingDisplay = YES;
|
|
|
|
}
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clears the queue of any pending invalides
|
|
|
|
- (void)processPendingRedraws
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mPendingFullDisplay) {
|
|
|
|
[self setNeedsDisplay:YES];
|
|
|
|
}
|
2010-06-08 21:11:42 -07:00
|
|
|
else if (mPendingDirtyRects) {
|
2007-03-22 10:30:00 -07:00
|
|
|
unsigned int count = [mPendingDirtyRects count];
|
|
|
|
for (unsigned int i = 0; i < count; ++i) {
|
|
|
|
[self setNeedsDisplayInRect:[[mPendingDirtyRects objectAtIndex:i] rectValue]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mPendingFullDisplay = NO;
|
2010-06-08 21:11:42 -07:00
|
|
|
mPendingDisplay = NO;
|
2007-03-22 10:30:00 -07:00
|
|
|
[mPendingDirtyRects release];
|
|
|
|
mPendingDirtyRects = nil;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-10-21 00:05:39 -07:00
|
|
|
- (void)setNeedsDisplayInRect:(NSRect)aRect
|
|
|
|
{
|
2013-05-23 07:55:50 -07:00
|
|
|
if (![self isUsingOpenGL]) {
|
|
|
|
[super setNeedsDisplayInRect:aRect];
|
2013-03-05 07:21:28 -08:00
|
|
|
return;
|
2013-05-23 07:55:50 -07:00
|
|
|
}
|
2013-03-05 07:21:28 -08:00
|
|
|
|
2013-05-23 07:55:50 -07:00
|
|
|
if ([[self window] isVisible] && [self isUsingMainThreadOpenGL]) {
|
|
|
|
// Draw without calling drawRect. This prevent us from
|
2013-03-05 07:21:28 -08:00
|
|
|
// needing to access the normal window buffer surface unnecessarily, so we
|
|
|
|
// waste less time synchronizing the two surfaces. (These synchronizations
|
|
|
|
// show up in a profiler as CGSDeviceLock / _CGSLockWindow /
|
|
|
|
// _CGSSynchronizeWindowBackingStore.) It also means that Cocoa doesn't
|
|
|
|
// have any potentially expensive invalid rect management for us.
|
|
|
|
if (!mWaitingForPaint) {
|
|
|
|
mWaitingForPaint = YES;
|
2013-04-05 01:18:06 -07:00
|
|
|
// Use NSRunLoopCommonModes instead of the default NSDefaultRunLoopMode
|
|
|
|
// so that the timer also fires while a native menu is open.
|
|
|
|
[self performSelector:@selector(drawUsingOpenGLCallback)
|
|
|
|
withObject:nil
|
|
|
|
afterDelay:0
|
|
|
|
inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
|
2013-03-05 07:21:28 -08:00
|
|
|
}
|
|
|
|
}
|
2009-10-21 00:05:39 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
- (NSString*)description
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [NSString stringWithFormat:@"ChildView %p, gecko child %p, frame %@", self, mGeckoChild, NSStringFromRect([self frame])];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make the origin of this view the topLeft corner (gecko origin) rather
|
|
|
|
// than the bottomLeft corner (standard cocoa origin).
|
|
|
|
- (BOOL)isFlipped
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isOpaque
|
|
|
|
{
|
2010-09-17 11:04:14 -07:00
|
|
|
return [[self window] isOpaque] && !mIsPluginView;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
-(void)setIsPluginView:(BOOL)aIsPlugin
|
|
|
|
{
|
|
|
|
mIsPluginView = aIsPlugin;
|
|
|
|
}
|
|
|
|
|
2007-03-26 18:07:57 -07:00
|
|
|
-(BOOL)isPluginView
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return mIsPluginView;
|
|
|
|
}
|
|
|
|
|
2010-11-15 13:12:50 -08:00
|
|
|
// Are we processing an NSLeftMouseDown event that will fail to click through?
|
|
|
|
// If so, we shouldn't focus or unfocus a plugin.
|
|
|
|
- (BOOL)isInFailingLeftClickThrough
|
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
if (!mClickThroughMouseDownEvent ||
|
|
|
|
[mClickThroughMouseDownEvent type] != NSLeftMouseDown)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
BOOL retval =
|
|
|
|
!ChildViewMouseTracker::WindowAcceptsEvent([self window],
|
|
|
|
mClickThroughMouseDownEvent,
|
2011-09-30 17:20:33 -07:00
|
|
|
self, true);
|
2010-11-15 13:12:50 -08:00
|
|
|
|
|
|
|
// If we return YES here, this will result in us not being focused,
|
|
|
|
// which will stop us receiving mClickThroughMouseDownEvent in
|
|
|
|
// [ChildView mouseDown:]. So we need to release and null-out
|
|
|
|
// mClickThroughMouseDownEvent here.
|
|
|
|
if (retval) {
|
|
|
|
[mClickThroughMouseDownEvent release];
|
|
|
|
mClickThroughMouseDownEvent = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2009-08-31 18:00:13 -07:00
|
|
|
- (void)setPluginEventModel:(NPEventModel)eventModel
|
2009-08-26 17:29:47 -07:00
|
|
|
{
|
2009-08-31 18:00:13 -07:00
|
|
|
mPluginEventModel = eventModel;
|
2009-08-26 17:29:47 -07:00
|
|
|
}
|
|
|
|
|
2010-09-17 10:55:39 -07:00
|
|
|
- (void)setPluginDrawingModel:(NPDrawingModel)drawingModel
|
|
|
|
{
|
|
|
|
mPluginDrawingModel = drawingModel;
|
|
|
|
}
|
|
|
|
|
2011-01-20 17:08:11 -08:00
|
|
|
- (NPEventModel)pluginEventModel
|
2009-08-26 17:29:47 -07:00
|
|
|
{
|
2009-08-31 18:00:13 -07:00
|
|
|
return mPluginEventModel;
|
2009-08-26 17:29:47 -07:00
|
|
|
}
|
|
|
|
|
2011-01-20 17:08:11 -08:00
|
|
|
- (NPDrawingModel)pluginDrawingModel
|
2010-09-17 10:55:39 -07:00
|
|
|
{
|
|
|
|
return mPluginDrawingModel;
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
- (void)sendFocusEvent:(uint32_t)eventType
|
2007-08-02 16:01:32 -07:00
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
2013-10-01 20:46:03 -07:00
|
|
|
WidgetGUIEvent focusGuiEvent(true, eventType, mGeckoChild);
|
2007-08-02 16:01:32 -07:00
|
|
|
focusGuiEvent.time = PR_IntervalNow();
|
|
|
|
mGeckoChild->DispatchEvent(&focusGuiEvent, status);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// We accept key and mouse events, so don't keep passing them up the chain. Allow
|
2010-04-25 13:58:03 -07:00
|
|
|
// this to be a 'focused' widget for event dispatch.
|
2007-03-22 10:30:00 -07:00
|
|
|
- (BOOL)acceptsFirstResponder
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2010-07-16 05:48:02 -07:00
|
|
|
// Accept mouse down events on background windows
|
|
|
|
- (BOOL)acceptsFirstMouse:(NSEvent*)aEvent
|
|
|
|
{
|
|
|
|
if (![[self window] isKindOfClass:[PopupWindow class]]) {
|
|
|
|
// We rely on this function to tell us that the mousedown was on a
|
|
|
|
// background window. Inside mouseDown we can't tell whether we were
|
|
|
|
// inactive because at that point we've already been made active.
|
|
|
|
// Unfortunately, acceptsFirstMouse is called for PopupWindows even when
|
|
|
|
// their parent window is active, so ignore this on them for now.
|
|
|
|
mClickThroughMouseDownEvent = [aEvent retain];
|
|
|
|
}
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2008-11-14 02:24:16 -08:00
|
|
|
- (void)viewWillMoveToWindow:(NSWindow *)newWindow
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
if (!newWindow)
|
|
|
|
HideChildPluginViews(self);
|
|
|
|
|
|
|
|
[super viewWillMoveToWindow:newWindow];
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2009-09-15 14:56:44 -07:00
|
|
|
- (void)viewDidMoveToWindow
|
|
|
|
{
|
2010-01-23 22:00:39 -08:00
|
|
|
if (mPluginEventModel == NPEventModelCocoa &&
|
|
|
|
[self window] && [self isPluginView] && mGeckoChild) {
|
2009-09-15 14:56:44 -07:00
|
|
|
mGeckoChild->UpdatePluginPort();
|
|
|
|
}
|
|
|
|
|
|
|
|
[super viewDidMoveToWindow];
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
- (void)scrollRect:(NSRect)aRect by:(NSSize)offset
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Update any pending dirty rects to reflect the new scroll position
|
|
|
|
if (mPendingDirtyRects) {
|
|
|
|
unsigned int count = [mPendingDirtyRects count];
|
|
|
|
for (unsigned int i = 0; i < count; ++i) {
|
|
|
|
NSRect oldRect = [[mPendingDirtyRects objectAtIndex:i] rectValue];
|
|
|
|
NSRect newRect = NSOffsetRect(oldRect, offset.width, offset.height);
|
|
|
|
[mPendingDirtyRects replaceObjectAtIndex:i
|
|
|
|
withObject:[NSValue valueWithRect:newRect]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[super scrollRect:aRect by:offset];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)mouseDownCanMoveWindow
|
|
|
|
{
|
2013-02-05 13:40:34 -08:00
|
|
|
return [[self window] isMovableByWindowBackground];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-10-09 07:39:22 -07:00
|
|
|
-(void)updateGLContext
|
2010-04-27 15:29:29 -07:00
|
|
|
{
|
2010-06-18 02:22:01 -07:00
|
|
|
if (mGLContext) {
|
2013-10-09 07:39:23 -07:00
|
|
|
CGLLockContext((CGLContextObj)[mGLContext CGLContextObj]);
|
2013-10-09 07:39:22 -07:00
|
|
|
[mGLContext setView:self];
|
2010-06-18 02:22:01 -07:00
|
|
|
[mGLContext update];
|
2013-10-09 07:39:23 -07:00
|
|
|
CGLUnlockContext((CGLContextObj)[mGLContext CGLContextObj]);
|
2010-04-27 15:29:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-09 07:39:22 -07:00
|
|
|
- (void)_surfaceNeedsUpdate:(NSNotification*)notification
|
2010-04-27 15:29:29 -07:00
|
|
|
{
|
2013-10-09 07:39:22 -07:00
|
|
|
[self updateGLContext];
|
2010-04-27 15:29:29 -07:00
|
|
|
}
|
|
|
|
|
2012-09-29 04:36:09 -07:00
|
|
|
- (BOOL)wantsBestResolutionOpenGLSurface
|
|
|
|
{
|
|
|
|
return nsCocoaUtils::HiDPIEnabled() ? YES : NO;
|
|
|
|
}
|
|
|
|
|
2012-10-16 12:41:20 -07:00
|
|
|
- (void)viewDidChangeBackingProperties
|
|
|
|
{
|
|
|
|
[super viewDidChangeBackingProperties];
|
|
|
|
if (mGeckoChild) {
|
|
|
|
// actually, it could be the color space that's changed,
|
|
|
|
// but we can't tell the difference here except by retrieving
|
|
|
|
// the backing scale factor and comparing to the old value
|
|
|
|
mGeckoChild->BackingScaleFactorChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
- (BOOL)isCoveringTitlebar
|
|
|
|
{
|
|
|
|
return [[self window] isKindOfClass:[BaseWindow class]] &&
|
|
|
|
[(BaseWindow*)[self window] mainChildView] == self &&
|
|
|
|
[(BaseWindow*)[self window] drawsContentsIntoWindowFrame];
|
|
|
|
}
|
|
|
|
|
2013-06-20 05:59:16 -07:00
|
|
|
- (nsIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect
|
|
|
|
{
|
|
|
|
nsIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect);
|
|
|
|
const NSRect *rects;
|
|
|
|
NSInteger count;
|
2013-06-28 18:05:07 -07:00
|
|
|
[self getRectsBeingDrawn:&rects count:&count];
|
2013-06-20 05:59:16 -07:00
|
|
|
|
|
|
|
if (count > MAX_RECTS_IN_REGION) {
|
|
|
|
return boundingRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIntRegion region;
|
|
|
|
for (NSInteger i = 0; i < count; ++i) {
|
2013-06-28 18:05:07 -07:00
|
|
|
region.Or(region, mGeckoChild->CocoaPointsToDevPixels(rects[i]));
|
2013-06-20 05:59:16 -07:00
|
|
|
}
|
|
|
|
region.And(region, boundingRect);
|
|
|
|
return region;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// The display system has told us that a portion of our view is dirty. Tell
|
|
|
|
// gecko to paint it
|
|
|
|
- (void)drawRect:(NSRect)aRect
|
|
|
|
{
|
2009-10-21 00:05:39 -07:00
|
|
|
CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
|
2013-05-23 07:49:16 -07:00
|
|
|
[self drawRect:aRect inContext:cgContext];
|
2009-10-21 00:05:39 -07:00
|
|
|
|
2009-12-11 13:53:22 -08:00
|
|
|
// If we're a transparent window and our contents have changed, we need
|
2009-10-21 00:05:39 -07:00
|
|
|
// to make sure the shadow is updated to the new contents.
|
2009-12-11 13:53:22 -08:00
|
|
|
if ([[self window] isKindOfClass:[BaseWindow class]]) {
|
|
|
|
[(BaseWindow*)[self window] deferredInvalidateShadow];
|
|
|
|
}
|
2009-10-21 00:05:39 -07:00
|
|
|
}
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2013-05-23 07:49:16 -07:00
|
|
|
- (void)drawRect:(NSRect)aRect inContext:(CGContextRef)aContext
|
2009-10-21 00:05:39 -07:00
|
|
|
{
|
2012-07-19 01:57:50 -07:00
|
|
|
if (!mGeckoChild || !mGeckoChild->IsVisible())
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
2012-08-30 12:10:55 -07:00
|
|
|
// Don't ever draw plugin views explicitly; they'll be drawn as part of their parent widget.
|
2010-09-17 11:04:14 -07:00
|
|
|
if (mIsPluginView)
|
|
|
|
return;
|
|
|
|
|
2009-10-21 00:05:39 -07:00
|
|
|
#ifdef DEBUG_UPDATE
|
2009-01-14 19:27:09 -08:00
|
|
|
nsIntRect geckoBounds;
|
2007-03-22 10:30:00 -07:00
|
|
|
mGeckoChild->GetBounds(geckoBounds);
|
|
|
|
|
|
|
|
fprintf (stderr, "---- Update[%p][%p] [%f %f %f %f] cgc: %p\n gecko bounds: [%d %d %d %d]\n",
|
|
|
|
self, mGeckoChild,
|
2009-10-21 00:05:39 -07:00
|
|
|
aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height, aContext,
|
2007-03-22 10:30:00 -07:00
|
|
|
geckoBounds.x, geckoBounds.y, geckoBounds.width, geckoBounds.height);
|
|
|
|
|
2009-10-21 00:05:39 -07:00
|
|
|
CGAffineTransform xform = CGContextGetCTM(aContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
fprintf (stderr, " xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx, xform.ty);
|
|
|
|
#endif
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
if ([self isUsingOpenGL]) {
|
|
|
|
// For Gecko-initiated repaints in OpenGL mode, drawUsingOpenGL is
|
|
|
|
// directly called from a delayed perform callback - without going through
|
|
|
|
// drawRect.
|
|
|
|
// Paints that come through here are triggered by something that Cocoa
|
|
|
|
// controls, for example by window resizing or window focus changes.
|
|
|
|
|
|
|
|
// Since this view is usually declared as opaque, the window's pixel
|
|
|
|
// buffer may now contain garbage which we need to prevent from reaching
|
|
|
|
// the screen. The only place where garbage can show is in the window
|
|
|
|
// corners - the rest of the window is covered by opaque content in our
|
|
|
|
// OpenGL surface.
|
|
|
|
// So we need to clear the pixel buffer contents in the corners.
|
|
|
|
[self clearCorners];
|
|
|
|
|
|
|
|
// Do GL composition and return.
|
|
|
|
[self drawUsingOpenGL];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PROFILER_LABEL("widget", "ChildView::drawRect");
|
2009-07-21 17:44:55 -07:00
|
|
|
|
2012-09-29 04:36:09 -07:00
|
|
|
// The CGContext that drawRect supplies us with comes with a transform that
|
|
|
|
// scales one user space unit to one Cocoa point, which can consist of
|
|
|
|
// multiple dev pixels. But Gecko expects its supplied context to be scaled
|
|
|
|
// to device pixels, so we need to reverse the scaling.
|
2012-11-06 09:01:58 -08:00
|
|
|
double scale = mGeckoChild->BackingScaleFactor();
|
2013-05-23 07:49:17 -07:00
|
|
|
CGContextSaveGState(aContext);
|
2012-11-06 09:01:58 -08:00
|
|
|
CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
|
|
|
|
|
|
|
|
NSSize viewSize = [self bounds].size;
|
|
|
|
nsIntSize backingSize(viewSize.width * scale, viewSize.height * scale);
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
CGContextSaveGState(aContext);
|
|
|
|
|
2013-06-20 05:59:16 -07:00
|
|
|
nsIntRegion region = [self nativeDirtyRegionWithBoundingRect:aRect];
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
// Create Cairo objects.
|
2012-11-06 09:01:58 -08:00
|
|
|
nsRefPtr<gfxQuartzSurface> targetSurface =
|
|
|
|
new gfxQuartzSurface(aContext, backingSize);
|
|
|
|
targetSurface->SetAllowUseAsSource(false);
|
|
|
|
|
2013-08-26 02:06:37 -07:00
|
|
|
nsRefPtr<gfxContext> targetContext;
|
2013-09-29 16:17:35 -07:00
|
|
|
if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(gfx::BACKEND_CAIRO)) {
|
|
|
|
RefPtr<gfx::DrawTarget> dt =
|
2013-08-26 02:06:37 -07:00
|
|
|
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(targetSurface,
|
2013-09-29 16:17:35 -07:00
|
|
|
gfx::IntSize(backingSize.width,
|
|
|
|
backingSize.height));
|
2013-10-09 21:44:09 -07:00
|
|
|
dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
|
2013-09-29 16:17:35 -07:00
|
|
|
targetContext = new gfxContext(dt);
|
|
|
|
} else if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(gfx::BACKEND_COREGRAPHICS)) {
|
|
|
|
RefPtr<gfx::DrawTarget> dt =
|
|
|
|
gfx::Factory::CreateDrawTargetForCairoCGContext(aContext,
|
|
|
|
gfx::IntSize(backingSize.width,
|
|
|
|
backingSize.height));
|
2013-10-09 21:44:09 -07:00
|
|
|
dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
|
2013-08-26 02:06:37 -07:00
|
|
|
targetContext = new gfxContext(dt);
|
|
|
|
} else {
|
|
|
|
targetContext = new gfxContext(targetSurface);
|
|
|
|
}
|
2012-11-06 09:01:58 -08:00
|
|
|
|
2009-10-21 00:05:39 -07:00
|
|
|
// Set up the clip region.
|
2012-08-15 11:52:42 -07:00
|
|
|
nsIntRegionRectIterator iter(region);
|
2010-03-01 00:03:49 -08:00
|
|
|
targetContext->NewPath();
|
|
|
|
for (;;) {
|
|
|
|
const nsIntRect* r = iter.Next();
|
|
|
|
if (!r)
|
|
|
|
break;
|
|
|
|
targetContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height));
|
2009-10-21 00:05:39 -07:00
|
|
|
}
|
|
|
|
targetContext->Clip();
|
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2013-05-09 14:02:49 -07:00
|
|
|
bool painted = false;
|
2013-04-30 22:03:25 -07:00
|
|
|
if (mGeckoChild->GetLayerManager()->GetBackendType() == LAYERS_BASIC) {
|
2010-07-15 14:08:04 -07:00
|
|
|
nsBaseWidget::AutoLayerManagerSetup
|
2012-07-30 17:42:26 -07:00
|
|
|
setupLayerManager(mGeckoChild, targetContext, BUFFER_NONE);
|
2013-05-23 07:49:16 -07:00
|
|
|
painted = mGeckoChild->PaintWindow(region);
|
2013-05-09 14:02:49 -07:00
|
|
|
} else if (mGeckoChild->GetLayerManager()->GetBackendType() == LAYERS_CLIENT) {
|
|
|
|
// We only need this so that we actually get DidPaintWindow fired
|
2013-05-23 07:49:16 -07:00
|
|
|
painted = mGeckoChild->PaintWindow(region);
|
2010-03-01 00:03:49 -08:00
|
|
|
}
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
targetContext = nullptr;
|
|
|
|
targetSurface = nullptr;
|
|
|
|
|
|
|
|
CGContextRestoreGState(aContext);
|
|
|
|
|
|
|
|
// Undo the scale transform so that from now on the context is in
|
|
|
|
// CocoaPoints again.
|
|
|
|
CGContextRestoreGState(aContext);
|
|
|
|
|
2009-11-06 02:17:45 -08:00
|
|
|
if (!painted && [self isOpaque]) {
|
|
|
|
// Gecko refused to draw, but we've claimed to be opaque, so we have to
|
|
|
|
// draw something--fill with white.
|
|
|
|
CGContextSetRGBFillColor(aContext, 1, 1, 1, 1);
|
2012-09-29 04:36:09 -07:00
|
|
|
CGContextFillRect(aContext, NSRectToCGRect(aRect));
|
2009-11-06 02:17:45 -08:00
|
|
|
}
|
2010-01-13 08:08:06 -08:00
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
if ([self isCoveringTitlebar]) {
|
|
|
|
[self drawTitlebarHighlight];
|
|
|
|
[self maskTopCornersInContext:aContext];
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG_UPDATE
|
|
|
|
fprintf (stderr, "---- update done ----\n");
|
|
|
|
|
|
|
|
#if 0
|
2009-10-21 00:05:39 -07:00
|
|
|
CGContextSetRGBStrokeColor (aContext,
|
2007-03-22 10:30:00 -07:00
|
|
|
((((unsigned long)self) & 0xff)) / 255.0,
|
|
|
|
((((unsigned long)self) & 0xff00) >> 8) / 255.0,
|
|
|
|
((((unsigned long)self) & 0xff0000) >> 16) / 255.0,
|
|
|
|
0.5);
|
2012-09-29 04:36:09 -07:00
|
|
|
#endif
|
2009-10-21 00:05:39 -07:00
|
|
|
CGContextSetRGBStrokeColor(aContext, 1, 0, 0, 0.8);
|
|
|
|
CGContextSetLineWidth(aContext, 4.0);
|
2012-09-29 04:36:09 -07:00
|
|
|
CGContextStrokeRect(aContext, NSRectToCGRect(aRect));
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-05-23 07:55:50 -07:00
|
|
|
- (BOOL)isUsingMainThreadOpenGL
|
2013-03-05 07:21:28 -08:00
|
|
|
{
|
|
|
|
if (!mGeckoChild || ![self window])
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
return mGeckoChild->GetLayerManager(nullptr)->GetBackendType() == mozilla::layers::LAYERS_OPENGL;
|
|
|
|
}
|
|
|
|
|
2013-05-23 07:55:50 -07:00
|
|
|
- (BOOL)isUsingOpenGL
|
|
|
|
{
|
|
|
|
if (!mGeckoChild || ![self window])
|
|
|
|
return NO;
|
|
|
|
|
2013-10-09 07:39:22 -07:00
|
|
|
return mGLContext || mUsingOMTCompositor || [self isUsingMainThreadOpenGL];
|
2013-05-23 07:55:50 -07:00
|
|
|
}
|
|
|
|
|
2013-03-05 07:21:28 -08:00
|
|
|
- (void)drawUsingOpenGL
|
|
|
|
{
|
2013-03-15 21:47:02 -07:00
|
|
|
PROFILER_LABEL("widget", "ChildView::drawUsingOpenGL");
|
2013-03-05 07:21:28 -08:00
|
|
|
|
|
|
|
if (![self isUsingOpenGL] || !mGeckoChild->IsVisible())
|
|
|
|
return;
|
|
|
|
|
|
|
|
mWaitingForPaint = NO;
|
|
|
|
|
|
|
|
nsIntRect geckoBounds;
|
|
|
|
mGeckoChild->GetBounds(geckoBounds);
|
|
|
|
nsIntRegion region(geckoBounds);
|
|
|
|
|
2013-05-23 07:49:16 -07:00
|
|
|
mGeckoChild->PaintWindow(region);
|
2013-03-05 07:21:28 -08:00
|
|
|
|
|
|
|
// Force OpenGL to refresh the very first time we draw. This works around a
|
|
|
|
// Mac OS X bug that stops windows updating on OS X when we use OpenGL.
|
|
|
|
if (!mDidForceRefreshOpenGL) {
|
|
|
|
[self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0];
|
|
|
|
mDidForceRefreshOpenGL = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Called asynchronously after setNeedsDisplay in order to avoid entering the
|
|
|
|
// normal drawing machinery.
|
|
|
|
- (void)drawUsingOpenGLCallback
|
|
|
|
{
|
|
|
|
if (mWaitingForPaint) {
|
|
|
|
[self drawUsingOpenGL];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-27 08:49:02 -07:00
|
|
|
- (BOOL)hasRoundedBottomCorners
|
|
|
|
{
|
|
|
|
return [[self window] respondsToSelector:@selector(bottomCornerRounded)] &&
|
|
|
|
[[self window] bottomCornerRounded];
|
|
|
|
}
|
|
|
|
|
2013-05-23 07:49:17 -07:00
|
|
|
- (CGFloat)cornerRadius
|
2013-03-27 08:49:02 -07:00
|
|
|
{
|
2013-05-23 07:49:17 -07:00
|
|
|
NSView* frameView = [[[self window] contentView] superview];
|
|
|
|
if (!frameView || ![frameView respondsToSelector:@selector(roundedCornerRadius)])
|
2013-03-27 08:49:02 -07:00
|
|
|
return 4.0f;
|
2013-05-23 07:49:17 -07:00
|
|
|
return [frameView roundedCornerRadius];
|
2013-03-27 08:49:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Accelerated windows have two NSSurfaces:
|
|
|
|
// (1) The window's pixel buffer in the back and
|
|
|
|
// (2) the OpenGL view in the front.
|
2013-05-23 07:49:17 -07:00
|
|
|
// These two surfaces are composited by the window manager. Drawing into the
|
|
|
|
// CGContext which is provided by drawRect ends up in (1).
|
|
|
|
// When our window has rounded corners, the OpenGL view has transparent pixels
|
|
|
|
// in the corners. In these places the contents of the window's pixel buffer
|
|
|
|
// can show through. So we need to make sure that the pixel buffer is
|
2013-03-27 08:49:02 -07:00
|
|
|
// transparent in the corners so that no garbage reaches the screen.
|
|
|
|
// The contents of the pixel buffer in the rest of the window don't matter
|
2013-05-23 07:49:17 -07:00
|
|
|
// because they're covered by opaque pixels of the OpenGL context.
|
|
|
|
// Making the corners transparent works even though our window is
|
2013-03-27 08:49:02 -07:00
|
|
|
// declared "opaque" (in the NSWindow's isOpaque method).
|
2013-05-23 07:49:17 -07:00
|
|
|
- (void)clearCorners
|
2013-03-27 08:49:02 -07:00
|
|
|
{
|
2013-05-23 07:49:17 -07:00
|
|
|
CGFloat radius = [self cornerRadius];
|
|
|
|
CGFloat w = [self bounds].size.width, h = [self bounds].size.height;
|
2013-03-27 08:49:02 -07:00
|
|
|
[[NSColor clearColor] set];
|
2013-05-23 07:49:17 -07:00
|
|
|
|
|
|
|
if ([self isCoveringTitlebar]) {
|
|
|
|
NSRectFill(NSMakeRect(0, 0, radius, radius));
|
|
|
|
NSRectFill(NSMakeRect(w - radius, 0, radius, radius));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([self hasRoundedBottomCorners]) {
|
|
|
|
NSRectFill(NSMakeRect(0, h - radius, radius, radius));
|
|
|
|
NSRectFill(NSMakeRect(w - radius, h - radius, radius, radius));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is the analog of nsChildView::MaybeDrawRoundedCorners for CGContexts.
|
|
|
|
// We only need to mask the top corners here because Cocoa does the masking
|
|
|
|
// for the window's bottom corners automatically (starting with 10.7).
|
|
|
|
- (void)maskTopCornersInContext:(CGContextRef)aContext
|
|
|
|
{
|
|
|
|
CGFloat radius = [self cornerRadius];
|
|
|
|
int32_t devPixelCornerRadius = mGeckoChild->CocoaPointsToDevPixels(radius);
|
|
|
|
|
|
|
|
// First make sure that mTopLeftCornerMask is set up.
|
|
|
|
if (!mTopLeftCornerMask ||
|
|
|
|
int32_t(CGImageGetWidth(mTopLeftCornerMask)) != devPixelCornerRadius) {
|
|
|
|
CGImageRelease(mTopLeftCornerMask);
|
|
|
|
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
|
|
|
|
CGContextRef imgCtx = CGBitmapContextCreate(NULL,
|
|
|
|
devPixelCornerRadius,
|
|
|
|
devPixelCornerRadius,
|
|
|
|
8, devPixelCornerRadius * 4,
|
|
|
|
rgb, kCGImageAlphaPremultipliedFirst);
|
|
|
|
CGColorSpaceRelease(rgb);
|
|
|
|
DrawTopLeftCornerMask(imgCtx, devPixelCornerRadius);
|
|
|
|
mTopLeftCornerMask = CGBitmapContextCreateImage(imgCtx);
|
|
|
|
CGContextRelease(imgCtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// kCGBlendModeDestinationIn is the secret sauce which allows us to erase
|
|
|
|
// already painted pixels. It's defined as R = D * Sa: multiply all channels
|
|
|
|
// of the destination pixel with the alpha of the source pixel. In our case,
|
|
|
|
// the source is mTopLeftCornerMask.
|
|
|
|
CGContextSaveGState(aContext);
|
|
|
|
CGContextSetBlendMode(aContext, kCGBlendModeDestinationIn);
|
|
|
|
|
|
|
|
CGRect destRect = CGRectMake(0, 0, radius, radius);
|
|
|
|
|
|
|
|
// Erase the top left corner...
|
|
|
|
CGContextDrawImage(aContext, destRect, mTopLeftCornerMask);
|
|
|
|
|
|
|
|
// ... and the top right corner.
|
|
|
|
CGContextTranslateCTM(aContext, [self bounds].size.width, 0);
|
|
|
|
CGContextScaleCTM(aContext, -1, 1);
|
|
|
|
CGContextDrawImage(aContext, destRect, mTopLeftCornerMask);
|
|
|
|
|
|
|
|
CGContextRestoreGState(aContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)drawTitlebarHighlight
|
|
|
|
{
|
|
|
|
DrawTitlebarHighlight([self bounds].size, [self cornerRadius],
|
|
|
|
mGeckoChild->DevPixelsToCocoaPoints(1));
|
2013-03-27 08:49:02 -07:00
|
|
|
}
|
|
|
|
|
2011-01-25 13:21:35 -08:00
|
|
|
- (void)releaseWidgets:(NSArray*)aWidgetArray
|
|
|
|
{
|
|
|
|
if (!aWidgetArray) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NSInteger count = [aWidgetArray count];
|
|
|
|
for (NSInteger i = 0; i < count; ++i) {
|
|
|
|
NSNumber* pointer = (NSNumber*) [aWidgetArray objectAtIndex:i];
|
|
|
|
nsIWidget* widget = (nsIWidget*) [pointer unsignedIntegerValue];
|
|
|
|
NS_RELEASE(widget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-13 15:03:46 -08:00
|
|
|
- (void)viewWillDraw
|
|
|
|
{
|
2009-12-11 11:31:42 -08:00
|
|
|
if (mGeckoChild) {
|
2011-01-25 13:21:35 -08:00
|
|
|
// The OS normally *will* draw our NSWindow, no matter what we do here.
|
|
|
|
// But Gecko can delete our parent widget(s) (along with mGeckoChild)
|
2012-08-15 11:52:42 -07:00
|
|
|
// while processing a paint request, which closes our NSWindow and
|
2011-01-25 13:21:35 -08:00
|
|
|
// makes the OS throw an NSInternalInconsistencyException assertion when
|
|
|
|
// it tries to draw it. Sometimes the OS also aborts the browser process.
|
|
|
|
// So we need to retain our parent(s) here and not release it/them until
|
|
|
|
// the next time through the main thread's run loop. When we do this we
|
|
|
|
// also need to retain and release mGeckoChild, which holds a strong
|
|
|
|
// reference to us (otherwise we might have been deleted by the time
|
|
|
|
// releaseWidgets: is called on us). See bug 550392.
|
|
|
|
nsIWidget* parent = mGeckoChild->GetParent();
|
|
|
|
if (parent) {
|
|
|
|
NSMutableArray* widgetArray = [NSMutableArray arrayWithCapacity:3];
|
|
|
|
while (parent) {
|
|
|
|
NS_ADDREF(parent);
|
|
|
|
[widgetArray addObject:[NSNumber numberWithUnsignedInteger:(NSUInteger)parent]];
|
|
|
|
parent = parent->GetParent();
|
|
|
|
}
|
|
|
|
NS_ADDREF(mGeckoChild);
|
|
|
|
[widgetArray addObject:[NSNumber numberWithUnsignedInteger:(NSUInteger)mGeckoChild]];
|
|
|
|
[self performSelector:@selector(releaseWidgets:)
|
|
|
|
withObject:widgetArray
|
|
|
|
afterDelay:0];
|
|
|
|
}
|
2012-08-15 11:52:42 -07:00
|
|
|
|
2013-06-20 05:59:16 -07:00
|
|
|
if ([self isUsingOpenGL]) {
|
|
|
|
// When our view covers the titlebar, we need to repaint the titlebar
|
|
|
|
// texture buffer when, for example, the window buttons are hovered.
|
|
|
|
// So we notify our nsChildView about any areas needing repainting.
|
|
|
|
mGeckoChild->NotifyDirtyRegion([self nativeDirtyRegionWithBoundingRect:[self bounds]]);
|
2013-06-20 06:01:20 -07:00
|
|
|
|
|
|
|
if (mGeckoChild->GetLayerManager()->GetBackendType() == LAYERS_CLIENT) {
|
|
|
|
ClientLayerManager *manager = static_cast<ClientLayerManager*>(mGeckoChild->GetLayerManager());
|
2013-11-27 07:19:34 -08:00
|
|
|
manager->AsShadowForwarder()->WindowOverlayChanged();
|
2013-06-20 06:01:20 -07:00
|
|
|
}
|
2013-06-20 05:59:16 -07:00
|
|
|
}
|
|
|
|
|
2013-02-25 13:18:48 -08:00
|
|
|
mGeckoChild->WillPaintWindow();
|
2009-12-11 11:31:42 -08:00
|
|
|
}
|
|
|
|
[super viewWillDraw];
|
2009-11-13 15:03:46 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#if USE_CLICK_HOLD_CONTEXTMENU
|
|
|
|
//
|
|
|
|
// -clickHoldCallback:
|
|
|
|
//
|
|
|
|
// called from a timer two seconds after a mouse down to see if we should display
|
|
|
|
// a context menu (click-hold). |anEvent| is the original mouseDown event. If we're
|
|
|
|
// still in that mouseDown by this time, put up the context menu, otherwise just
|
|
|
|
// fuhgeddaboutit. |anEvent| has been retained by the OS until after this callback
|
|
|
|
// fires so we're ok there.
|
|
|
|
//
|
|
|
|
// This code currently messes in a bunch of edge cases (bugs 234751, 232964, 232314)
|
|
|
|
// so removing it until we get it straightened out.
|
|
|
|
//
|
|
|
|
- (void)clickHoldCallback:(id)theEvent;
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if( theEvent == [NSApp currentEvent] ) {
|
|
|
|
// we're still in the middle of the same mousedown event here, activate
|
|
|
|
// click-hold context menu by triggering the right mouseDown action.
|
|
|
|
NSEvent* clickHoldEvent = [NSEvent mouseEventWithType:NSRightMouseDown
|
|
|
|
location:[theEvent locationInWindow]
|
2010-02-23 15:30:39 -08:00
|
|
|
modifierFlags:[theEvent modifierFlags]
|
2007-03-22 10:30:00 -07:00
|
|
|
timestamp:[theEvent timestamp]
|
|
|
|
windowNumber:[theEvent windowNumber]
|
|
|
|
context:[theEvent context]
|
|
|
|
eventNumber:[theEvent eventNumber]
|
|
|
|
clickCount:[theEvent clickCount]
|
|
|
|
pressure:[theEvent pressure]];
|
|
|
|
[self rightMouseDown:clickHoldEvent];
|
|
|
|
}
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-07-17 13:29:39 -07:00
|
|
|
// If we've just created a non-native context menu, we need to mark it as
|
|
|
|
// such and let the OS (and other programs) know when it opens and closes
|
|
|
|
// (this is how the OS knows to close other programs' context menus when
|
|
|
|
// ours open). We send the initial notification here, but others are sent
|
|
|
|
// in nsCocoaWindow::Show().
|
|
|
|
- (void)maybeInitContextMenuTracking
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2011-06-21 14:00:47 -07:00
|
|
|
#ifdef MOZ_USE_NATIVE_POPUP_WINDOWS
|
|
|
|
return;
|
|
|
|
#endif /* MOZ_USE_NATIVE_POPUP_WINDOWS */
|
2008-03-04 00:06:47 -08:00
|
|
|
|
2012-10-26 06:15:22 -07:00
|
|
|
nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
|
2012-12-31 09:27:04 -08:00
|
|
|
NS_ENSURE_TRUE_VOID(rollupListener);
|
2012-10-26 06:15:22 -07:00
|
|
|
nsCOMPtr<nsIWidget> widget = rollupListener->GetRollupWidget();
|
2012-12-31 09:27:04 -08:00
|
|
|
NS_ENSURE_TRUE_VOID(widget);
|
2012-10-26 06:15:22 -07:00
|
|
|
|
|
|
|
NSWindow *popupWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
|
2007-11-06 23:53:24 -08:00
|
|
|
if (!popupWindow || ![popupWindow isKindOfClass:[PopupWindow class]])
|
2007-07-17 13:29:39 -07:00
|
|
|
return;
|
2007-11-06 23:53:24 -08:00
|
|
|
|
2007-07-17 13:29:39 -07:00
|
|
|
[[NSDistributedNotificationCenter defaultCenter]
|
|
|
|
postNotificationName:@"com.apple.HIToolbox.beginMenuTrackingNotification"
|
|
|
|
object:@"org.mozilla.gecko.PopupWindow"];
|
2007-11-06 23:53:24 -08:00
|
|
|
[(PopupWindow*)popupWindow setIsContextMenu:YES];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-07-17 13:29:39 -07:00
|
|
|
}
|
|
|
|
|
2009-05-14 13:13:22 -07:00
|
|
|
// Returns true if the event should no longer be processed, false otherwise.
|
|
|
|
// This does not return whether or not anything was rolled up.
|
2007-11-26 15:19:04 -08:00
|
|
|
- (BOOL)maybeRollup:(NSEvent*)theEvent
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
2009-05-14 13:13:22 -07:00
|
|
|
BOOL consumeEvent = NO;
|
|
|
|
|
2012-10-26 06:15:22 -07:00
|
|
|
nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
|
2012-12-31 09:27:04 -08:00
|
|
|
NS_ENSURE_TRUE(rollupListener, false);
|
2012-10-26 06:15:22 -07:00
|
|
|
nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
|
|
|
|
if (rollupWidget) {
|
|
|
|
NSWindow* currentPopup = static_cast<NSWindow*>(rollupWidget->GetNativeData(NS_NATIVE_WINDOW));
|
2007-12-05 15:17:08 -08:00
|
|
|
if (!nsCocoaUtils::IsEventOverWindow(theEvent, currentPopup)) {
|
2009-05-14 13:13:22 -07:00
|
|
|
// event is not over the rollup window, default is to roll up
|
2011-09-28 23:19:26 -07:00
|
|
|
bool shouldRollup = true;
|
2009-05-14 13:13:22 -07:00
|
|
|
|
|
|
|
// check to see if scroll events should roll up the popup
|
2007-11-26 15:19:04 -08:00
|
|
|
if ([theEvent type] == NSScrollWheel) {
|
2012-10-26 06:15:22 -07:00
|
|
|
shouldRollup = rollupListener->ShouldRollupOnMouseWheelEvent();
|
2013-03-08 11:48:48 -08:00
|
|
|
// consume scroll events that aren't over the popup
|
|
|
|
// unless the popup is an arrow panel
|
|
|
|
consumeEvent = rollupListener->ShouldConsumeOnMouseWheelEvent();
|
2007-11-26 15:19:04 -08:00
|
|
|
}
|
2009-05-14 13:13:22 -07:00
|
|
|
|
2007-11-26 15:19:04 -08:00
|
|
|
// if we're dealing with menus, we probably have submenus and
|
2008-04-06 16:52:05 -07:00
|
|
|
// we don't want to rollup if the click is in a parent menu of
|
2007-11-26 15:19:04 -08:00
|
|
|
// the current submenu
|
2012-09-27 23:57:33 -07:00
|
|
|
uint32_t popupsToRollup = UINT32_MAX;
|
2012-10-26 06:15:22 -07:00
|
|
|
nsAutoTArray<nsIWidget*, 5> widgetChain;
|
|
|
|
uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
|
|
|
|
for (uint32_t i = 0; i < widgetChain.Length(); i++) {
|
|
|
|
nsIWidget* widget = widgetChain[i];
|
|
|
|
NSWindow* currWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
if (nsCocoaUtils::IsEventOverWindow(theEvent, currWindow)) {
|
|
|
|
// don't roll up if the mouse event occurred within a menu of the
|
|
|
|
// same type. If the mouse event occurred in a menu higher than
|
|
|
|
// that, roll up, but pass the number of popups to Rollup so
|
|
|
|
// that only those of the same type close up.
|
|
|
|
if (i < sameTypeCount) {
|
|
|
|
shouldRollup = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
popupsToRollup = sameTypeCount;
|
2008-01-16 23:06:43 -08:00
|
|
|
}
|
2012-10-26 06:15:22 -07:00
|
|
|
break;
|
2009-05-14 13:13:22 -07:00
|
|
|
}
|
|
|
|
}
|
2007-11-06 23:53:24 -08:00
|
|
|
|
2009-05-14 13:13:22 -07:00
|
|
|
if (shouldRollup) {
|
2013-11-04 08:22:24 -08:00
|
|
|
if ([theEvent type] == NSLeftMouseDown) {
|
|
|
|
NSPoint point = [NSEvent mouseLocation];
|
|
|
|
FlipCocoaScreenCoordinate(point);
|
|
|
|
nsIntPoint pos(point.x, point.y);
|
|
|
|
consumeEvent = (BOOL)rollupListener->Rollup(popupsToRollup, &pos, nullptr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
consumeEvent = (BOOL)rollupListener->Rollup(popupsToRollup, nullptr, nullptr);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-11-26 15:19:04 -08:00
|
|
|
|
2009-05-14 13:13:22 -07:00
|
|
|
return consumeEvent;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
|
2007-11-26 15:19:04 -08:00
|
|
|
}
|
|
|
|
|
2008-10-23 13:15:20 -07:00
|
|
|
/*
|
2013-04-29 08:24:26 -07:00
|
|
|
* In OS X Mountain Lion and above, smart zoom gestures are implemented in
|
|
|
|
* smartMagnifyWithEvent. In OS X Lion, they are implemented in
|
|
|
|
* magnifyWithEvent. See inline comments for more info.
|
2008-10-23 13:15:20 -07:00
|
|
|
*
|
2013-04-29 08:24:26 -07:00
|
|
|
* The prototypes swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
|
|
|
|
* smartMagnifyWithEvent, rotateWithEvent, and endGestureWithEvent were
|
|
|
|
* obtained from the following links:
|
|
|
|
* https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/Reference/Reference.html
|
|
|
|
* https://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKit.html
|
2008-10-23 13:15:20 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
- (void)swipeWithEvent:(NSEvent *)anEvent
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
if (!anEvent || !mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
float deltaX = [anEvent deltaX]; // left=1.0, right=-1.0
|
|
|
|
float deltaY = [anEvent deltaY]; // up=1.0, down=-1.0
|
|
|
|
|
|
|
|
// Setup the "swipe" event.
|
2013-09-26 23:20:57 -07:00
|
|
|
WidgetSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_SWIPE,
|
|
|
|
mGeckoChild, 0, 0.0);
|
2009-01-03 04:40:26 -08:00
|
|
|
[self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
|
2008-10-23 13:15:20 -07:00
|
|
|
|
|
|
|
// Record the left/right direction.
|
|
|
|
if (deltaX > 0.0)
|
|
|
|
geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
|
|
|
|
else if (deltaX < 0.0)
|
|
|
|
geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
|
|
|
|
|
|
|
|
// Record the up/down direction.
|
|
|
|
if (deltaY > 0.0)
|
|
|
|
geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_UP;
|
|
|
|
else if (deltaY < 0.0)
|
|
|
|
geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
|
|
|
|
|
|
|
|
// Send the event.
|
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)beginGestureWithEvent:(NSEvent *)anEvent
|
|
|
|
{
|
|
|
|
if (!anEvent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mGestureState = eGestureState_StartGesture;
|
|
|
|
mCumulativeMagnification = 0;
|
|
|
|
mCumulativeRotation = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)magnifyWithEvent:(NSEvent *)anEvent
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
if (!anEvent || !mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2013-04-29 08:24:26 -07:00
|
|
|
/*
|
|
|
|
* In OS X 10.7.* (Lion), smart zoom events come through magnifyWithEvent,
|
|
|
|
* instead of smartMagnifyWithEvent. See bug 863841.
|
|
|
|
*/
|
|
|
|
if ([ChildView isLionSmartMagnifyEvent: anEvent]) {
|
|
|
|
[self smartMagnifyWithEvent: anEvent];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-10-23 13:15:20 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
float deltaZ = [anEvent deltaZ];
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t msg;
|
2008-10-23 13:15:20 -07:00
|
|
|
switch (mGestureState) {
|
|
|
|
case eGestureState_StartGesture:
|
|
|
|
msg = NS_SIMPLE_GESTURE_MAGNIFY_START;
|
|
|
|
mGestureState = eGestureState_MagnifyGesture;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eGestureState_MagnifyGesture:
|
|
|
|
msg = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eGestureState_None:
|
|
|
|
case eGestureState_RotateGesture:
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the event.
|
2013-09-26 23:20:57 -07:00
|
|
|
WidgetSimpleGestureEvent geckoEvent(true, msg, mGeckoChild, 0, deltaZ);
|
2009-01-03 04:40:26 -08:00
|
|
|
[self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
|
2008-10-23 13:15:20 -07:00
|
|
|
|
|
|
|
// Send the event.
|
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
|
|
|
|
// Keep track of the cumulative magnification for the final "magnify" event.
|
|
|
|
mCumulativeMagnification += deltaZ;
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2013-04-29 08:24:26 -07:00
|
|
|
- (void)smartMagnifyWithEvent:(NSEvent *)anEvent
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
if (!anEvent || !mGeckoChild) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
// Setup the "double tap" event.
|
2013-09-26 23:20:57 -07:00
|
|
|
WidgetSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_TAP,
|
|
|
|
mGeckoChild, 0, 0.0);
|
2013-04-29 08:24:26 -07:00
|
|
|
[self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
|
|
|
|
geckoEvent.clickCount = 1;
|
|
|
|
|
|
|
|
// Send the event.
|
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
|
|
|
|
// Clear the gesture state
|
|
|
|
mGestureState = eGestureState_None;
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2008-10-23 13:15:20 -07:00
|
|
|
- (void)rotateWithEvent:(NSEvent *)anEvent
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
if (!anEvent || !mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
float rotation = [anEvent rotation];
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t msg;
|
2008-10-23 13:15:20 -07:00
|
|
|
switch (mGestureState) {
|
|
|
|
case eGestureState_StartGesture:
|
|
|
|
msg = NS_SIMPLE_GESTURE_ROTATE_START;
|
|
|
|
mGestureState = eGestureState_RotateGesture;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eGestureState_RotateGesture:
|
|
|
|
msg = NS_SIMPLE_GESTURE_ROTATE_UPDATE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eGestureState_None:
|
|
|
|
case eGestureState_MagnifyGesture:
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the event.
|
2013-09-26 23:20:57 -07:00
|
|
|
WidgetSimpleGestureEvent geckoEvent(true, msg, mGeckoChild, 0, 0.0);
|
2009-01-03 04:40:26 -08:00
|
|
|
[self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
|
2008-10-23 13:15:20 -07:00
|
|
|
geckoEvent.delta = -rotation;
|
|
|
|
if (rotation > 0.0) {
|
2009-04-02 12:34:31 -07:00
|
|
|
geckoEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE;
|
2008-10-23 13:15:20 -07:00
|
|
|
} else {
|
2009-04-02 12:34:31 -07:00
|
|
|
geckoEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE;
|
2008-10-23 13:15:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Send the event.
|
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
|
|
|
|
// Keep track of the cumulative rotation for the final "rotate" event.
|
|
|
|
mCumulativeRotation += rotation;
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)endGestureWithEvent:(NSEvent *)anEvent
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
if (!anEvent || !mGeckoChild) {
|
|
|
|
// Clear the gestures state if we cannot send an event.
|
|
|
|
mGestureState = eGestureState_None;
|
|
|
|
mCumulativeMagnification = 0.0;
|
|
|
|
mCumulativeRotation = 0.0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
switch (mGestureState) {
|
|
|
|
case eGestureState_MagnifyGesture:
|
|
|
|
{
|
|
|
|
// Setup the "magnify" event.
|
2013-09-26 23:20:57 -07:00
|
|
|
WidgetSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_MAGNIFY,
|
|
|
|
mGeckoChild, 0,
|
|
|
|
mCumulativeMagnification);
|
2009-01-03 04:40:26 -08:00
|
|
|
[self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
|
2008-10-23 13:15:20 -07:00
|
|
|
|
|
|
|
// Send the event.
|
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eGestureState_RotateGesture:
|
|
|
|
{
|
|
|
|
// Setup the "rotate" event.
|
2013-09-26 23:20:57 -07:00
|
|
|
WidgetSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_ROTATE,
|
|
|
|
mGeckoChild, 0, 0.0);
|
2009-01-03 04:40:26 -08:00
|
|
|
[self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
|
2008-10-23 13:15:20 -07:00
|
|
|
geckoEvent.delta = -mCumulativeRotation;
|
|
|
|
if (mCumulativeRotation > 0.0) {
|
2009-04-02 12:34:31 -07:00
|
|
|
geckoEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE;
|
2008-10-23 13:15:20 -07:00
|
|
|
} else {
|
2009-04-02 12:34:31 -07:00
|
|
|
geckoEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE;
|
2008-10-23 13:15:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Send the event.
|
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eGestureState_None:
|
|
|
|
case eGestureState_StartGesture:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear the gestures state.
|
|
|
|
mGestureState = eGestureState_None;
|
|
|
|
mCumulativeMagnification = 0.0;
|
|
|
|
mCumulativeRotation = 0.0;
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2013-04-29 08:24:26 -07:00
|
|
|
+ (BOOL)isLionSmartMagnifyEvent:(NSEvent*)anEvent
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* On Lion, smart zoom events have type NSEventTypeGesture, subtype 0x16,
|
|
|
|
* whereas pinch zoom events have type NSEventTypeMagnify. So, use that to
|
|
|
|
* discriminate between the two. Smart zoom gestures do not call
|
|
|
|
* beginGestureWithEvent or endGestureWithEvent, so mGestureState is not
|
|
|
|
* changed. Documentation couldn't be found for the meaning of the subtype
|
|
|
|
* 0x16, but it will probably never change. See bug 863841.
|
|
|
|
*/
|
|
|
|
return nsCocoaFeatures::OnLionOrLater() &&
|
|
|
|
!nsCocoaFeatures::OnMountainLionOrLater() &&
|
|
|
|
[anEvent type] == NSEventTypeGesture &&
|
|
|
|
[anEvent subtype] == 0x16;
|
|
|
|
}
|
|
|
|
|
2013-04-09 12:44:01 -07:00
|
|
|
#ifdef __LP64__
|
|
|
|
- (bool)sendSwipeEvent:(NSEvent*)aEvent
|
2013-06-12 18:26:59 -07:00
|
|
|
withKind:(uint32_t)aMsg
|
|
|
|
allowedDirections:(uint32_t*)aAllowedDirections
|
|
|
|
direction:(uint32_t)aDirection
|
|
|
|
delta:(double)aDelta
|
2013-04-09 12:44:01 -07:00
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return false;
|
|
|
|
|
2013-09-26 23:20:57 -07:00
|
|
|
WidgetSimpleGestureEvent geckoEvent(true, aMsg, mGeckoChild,
|
|
|
|
aDirection, aDelta);
|
2013-04-09 12:44:01 -07:00
|
|
|
geckoEvent.allowedDirections = *aAllowedDirections;
|
|
|
|
[self convertCocoaMouseEvent:aEvent toGeckoEvent:&geckoEvent];
|
|
|
|
bool eventCancelled = mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
*aAllowedDirections = geckoEvent.allowedDirections;
|
|
|
|
return eventCancelled; // event cancelled == swipe should start
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)sendSwipeEndEvent:(NSEvent *)anEvent
|
2013-06-12 18:26:59 -07:00
|
|
|
allowedDirections:(uint32_t)aAllowedDirections
|
2013-04-09 12:44:01 -07:00
|
|
|
{
|
|
|
|
// Tear down animation overlay by sending a swipe end event.
|
2013-06-12 18:26:59 -07:00
|
|
|
uint32_t allowedDirectionsCopy = aAllowedDirections;
|
2013-04-09 12:44:01 -07:00
|
|
|
[self sendSwipeEvent:anEvent
|
|
|
|
withKind:NS_SIMPLE_GESTURE_SWIPE_END
|
|
|
|
allowedDirections:&allowedDirectionsCopy
|
|
|
|
direction:0
|
|
|
|
delta:0.0];
|
|
|
|
}
|
|
|
|
|
2013-10-11 12:48:53 -07:00
|
|
|
// Support fluid swipe tracking on OS X 10.7 and higher. We must be careful
|
|
|
|
// to only invoke this support on a two-finger gesture that really
|
2011-08-11 10:42:23 -07:00
|
|
|
// is a swipe (and not a scroll) -- in other words, the app is responsible
|
2013-10-11 12:48:53 -07:00
|
|
|
// for deciding which is which. But once the decision is made, the OS tracks
|
2011-08-11 10:42:23 -07:00
|
|
|
// the swipe until it has finished, and decides whether or not it succeeded.
|
2013-10-11 12:48:53 -07:00
|
|
|
// A horizontal swipe has the same functionality as the Back and Forward
|
|
|
|
// buttons.
|
|
|
|
// This method is partly based on Apple sample code available at
|
|
|
|
// developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html
|
|
|
|
// (under Fluid Swipe Tracking API).
|
2011-08-11 10:42:23 -07:00
|
|
|
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
|
2013-10-11 12:48:53 -07:00
|
|
|
scrollOverflowX:(double)anOverflowX
|
|
|
|
scrollOverflowY:(double)anOverflowY
|
|
|
|
viewPortIsOverscrolled:(BOOL)aViewPortIsOverscrolled
|
2011-08-11 10:42:23 -07:00
|
|
|
{
|
2012-05-17 00:53:20 -07:00
|
|
|
if (!nsCocoaFeatures::OnLionOrLater()) {
|
2011-08-11 10:42:23 -07:00
|
|
|
return;
|
|
|
|
}
|
2013-04-12 20:04:52 -07:00
|
|
|
|
2011-08-11 10:42:23 -07:00
|
|
|
// This method checks whether the AppleEnableSwipeNavigateWithScrolls global
|
|
|
|
// preference is set. If it isn't, fluid swipe tracking is disabled, and a
|
|
|
|
// horizontal two-finger gesture is always a scroll (even in Safari). This
|
|
|
|
// preference can't (currently) be set from the Preferences UI -- only using
|
|
|
|
// 'defaults write'.
|
|
|
|
if (![NSEvent isSwipeTrackingFromScrollEventsEnabled]) {
|
|
|
|
return;
|
|
|
|
}
|
2013-04-12 20:04:52 -07:00
|
|
|
|
2013-10-11 12:48:53 -07:00
|
|
|
// We should only track scroll events as swipe if the viewport is being
|
|
|
|
// overscrolled.
|
|
|
|
if (!aViewPortIsOverscrolled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-23 06:02:55 -07:00
|
|
|
// Verify that this is a scroll wheel event with proper phase to be tracked
|
|
|
|
// by the OS.
|
|
|
|
if ([anEvent type] != NSScrollWheel || [anEvent phase] == NSEventPhaseNone) {
|
2011-08-11 10:42:23 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only initiate tracking if the user has tried to scroll past the edge of
|
2013-10-11 12:48:53 -07:00
|
|
|
// the current page (as indicated by 'anOverflowX' or 'anOverflowY' being
|
|
|
|
// non-zero). Gecko only sets WidgetMouseScrollEvent.scrollOverflow when it's
|
|
|
|
// processing NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
|
|
|
|
if (anOverflowX == 0.0 && anOverflowY == 0.0) {
|
2013-08-21 09:22:03 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-08-11 10:42:23 -07:00
|
|
|
CGFloat deltaX, deltaY;
|
|
|
|
if ([anEvent hasPreciseScrollingDeltas]) {
|
|
|
|
deltaX = [anEvent scrollingDeltaX];
|
|
|
|
deltaY = [anEvent scrollingDeltaY];
|
2013-08-21 09:22:03 -07:00
|
|
|
} else {
|
2013-10-11 12:48:53 -07:00
|
|
|
return;
|
2013-08-21 09:22:03 -07:00
|
|
|
}
|
2013-09-23 06:02:55 -07:00
|
|
|
|
2013-10-11 12:48:53 -07:00
|
|
|
uint32_t vDirs = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN |
|
|
|
|
(uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP;
|
2013-09-23 06:02:55 -07:00
|
|
|
uint32_t direction = 0;
|
2013-10-11 12:48:53 -07:00
|
|
|
|
2013-09-23 06:02:55 -07:00
|
|
|
// Only initiate horizontal tracking for events whose horizontal element is
|
|
|
|
// at least eight times larger than its vertical element. This minimizes
|
|
|
|
// performance problems with vertical scrolls (by minimizing the possibility
|
|
|
|
// that they'll be misinterpreted as horizontal swipes), while still
|
|
|
|
// tolerating a small vertical element to a true horizontal swipe. The number
|
|
|
|
// '8' was arrived at by trial and error.
|
2013-10-11 12:48:53 -07:00
|
|
|
if (anOverflowX != 0.0 && deltaX != 0.0 &&
|
2013-09-23 06:02:55 -07:00
|
|
|
fabsf(deltaX) > fabsf(deltaY) * 8) {
|
|
|
|
// Only initiate horizontal tracking for gestures that have just begun --
|
|
|
|
// otherwise a scroll to one side of the page can have a swipe tacked on
|
|
|
|
// to it.
|
|
|
|
if ([anEvent phase] != NSEventPhaseBegan) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (deltaX < 0.0) {
|
|
|
|
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
|
|
|
|
} else {
|
|
|
|
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
|
|
|
|
}
|
2013-10-11 12:48:53 -07:00
|
|
|
}
|
|
|
|
// Only initiate vertical tracking for events whose vertical element is
|
|
|
|
// at least two times larger than its horizontal element. This minimizes
|
|
|
|
// performance problems. The number '2' was arrived at by trial and error.
|
|
|
|
else if (anOverflowY != 0.0 && deltaY != 0.0 &&
|
|
|
|
fabsf(deltaY) > fabsf(deltaX) * 2) {
|
|
|
|
if (deltaY < 0.0) {
|
|
|
|
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
|
|
|
|
} else {
|
|
|
|
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mCurrentSwipeDir & vDirs) && (mCurrentSwipeDir != direction)) {
|
|
|
|
// If a swipe is currently being tracked kill it -- it's been interrupted
|
|
|
|
// by another gesture event.
|
|
|
|
if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
|
|
|
|
*mCancelSwipeAnimation = YES;
|
|
|
|
mCancelSwipeAnimation = nil;
|
|
|
|
[self sendSwipeEndEvent:anEvent allowedDirections:0];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2013-09-23 06:02:55 -07:00
|
|
|
} else {
|
2013-04-12 20:04:52 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-11 12:48:53 -07:00
|
|
|
// Track the direction we're going in.
|
|
|
|
mCurrentSwipeDir = direction;
|
|
|
|
|
2013-09-23 06:02:55 -07:00
|
|
|
uint32_t allowedDirections = 0;
|
2013-04-09 12:44:01 -07:00
|
|
|
// We're ready to start the animation. Tell Gecko about it, and at the same
|
|
|
|
// time ask it if it really wants to start an animation for this event.
|
|
|
|
// This event also reports back the directions that we can swipe in.
|
|
|
|
bool shouldStartSwipe = [self sendSwipeEvent:anEvent
|
2013-09-23 06:02:55 -07:00
|
|
|
withKind:NS_SIMPLE_GESTURE_SWIPE_START
|
|
|
|
allowedDirections:&allowedDirections
|
|
|
|
direction:direction
|
|
|
|
delta:0.0];
|
2013-04-09 12:44:01 -07:00
|
|
|
|
|
|
|
if (!shouldStartSwipe) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-16 06:07:42 -07:00
|
|
|
// If a swipe is currently being tracked kill it -- it's been interrupted
|
|
|
|
// by another gesture event.
|
|
|
|
if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
|
|
|
|
*mCancelSwipeAnimation = YES;
|
|
|
|
mCancelSwipeAnimation = nil;
|
|
|
|
}
|
|
|
|
|
2013-10-11 12:48:53 -07:00
|
|
|
CGFloat min = 0.0;
|
|
|
|
CGFloat max = 0.0;
|
|
|
|
if (!(direction & vDirs)) {
|
|
|
|
min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ?
|
|
|
|
-1.0 : 0.0;
|
|
|
|
max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ?
|
|
|
|
1.0 : 0.0;
|
|
|
|
}
|
2013-04-09 12:44:01 -07:00
|
|
|
|
2013-09-23 06:02:55 -07:00
|
|
|
__block BOOL animationCanceled = NO;
|
2013-08-21 09:22:03 -07:00
|
|
|
__block BOOL geckoSwipeEventSent = NO;
|
2011-08-11 10:42:23 -07:00
|
|
|
// At this point, anEvent is the first scroll wheel event in a two-finger
|
|
|
|
// horizontal gesture that we've decided to treat as a swipe. When we call
|
|
|
|
// [NSEvent trackSwipeEventWithOptions:...], the OS interprets all
|
|
|
|
// subsequent scroll wheel events that are part of this gesture as a swipe,
|
|
|
|
// and stops sending them to us. The OS calls the trackingHandler "block"
|
|
|
|
// multiple times, asynchronously (sometimes after [NSEvent
|
|
|
|
// maybeTrackScrollEventAsSwipe:...] has returned). The OS determines when
|
|
|
|
// the gesture has finished, and whether or not it was "successful" -- this
|
|
|
|
// information is passed to trackingHandler. We must be careful to only
|
|
|
|
// call [NSEvent maybeTrackScrollEventAsSwipe:...] on a "real" swipe --
|
|
|
|
// otherwise two-finger scrolling performance will suffer significantly.
|
2011-09-08 06:31:09 -07:00
|
|
|
// Note that we use anEvent inside the block. This extends the lifetime of
|
|
|
|
// the anEvent object because it's retained by the block, see bug 682445.
|
|
|
|
// The block will release it when the block goes away at the end of the
|
|
|
|
// animation, or when the animation is canceled.
|
2013-09-23 06:02:55 -07:00
|
|
|
[anEvent trackSwipeEventWithOptions:NSEventSwipeTrackingLockDirection |
|
|
|
|
NSEventSwipeTrackingClampGestureAmount
|
2013-04-09 12:44:01 -07:00
|
|
|
dampenAmountThresholdMin:min
|
|
|
|
max:max
|
2013-09-23 06:02:55 -07:00
|
|
|
usingHandler:^(CGFloat gestureAmount,
|
|
|
|
NSEventPhase phase,
|
|
|
|
BOOL isComplete,
|
|
|
|
BOOL *stop) {
|
|
|
|
uint32_t allowedDirectionsCopy = allowedDirections;
|
|
|
|
// Since this tracking handler can be called asynchronously, mGeckoChild
|
|
|
|
// might have become NULL here (our child widget might have been
|
|
|
|
// destroyed).
|
|
|
|
// Checking for gestureAmount == 0.0 also works around bug 770626, which
|
|
|
|
// happens when DispatchWindowEvent() triggers a modal dialog, which spins
|
|
|
|
// the event loop and confuses the OS. This results in several re-entrant
|
|
|
|
// calls to this handler.
|
|
|
|
if (animationCanceled || !mGeckoChild || gestureAmount == 0.0) {
|
|
|
|
*stop = YES;
|
|
|
|
animationCanceled = YES;
|
2013-10-11 12:48:53 -07:00
|
|
|
if (gestureAmount == 0.0 ||
|
|
|
|
((direction & vDirs) && (direction != mCurrentSwipeDir))) {
|
2013-09-23 06:02:55 -07:00
|
|
|
if (mCancelSwipeAnimation)
|
|
|
|
*mCancelSwipeAnimation = YES;
|
|
|
|
mCancelSwipeAnimation = nil;
|
|
|
|
[self sendSwipeEndEvent:anEvent
|
|
|
|
allowedDirections:allowedDirectionsCopy];
|
2011-08-11 10:42:23 -07:00
|
|
|
}
|
2013-10-11 12:48:53 -07:00
|
|
|
mCurrentSwipeDir = 0;
|
2013-09-23 06:02:55 -07:00
|
|
|
return;
|
|
|
|
}
|
2013-04-09 12:44:01 -07:00
|
|
|
|
2013-09-23 06:02:55 -07:00
|
|
|
// Update animation overlay to match gestureAmount.
|
|
|
|
[self sendSwipeEvent:anEvent
|
|
|
|
withKind:NS_SIMPLE_GESTURE_SWIPE_UPDATE
|
|
|
|
allowedDirections:&allowedDirectionsCopy
|
|
|
|
direction:0.0
|
|
|
|
delta:gestureAmount];
|
|
|
|
|
|
|
|
if (phase == NSEventPhaseEnded && !geckoSwipeEventSent) {
|
|
|
|
// The result of the swipe is now known, so the main event can be sent.
|
|
|
|
// The animation might continue even after this event was sent, so
|
|
|
|
// don't tear down the animation overlay yet.
|
|
|
|
|
|
|
|
uint32_t directionCopy = direction;
|
|
|
|
|
|
|
|
// gestureAmount is documented to be '-1', '0' or '1' when isComplete
|
|
|
|
// is TRUE, but the docs don't say anything about its value at other
|
|
|
|
// times. However, tests show that, when phase == NSEventPhaseEnded,
|
|
|
|
// gestureAmount is negative when it will be '-1' at isComplete, and
|
|
|
|
// positive when it will be '1'. And phase is never equal to
|
|
|
|
// NSEventPhaseEnded when gestureAmount will be '0' at isComplete.
|
|
|
|
geckoSwipeEventSent = YES;
|
2013-04-09 12:44:01 -07:00
|
|
|
[self sendSwipeEvent:anEvent
|
2013-09-23 06:02:55 -07:00
|
|
|
withKind:NS_SIMPLE_GESTURE_SWIPE
|
2013-04-09 12:44:01 -07:00
|
|
|
allowedDirections:&allowedDirectionsCopy
|
2013-09-23 06:02:55 -07:00
|
|
|
direction:directionCopy
|
|
|
|
delta:0.0];
|
|
|
|
}
|
2013-04-09 12:44:01 -07:00
|
|
|
|
2013-09-23 06:02:55 -07:00
|
|
|
if (isComplete) {
|
|
|
|
[self sendSwipeEndEvent:anEvent allowedDirections:allowedDirectionsCopy];
|
2013-10-11 12:48:53 -07:00
|
|
|
mCurrentSwipeDir = 0;
|
2013-09-23 06:02:55 -07:00
|
|
|
mCancelSwipeAnimation = nil;
|
|
|
|
}
|
|
|
|
}];
|
2011-08-11 10:42:23 -07:00
|
|
|
|
2013-09-23 06:02:55 -07:00
|
|
|
mCancelSwipeAnimation = &animationCanceled;
|
2011-08-11 10:42:23 -07:00
|
|
|
}
|
|
|
|
#endif // #ifdef __LP64__
|
|
|
|
|
2012-01-19 06:45:37 -08:00
|
|
|
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC
|
|
|
|
{
|
|
|
|
mUsingOMTCompositor = aUseOMTC;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-11 13:57:40 -08:00
|
|
|
// Returning NO from this method only disallows ordering on mousedown - in order
|
|
|
|
// to prevent it for mouseup too, we need to call [NSApp preventWindowOrdering]
|
|
|
|
// when handling the mousedown event.
|
|
|
|
- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent*)aEvent
|
|
|
|
{
|
|
|
|
// Always using system-provided window ordering for normal windows.
|
|
|
|
if (![[self window] isKindOfClass:[PopupWindow class]])
|
|
|
|
return NO;
|
|
|
|
|
2010-07-16 05:48:02 -07:00
|
|
|
// Don't reorder when we don't have a parent window, like when we're a
|
|
|
|
// context menu or a tooltip.
|
|
|
|
return ![[self window] parentWindow];
|
2009-12-11 13:57:40 -08:00
|
|
|
}
|
|
|
|
|
2007-11-26 15:19:04 -08:00
|
|
|
- (void)mouseDown:(NSEvent*)theEvent
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2009-12-11 13:57:40 -08:00
|
|
|
if ([self shouldDelayWindowOrderingForEvent:theEvent]) {
|
|
|
|
[NSApp preventWindowOrdering];
|
|
|
|
}
|
|
|
|
|
2008-04-06 16:52:05 -07:00
|
|
|
// If we've already seen this event due to direct dispatch from menuForEvent:
|
|
|
|
// just bail; if not, remember it.
|
|
|
|
if (mLastMouseDownEvent == theEvent) {
|
|
|
|
[mLastMouseDownEvent release];
|
|
|
|
mLastMouseDownEvent = nil;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
[mLastMouseDownEvent release];
|
|
|
|
mLastMouseDownEvent = [theEvent retain];
|
|
|
|
}
|
|
|
|
|
2009-11-06 02:21:41 -08:00
|
|
|
[gLastDragMouseDownEvent release];
|
|
|
|
gLastDragMouseDownEvent = [theEvent retain];
|
|
|
|
|
2010-07-16 05:48:02 -07:00
|
|
|
// We need isClickThrough because at this point the window we're in might
|
|
|
|
// already have become main, so the check for isMainWindow in
|
|
|
|
// WindowAcceptsEvent isn't enough. It also has to check isClickThrough.
|
|
|
|
BOOL isClickThrough = (theEvent == mClickThroughMouseDownEvent);
|
|
|
|
[mClickThroughMouseDownEvent release];
|
|
|
|
mClickThroughMouseDownEvent = nil;
|
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-01-15 15:11:55 -08:00
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
if ([self maybeRollup:theEvent] ||
|
2010-07-16 05:48:02 -07:00
|
|
|
!ChildViewMouseTracker::WindowAcceptsEvent([self window], theEvent, self, isClickThrough)) {
|
|
|
|
// Remember blocking because that means we want to block mouseup as well.
|
|
|
|
mBlockedLastMouseDown = YES;
|
2007-11-26 15:19:04 -08:00
|
|
|
return;
|
2010-07-16 05:48:02 -07:00
|
|
|
}
|
2007-11-26 15:19:04 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#if USE_CLICK_HOLD_CONTEXTMENU
|
|
|
|
// fire off timer to check for click-hold after two seconds. retains |theEvent|
|
|
|
|
[self performSelector:@selector(clickHoldCallback:) withObject:theEvent afterDelay:2.0];
|
|
|
|
#endif
|
|
|
|
|
2007-04-19 13:18:46 -07:00
|
|
|
// in order to send gecko events we'll need a gecko widget
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2010-02-23 15:30:39 -08:00
|
|
|
NSUInteger modifierFlags = [theEvent modifierFlags];
|
2009-08-26 17:29:47 -07:00
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_DOWN, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-06-12 13:28:26 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2010-07-16 05:48:02 -07:00
|
|
|
|
|
|
|
NSInteger clickCount = [theEvent clickCount];
|
|
|
|
if (mBlockedLastMouseDown && clickCount > 1) {
|
|
|
|
// Don't send a double click if the first click of the double click was
|
|
|
|
// blocked.
|
|
|
|
clickCount--;
|
|
|
|
}
|
|
|
|
geckoEvent.clickCount = clickCount;
|
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
if (modifierFlags & NSControlKeyMask)
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eRightButton;
|
2007-03-22 10:30:00 -07:00
|
|
|
else
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eLeftButton;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
// Create event for use by plugins.
|
|
|
|
// This is going to our child view so we don't need to look up the destination
|
|
|
|
// event type.
|
2009-08-31 18:00:13 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseDown,
|
|
|
|
&cocoaEvent);
|
|
|
|
// Don't lose possible changes made above to clickCount
|
|
|
|
cocoaEvent.data.mouse.clickCount = clickCount;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2010-07-16 05:48:02 -07:00
|
|
|
mBlockedLastMouseDown = NO;
|
2007-04-19 13:18:46 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// XXX maybe call markedTextSelectionChanged:client: here?
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)mouseUp:(NSEvent *)theEvent
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2010-07-16 05:48:02 -07:00
|
|
|
if (!mGeckoChild || mBlockedLastMouseDown)
|
2007-06-12 13:28:26 -07:00
|
|
|
return;
|
|
|
|
|
2010-01-22 12:57:04 -08:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
2011-03-31 16:31:32 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
2013-08-21 09:22:03 -07:00
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_UP, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-06-12 13:28:26 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2010-02-23 15:30:39 -08:00
|
|
|
if ([theEvent modifierFlags] & NSControlKeyMask)
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eRightButton;
|
2008-09-15 05:50:59 -07:00
|
|
|
else
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eLeftButton;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
// Create event for use by plugins.
|
|
|
|
// This is going to our child view so we don't need to look up the destination
|
|
|
|
// event type.
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseUp,
|
|
|
|
&cocoaEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-03-02 14:04:13 -08:00
|
|
|
// This might destroy our widget (and null out mGeckoChild).
|
2013-05-20 14:38:54 -07:00
|
|
|
bool defaultPrevented = mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
|
|
|
|
// Check to see if we are double-clicking in the titlebar.
|
|
|
|
CGFloat locationInTitlebar = [[self window] frame].size.height - [theEvent locationInWindow].y;
|
|
|
|
if (!defaultPrevented && [theEvent clickCount] == 2 &&
|
|
|
|
[[self window] isMovableByWindowBackground] &&
|
|
|
|
[self shouldMinimizeOnTitlebarDoubleClick] &&
|
|
|
|
[[self window] isKindOfClass:[ToolbarWindow class]] &&
|
|
|
|
(locationInTitlebar < [(ToolbarWindow*)[self window] titlebarHeight] ||
|
|
|
|
locationInTitlebar < [(ToolbarWindow*)[self window] unifiedToolbarHeight])) {
|
2013-06-11 10:33:32 -07:00
|
|
|
|
|
|
|
NSButton *minimizeButton = [[self window] standardWindowButton:NSWindowMiniaturizeButton];
|
|
|
|
[minimizeButton performClick:self];
|
2013-05-20 14:38:54 -07:00
|
|
|
}
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2010-01-22 12:57:04 -08:00
|
|
|
// If our mouse-up event's location is over some other object (as might
|
|
|
|
// happen if it came at the end of a dragging operation), also send our
|
|
|
|
// Gecko frame a mouse-exit event.
|
2010-03-02 14:04:13 -08:00
|
|
|
if (mGeckoChild && mIsPluginView) {
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::ReEvaluateMouseEnterState(theEvent, self);
|
2010-01-22 12:57:04 -08:00
|
|
|
}
|
|
|
|
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
- (void)sendMouseEnterOrExitEvent:(NSEvent*)aEvent
|
|
|
|
enter:(BOOL)aEnter
|
2013-10-01 23:38:27 -07:00
|
|
|
type:(WidgetMouseEvent::exitType)aType
|
2007-04-10 13:07:49 -07:00
|
|
|
{
|
2009-09-22 19:31:37 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
NSPoint windowEventLocation = nsCocoaUtils::EventLocationForWindow(aEvent, [self window]);
|
|
|
|
NSPoint localEventLocation = [self convertPoint:windowEventLocation fromView:nil];
|
2007-06-12 13:28:26 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t msg = aEnter ? NS_MOUSE_ENTER : NS_MOUSE_EXIT;
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent event(true, msg, mGeckoChild, WidgetMouseEvent::eReal);
|
2013-08-02 00:05:16 -07:00
|
|
|
event.refPoint = LayoutDeviceIntPoint::FromUntyped(
|
|
|
|
mGeckoChild->CocoaPointsToDevPixels(localEventLocation));
|
2007-06-12 13:28:26 -07:00
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
// Create event for use by plugins.
|
2009-09-22 19:31:37 -07:00
|
|
|
// This is going to our child view so we don't need to look up the destination
|
|
|
|
// event type.
|
2009-08-31 18:00:13 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(event, self, aEvent,
|
|
|
|
(msg == NS_MOUSE_ENTER) ?
|
|
|
|
NPCocoaEventMouseEntered : NPCocoaEventMouseExited,
|
|
|
|
&cocoaEvent);
|
2007-09-05 22:11:35 -07:00
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
event.exit = aType;
|
2008-04-09 10:23:34 -07:00
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
nsEventStatus status; // ignored
|
|
|
|
mGeckoChild->DispatchEvent(&event, status);
|
|
|
|
}
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2013-02-05 13:40:34 -08:00
|
|
|
- (void)updateWindowDraggableStateOnMouseMove:(NSEvent*)theEvent
|
|
|
|
{
|
|
|
|
if (!theEvent || !mGeckoChild) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCocoaWindow* windowWidget = mGeckoChild->GetXULWindowWidget();
|
|
|
|
if (!windowWidget) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We assume later on that sending a hit test event won't cause widget destruction.
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent hitTestEvent(true, NS_MOUSE_MOZHITTEST, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2013-02-05 13:40:34 -08:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&hitTestEvent];
|
|
|
|
bool result = mGeckoChild->DispatchWindowEvent(hitTestEvent);
|
|
|
|
|
|
|
|
[windowWidget->GetCocoaWindow() setMovableByWindowBackground:result];
|
|
|
|
}
|
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
- (void)handleMouseMoved:(NSEvent*)theEvent
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-06-15 15:34:48 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_MOVE, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-06-12 13:28:26 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
// Create event for use by plugins.
|
|
|
|
// This is going to our child view so we don't need to look up the destination
|
|
|
|
// event type.
|
2009-08-31 18:00:13 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseMoved,
|
|
|
|
&cocoaEvent);
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)mouseDragged:(NSEvent*)theEvent
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-06-15 15:34:48 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2007-09-23 17:01:04 -07:00
|
|
|
gLastDragView = self;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-03-31 16:31:32 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_MOVE, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-06-12 13:28:26 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
// create event for use by plugins
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseDragged,
|
|
|
|
&cocoaEvent);
|
2007-06-12 13:28:26 -07:00
|
|
|
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2008-01-15 15:11:55 -08:00
|
|
|
|
|
|
|
// Note, sending the above event might have destroyed our widget since we didn't retain.
|
|
|
|
// Fine so long as we don't access any local variables from here on.
|
2007-09-23 17:01:04 -07:00
|
|
|
gLastDragView = nil;
|
2009-11-06 02:21:41 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// XXX maybe call markedTextSelectionChanged:client: here?
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)rightMouseDown:(NSEvent *)theEvent
|
2007-11-06 23:53:24 -08:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-01-15 15:11:21 -08:00
|
|
|
|
2008-01-15 15:11:55 -08:00
|
|
|
[self maybeRollup:theEvent];
|
2007-06-15 15:34:48 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
2007-11-26 15:19:04 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// The right mouse went down, fire off a right mouse down event to gecko
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_DOWN, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-06-12 13:28:26 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eRightButton;
|
2007-06-12 13:28:26 -07:00
|
|
|
geckoEvent.clickCount = [theEvent clickCount];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
// create event for use by plugins
|
2009-08-31 18:00:13 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseDown,
|
|
|
|
&cocoaEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-06-01 18:18:27 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2008-01-15 15:11:55 -08:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2011-06-01 18:18:27 -07:00
|
|
|
// Let the superclass do the context menu stuff.
|
|
|
|
[super rightMouseDown:theEvent];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)rightMouseUp:(NSEvent *)theEvent
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-06-15 15:34:48 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
2008-01-15 15:11:55 -08:00
|
|
|
|
2011-03-31 16:31:32 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_UP, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-06-12 13:28:26 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eRightButton;
|
2007-06-12 13:28:26 -07:00
|
|
|
geckoEvent.clickCount = [theEvent clickCount];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-08-26 17:29:47 -07:00
|
|
|
// create event for use by plugins
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseUp,
|
|
|
|
&cocoaEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2013-09-17 16:36:03 -07:00
|
|
|
// If our mouse-up event's location is over some other object (as might
|
|
|
|
// happen if it came at the end of a dragging operation), also send our
|
|
|
|
// Gecko frame a mouse-exit event.
|
|
|
|
if (mGeckoChild && mIsPluginView) {
|
|
|
|
ChildViewMouseTracker::ReEvaluateMouseEnterState(theEvent, self);
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-07-17 13:29:39 -07:00
|
|
|
- (void)rightMouseDragged:(NSEvent*)theEvent
|
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_MOVE, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-07-17 13:29:39 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eRightButton;
|
2007-07-17 13:29:39 -07:00
|
|
|
|
2013-09-17 16:36:03 -07:00
|
|
|
// create event for use by plugins
|
|
|
|
NPCocoaEvent cocoaEvent;
|
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseDragged,
|
|
|
|
&cocoaEvent);
|
|
|
|
|
2007-07-17 13:29:39 -07:00
|
|
|
// send event into Gecko by going directly to the
|
|
|
|
// the widget.
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2007-07-17 13:29:39 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
- (void)otherMouseDown:(NSEvent *)theEvent
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-01-15 15:11:55 -08:00
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
if ([self maybeRollup:theEvent] ||
|
2010-07-16 05:48:02 -07:00
|
|
|
!ChildViewMouseTracker::WindowAcceptsEvent([self window], theEvent, self))
|
2007-11-26 15:19:04 -08:00
|
|
|
return;
|
2007-07-17 13:29:39 -07:00
|
|
|
|
2007-06-15 15:34:48 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_DOWN, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-06-12 13:28:26 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eMiddleButton;
|
2007-06-12 13:28:26 -07:00
|
|
|
geckoEvent.clickCount = [theEvent clickCount];
|
|
|
|
|
2013-09-17 16:36:03 -07:00
|
|
|
// create event for use by plugins
|
|
|
|
NPCocoaEvent cocoaEvent;
|
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseDown,
|
|
|
|
&cocoaEvent);
|
|
|
|
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)otherMouseUp:(NSEvent *)theEvent
|
|
|
|
{
|
2007-06-15 15:34:48 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_UP, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-06-12 13:28:26 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eMiddleButton;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-09-17 16:36:03 -07:00
|
|
|
// create event for use by plugins
|
|
|
|
NPCocoaEvent cocoaEvent;
|
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseUp,
|
|
|
|
&cocoaEvent);
|
|
|
|
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2013-09-17 16:36:03 -07:00
|
|
|
|
|
|
|
// If our mouse-up event's location is over some other object (as might
|
|
|
|
// happen if it came at the end of a dragging operation), also send our
|
|
|
|
// Gecko frame a mouse-exit event.
|
|
|
|
if (mGeckoChild && mIsPluginView) {
|
|
|
|
ChildViewMouseTracker::ReEvaluateMouseEnterState(theEvent, self);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-07-17 13:29:39 -07:00
|
|
|
- (void)otherMouseDragged:(NSEvent*)theEvent
|
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return;
|
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_MOVE, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2007-07-17 13:29:39 -07:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eMiddleButton;
|
2007-07-17 13:29:39 -07:00
|
|
|
|
2013-09-17 16:36:03 -07:00
|
|
|
// create event for use by plugins
|
|
|
|
NPCocoaEvent cocoaEvent;
|
|
|
|
ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent,
|
|
|
|
NPCocoaEventMouseDragged,
|
|
|
|
&cocoaEvent);
|
|
|
|
|
2007-07-17 13:29:39 -07:00
|
|
|
// send event into Gecko by going directly to the
|
|
|
|
// the widget.
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2007-07-17 13:29:39 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
static int32_t RoundUp(double aDouble)
|
2012-08-11 18:42:37 -07:00
|
|
|
{
|
2012-08-22 08:56:38 -07:00
|
|
|
return aDouble < 0 ? static_cast<int32_t>(floor(aDouble)) :
|
|
|
|
static_cast<int32_t>(ceil(aDouble));
|
2012-08-11 18:42:37 -07:00
|
|
|
}
|
|
|
|
|
2013-08-16 14:17:40 -07:00
|
|
|
- (void)sendWheelStartOrStop:(uint32_t)msg forEvent:(NSEvent *)theEvent
|
|
|
|
{
|
|
|
|
WidgetWheelEvent wheelEvent(true, msg, mGeckoChild);
|
|
|
|
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
|
|
|
|
mExpectingWheelStop = (msg == NS_WHEEL_START);
|
|
|
|
mGeckoChild->DispatchWindowEvent(wheelEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)sendWheelCondition:(BOOL)condition first:(uint32_t)first second:(uint32_t)second forEvent:(NSEvent *)theEvent
|
|
|
|
{
|
|
|
|
if (mExpectingWheelStop == condition) {
|
|
|
|
[self sendWheelStartOrStop:first forEvent:theEvent];
|
|
|
|
}
|
|
|
|
[self sendWheelStartOrStop:second forEvent:theEvent];
|
|
|
|
}
|
|
|
|
|
2012-08-11 18:42:37 -07:00
|
|
|
- (void)scrollWheel:(NSEvent*)theEvent
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2012-08-11 18:42:37 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
ChildViewMouseTracker::MouseScrolled(theEvent);
|
|
|
|
|
|
|
|
if ([self maybeRollup:theEvent]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mGeckoChild) {
|
2007-06-15 15:34:48 -07:00
|
|
|
return;
|
2012-08-11 18:42:37 -07:00
|
|
|
}
|
2007-06-15 15:34:48 -07:00
|
|
|
|
2013-08-16 14:17:40 -07:00
|
|
|
if (nsCocoaFeatures::OnLionOrLater()) {
|
|
|
|
NSEventPhase phase = [theEvent phase];
|
|
|
|
// Fire NS_WHEEL_START/STOP events when 2 fingers touch/release the touchpad.
|
|
|
|
if (phase & NSEventPhaseMayBegin) {
|
|
|
|
[self sendWheelCondition:YES first:NS_WHEEL_STOP second:NS_WHEEL_START forEvent:theEvent];
|
|
|
|
return;
|
|
|
|
}
|
2008-09-17 04:27:19 -07:00
|
|
|
|
2013-08-16 14:17:40 -07:00
|
|
|
if (phase & (NSEventPhaseEnded | NSEventPhaseCancelled)) {
|
|
|
|
[self sendWheelCondition:NO first:NS_WHEEL_START second:NS_WHEEL_STOP forEvent:theEvent];
|
|
|
|
return;
|
2013-10-10 14:22:02 -07:00
|
|
|
}
|
2012-08-11 18:42:37 -07:00
|
|
|
}
|
|
|
|
|
2013-08-16 14:17:40 -07:00
|
|
|
WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
|
|
|
|
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
|
|
|
|
|
2012-08-11 18:42:37 -07:00
|
|
|
wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]);
|
|
|
|
wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]);
|
|
|
|
|
|
|
|
if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
|
|
|
|
// Some scrolling devices supports pixel scrolling, e.g. a Macbook
|
|
|
|
// touchpad or a Mighty Mouse. On those devices, [theEvent deviceDeltaX/Y]
|
|
|
|
// contains the amount of pixels to scroll. Since Lion this has changed
|
|
|
|
// to [theEvent scrollingDeltaX/Y].
|
2012-09-29 04:36:09 -07:00
|
|
|
double scale = mGeckoChild->BackingScaleFactor();
|
2012-08-11 18:42:37 -07:00
|
|
|
if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
|
2012-09-29 04:36:09 -07:00
|
|
|
wheelEvent.deltaX = -[theEvent scrollingDeltaX] * scale;
|
|
|
|
wheelEvent.deltaY = -[theEvent scrollingDeltaY] * scale;
|
2012-08-11 18:42:37 -07:00
|
|
|
} else {
|
2012-09-29 04:36:09 -07:00
|
|
|
wheelEvent.deltaX = -[theEvent deviceDeltaX] * scale;
|
|
|
|
wheelEvent.deltaY = -[theEvent deviceDeltaY] * scale;
|
2008-09-17 04:27:19 -07:00
|
|
|
}
|
|
|
|
} else {
|
2012-08-11 18:42:37 -07:00
|
|
|
wheelEvent.deltaX = -[theEvent deltaX];
|
|
|
|
wheelEvent.deltaY = -[theEvent deltaY];
|
2008-09-17 04:27:19 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-11 18:42:37 -07:00
|
|
|
// TODO: We should not set deltaZ for now because we're not sure if we should
|
|
|
|
// revert the sign.
|
|
|
|
// wheelEvent.deltaZ = [theEvent deltaZ];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-11 18:42:37 -07:00
|
|
|
if (!wheelEvent.deltaX && !wheelEvent.deltaY && !wheelEvent.deltaZ) {
|
2008-09-17 04:27:19 -07:00
|
|
|
// No sense in firing off a Gecko event.
|
2012-08-11 18:42:37 -07:00
|
|
|
return;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-11 18:42:37 -07:00
|
|
|
NPCocoaEvent cocoaEvent;
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(wheelEvent, self, theEvent,
|
|
|
|
NPCocoaEventScrollWheel,
|
|
|
|
&cocoaEvent);
|
2010-11-05 09:04:28 -07:00
|
|
|
|
2013-10-11 12:48:53 -07:00
|
|
|
#ifdef __LP64__
|
|
|
|
// Only dispatch this event if we're not currently tracking a scroll event as
|
|
|
|
// swipe.
|
|
|
|
if (!mCancelSwipeAnimation || *mCancelSwipeAnimation == YES) {
|
|
|
|
#endif // #ifdef __LP64__
|
|
|
|
mGeckoChild->DispatchWindowEvent(wheelEvent);
|
|
|
|
if (!mGeckoChild) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#ifdef __LP64__
|
|
|
|
} else {
|
|
|
|
// Manually set these members here since we didn't dispatch the event.
|
|
|
|
wheelEvent.overflowDeltaX = wheelEvent.deltaX;
|
|
|
|
wheelEvent.overflowDeltaY = wheelEvent.deltaY;
|
|
|
|
wheelEvent.mViewPortIsOverscrolled = true;
|
2012-08-11 18:42:37 -07:00
|
|
|
}
|
2008-09-17 04:27:19 -07:00
|
|
|
|
2013-10-11 12:48:53 -07:00
|
|
|
// overflowDeltaX and overflowDeltaY tell us when the user has tried to
|
|
|
|
// scroll past the edge of a page (in those cases it's non-zero).
|
|
|
|
if ((wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) &&
|
|
|
|
(wheelEvent.deltaX != 0.0 || wheelEvent.deltaY != 0.0)) {
|
2012-08-11 18:42:37 -07:00
|
|
|
[self maybeTrackScrollEventAsSwipe:theEvent
|
2013-10-11 12:48:53 -07:00
|
|
|
scrollOverflowX:wheelEvent.overflowDeltaX
|
|
|
|
scrollOverflowY:wheelEvent.overflowDeltaY
|
|
|
|
viewPortIsOverscrolled:wheelEvent.mViewPortIsOverscrolled];
|
2008-09-17 04:27:19 -07:00
|
|
|
}
|
2012-08-11 18:42:37 -07:00
|
|
|
#endif // #ifdef __LP64__
|
2008-09-17 04:27:19 -07:00
|
|
|
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
-(NSMenu*)menuForEvent:(NSEvent*)theEvent
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-06-15 15:34:48 -07:00
|
|
|
if (!mGeckoChild || [self isPluginView])
|
2007-03-22 10:30:00 -07:00
|
|
|
return nil;
|
2007-08-20 18:02:09 -07:00
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-01-15 15:11:55 -08:00
|
|
|
|
2007-11-26 15:19:04 -08:00
|
|
|
[self maybeRollup:theEvent];
|
2008-01-15 15:11:55 -08:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return nil;
|
2007-11-26 15:19:04 -08:00
|
|
|
|
2008-04-06 16:52:05 -07:00
|
|
|
// Cocoa doesn't always dispatch a mouseDown: for a control-click event,
|
|
|
|
// depends on what we return from menuForEvent:. Gecko always expects one
|
|
|
|
// and expects the mouse down event before the context menu event, so
|
|
|
|
// get that event sent first if this is a left mouse click.
|
|
|
|
if ([theEvent type] == NSLeftMouseDown) {
|
|
|
|
[self mouseDown:theEvent];
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return nil;
|
|
|
|
}
|
2008-01-16 20:59:43 -08:00
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_CONTEXTMENU, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2008-01-16 20:59:43 -08:00
|
|
|
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
|
2013-10-01 23:38:27 -07:00
|
|
|
geckoEvent.button = WidgetMouseEvent::eRightButton;
|
2008-08-25 17:02:26 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2008-01-16 20:59:43 -08:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return nil;
|
|
|
|
|
2008-03-04 00:06:47 -08:00
|
|
|
[self maybeInitContextMenuTracking];
|
2008-02-28 07:58:33 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Go up our view chain to fetch the correct menu to return.
|
|
|
|
return [self contextMenu];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSMenu*)contextMenu
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NSView* superView = [self superview];
|
|
|
|
if ([superView respondsToSelector:@selector(contextMenu)])
|
|
|
|
return [(NSView<mozView>*)superView contextMenu];
|
|
|
|
|
|
|
|
return nil;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-08-16 14:17:40 -07:00
|
|
|
- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
|
|
|
|
toGeckoEvent:(WidgetWheelEvent*)outWheelEvent
|
|
|
|
{
|
|
|
|
[self convertCocoaMouseEvent:aMouseEvent toGeckoEvent:outWheelEvent];
|
|
|
|
outWheelEvent->deltaMode =
|
|
|
|
Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ?
|
|
|
|
nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE;
|
|
|
|
|
|
|
|
// Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa
|
|
|
|
// assertion and an Objective-C NSInternalInconsistencyException if the
|
|
|
|
// underlying "Carbon" event doesn't contain pixel scrolling information.
|
|
|
|
// For these events, carbonEventKind is kEventMouseWheelMoved instead of
|
|
|
|
// kEventMouseScroll.
|
|
|
|
if (outWheelEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
|
|
|
|
EventRef theCarbonEvent = [aMouseEvent _eventRef];
|
|
|
|
UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
|
|
|
|
if (carbonEventKind != kEventMouseScroll) {
|
|
|
|
outWheelEvent->deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
outWheelEvent->isMomentum = nsCocoaUtils::IsMomentumScrollEvent(aMouseEvent);
|
|
|
|
}
|
|
|
|
|
2013-10-01 00:23:02 -07:00
|
|
|
- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
|
|
|
|
toGeckoEvent:(WidgetInputEvent*)outGeckoEvent
|
2007-06-12 13:28:26 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2010-07-16 05:48:02 -07:00
|
|
|
NS_ASSERTION(outGeckoEvent, "convertCocoaMouseEvent:toGeckoEvent: requires non-null aoutGeckoEvent");
|
|
|
|
if (!outGeckoEvent)
|
2007-06-12 13:28:26 -07:00
|
|
|
return;
|
|
|
|
|
2012-04-24 20:00:02 -07:00
|
|
|
nsCocoaUtils::InitInputEvent(*outGeckoEvent, aMouseEvent);
|
2007-06-12 13:28:26 -07:00
|
|
|
|
|
|
|
// convert point to view coordinate system
|
2009-09-15 14:56:44 -07:00
|
|
|
NSPoint locationInWindow = nsCocoaUtils::EventLocationForWindow(aMouseEvent, [self window]);
|
2009-08-17 19:36:15 -07:00
|
|
|
NSPoint localPoint = [self convertPoint:locationInWindow fromView:nil];
|
2012-09-29 04:36:09 -07:00
|
|
|
|
2013-08-02 00:05:16 -07:00
|
|
|
outGeckoEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(
|
|
|
|
mGeckoChild->CocoaPointsToDevPixels(localPoint));
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2013-10-17 23:10:26 -07:00
|
|
|
WidgetMouseEventBase* mouseEvent = outGeckoEvent->AsMouseEventBase();
|
2012-04-24 20:00:01 -07:00
|
|
|
mouseEvent->buttons = 0;
|
2012-11-09 02:22:36 -08:00
|
|
|
NSUInteger mouseButtons = [NSEvent pressedMouseButtons];
|
2012-04-24 20:00:01 -07:00
|
|
|
|
|
|
|
if (mouseButtons & 0x01) {
|
2013-10-01 23:38:27 -07:00
|
|
|
mouseEvent->buttons |= WidgetMouseEvent::eLeftButtonFlag;
|
2012-04-24 20:00:01 -07:00
|
|
|
}
|
|
|
|
if (mouseButtons & 0x02) {
|
2013-10-01 23:38:27 -07:00
|
|
|
mouseEvent->buttons |= WidgetMouseEvent::eRightButtonFlag;
|
2012-04-24 20:00:01 -07:00
|
|
|
}
|
|
|
|
if (mouseButtons & 0x04) {
|
2013-10-01 23:38:27 -07:00
|
|
|
mouseEvent->buttons |= WidgetMouseEvent::eMiddleButtonFlag;
|
2012-04-24 20:00:01 -07:00
|
|
|
}
|
|
|
|
if (mouseButtons & 0x08) {
|
2013-10-01 23:38:27 -07:00
|
|
|
mouseEvent->buttons |= WidgetMouseEvent::e4thButtonFlag;
|
2012-04-24 20:00:01 -07:00
|
|
|
}
|
|
|
|
if (mouseButtons & 0x10) {
|
2013-10-01 23:38:27 -07:00
|
|
|
mouseEvent->buttons |= WidgetMouseEvent::e5thButtonFlag;
|
2012-04-24 20:00:01 -07:00
|
|
|
}
|
|
|
|
|
2013-06-07 05:40:28 -07:00
|
|
|
switch ([aMouseEvent type]) {
|
|
|
|
case NSLeftMouseDown:
|
|
|
|
case NSLeftMouseUp:
|
|
|
|
case NSLeftMouseDragged:
|
|
|
|
case NSRightMouseDown:
|
|
|
|
case NSRightMouseUp:
|
|
|
|
case NSRightMouseDragged:
|
|
|
|
case NSOtherMouseDown:
|
|
|
|
case NSOtherMouseUp:
|
|
|
|
case NSOtherMouseDragged:
|
|
|
|
if ([aMouseEvent subtype] == NSTabletPointEventSubtype) {
|
|
|
|
mouseEvent->pressure = [aMouseEvent pressure];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-06-12 13:28:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
// NSTextInput implementation
|
|
|
|
|
|
|
|
- (void)insertText:(id)insertString
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2013-07-11 00:46:35 -07:00
|
|
|
NS_ENSURE_TRUE_VOID(mGeckoChild);
|
2009-09-30 19:52:50 -07:00
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2007-08-16 13:30:50 -07:00
|
|
|
|
2011-02-23 10:06:26 -08:00
|
|
|
NSAttributedString* attrStr;
|
|
|
|
if ([insertString isKindOfClass:[NSAttributedString class]]) {
|
|
|
|
attrStr = static_cast<NSAttributedString*>(insertString);
|
|
|
|
} else {
|
|
|
|
attrStr =
|
|
|
|
[[[NSAttributedString alloc] initWithString:insertString] autorelease];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-02-23 10:06:26 -08:00
|
|
|
mTextInputHandler->InsertText(attrStr);
|
2007-08-16 13:30:50 -07:00
|
|
|
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)insertNewline:(id)sender
|
|
|
|
{
|
2008-03-04 14:32:55 -08:00
|
|
|
[self insertText:@"\n"];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) doCommandBySelector:(SEL)aSelector
|
2008-02-20 15:47:05 -08:00
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
2008-03-04 14:32:55 -08:00
|
|
|
|
2011-07-20 17:33:16 -07:00
|
|
|
if (!mGeckoChild || !mTextInputHandler) {
|
|
|
|
return;
|
|
|
|
}
|
2007-04-21 17:37:27 -07:00
|
|
|
|
2011-07-20 17:33:16 -07:00
|
|
|
const char* sel = reinterpret_cast<const char*>(aSelector);
|
|
|
|
if (!mTextInputHandler->DoCommandBySelector(sel)) {
|
2008-03-04 14:32:55 -08:00
|
|
|
[super doCommandBySelector:aSelector];
|
2011-02-23 10:06:26 -08:00
|
|
|
}
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setMarkedText:(id)aString selectedRange:(NSRange)selRange
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2013-07-11 00:46:36 -07:00
|
|
|
NS_ENSURE_TRUE_VOID(mTextInputHandler);
|
2009-09-30 19:52:50 -07:00
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2007-08-16 13:30:50 -07:00
|
|
|
|
2011-02-18 20:55:34 -08:00
|
|
|
NSAttributedString* attrStr;
|
|
|
|
if ([aString isKindOfClass:[NSAttributedString class]]) {
|
|
|
|
attrStr = static_cast<NSAttributedString*>(aString);
|
|
|
|
} else {
|
|
|
|
attrStr = [[[NSAttributedString alloc] initWithString:aString] autorelease];
|
2008-01-15 15:11:55 -08:00
|
|
|
}
|
2008-04-21 20:30:45 -07:00
|
|
|
|
2011-05-08 03:19:23 -07:00
|
|
|
mTextInputHandler->SetMarkedText(attrStr, selRange);
|
2007-08-16 13:30:50 -07:00
|
|
|
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) unmarkText
|
|
|
|
{
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, );
|
|
|
|
mTextInputHandler->CommitIMEComposition();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) hasMarkedText
|
|
|
|
{
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NO);
|
|
|
|
return mTextInputHandler->HasMarkedText();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-05-20 14:38:54 -07:00
|
|
|
- (BOOL)shouldMinimizeOnTitlebarDoubleClick
|
|
|
|
{
|
|
|
|
NSString *MDAppleMiniaturizeOnDoubleClickKey =
|
|
|
|
@"AppleMiniaturizeOnDoubleClick";
|
|
|
|
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
bool shouldMinimize = [[userDefaults
|
|
|
|
objectForKey:MDAppleMiniaturizeOnDoubleClickKey] boolValue];
|
|
|
|
|
|
|
|
return shouldMinimize;
|
|
|
|
}
|
|
|
|
|
2009-08-31 18:00:13 -07:00
|
|
|
- (NSInteger) conversationIdentifier
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, reinterpret_cast<NSInteger>(self));
|
|
|
|
return mTextInputHandler->ConversationIdentifier();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSAttributedString *) attributedSubstringFromRange:(NSRange)theRange
|
|
|
|
{
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, nil);
|
|
|
|
return mTextInputHandler->GetAttributedSubstringFromRange(theRange);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSRange) markedRange
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NSMakeRange(NSNotFound, 0));
|
|
|
|
return mTextInputHandler->MarkedRange();
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakeRange(0, 0));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSRange) selectedRange
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NSMakeRange(NSNotFound, 0));
|
|
|
|
return mTextInputHandler->SelectedRange();
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakeRange(0, 0));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSRect) firstRectForCharacterRange:(NSRange)theRange
|
|
|
|
{
|
2008-02-19 23:40:04 -08:00
|
|
|
NSRect rect;
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, rect);
|
|
|
|
return mTextInputHandler->FirstRectForCharacterRange(theRange);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-08-31 18:00:13 -07:00
|
|
|
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, 0);
|
|
|
|
return mTextInputHandler->CharacterIndexForPoint(thePoint);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) validAttributesForMarkedText
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2011-05-08 03:19:23 -07:00
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, [NSArray array]);
|
|
|
|
return mTextInputHandler->GetValidAttributesForMarkedText();
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-07-11 00:46:35 -07:00
|
|
|
#pragma mark -
|
|
|
|
// NSTextInputClient implementation
|
|
|
|
|
2013-07-11 00:46:35 -07:00
|
|
|
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
NS_ENSURE_TRUE_VOID(mGeckoChild);
|
|
|
|
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
NSAttributedString* attrStr;
|
|
|
|
if ([aString isKindOfClass:[NSAttributedString class]]) {
|
|
|
|
attrStr = static_cast<NSAttributedString*>(aString);
|
|
|
|
} else {
|
|
|
|
attrStr = [[[NSAttributedString alloc] initWithString:aString] autorelease];
|
|
|
|
}
|
|
|
|
|
|
|
|
mTextInputHandler->InsertText(attrStr, &replacementRange);
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2013-07-11 00:46:36 -07:00
|
|
|
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange
|
|
|
|
replacementRange:(NSRange)replacementRange
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
NS_ENSURE_TRUE_VOID(mTextInputHandler);
|
|
|
|
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
NSAttributedString* attrStr;
|
|
|
|
if ([aString isKindOfClass:[NSAttributedString class]]) {
|
|
|
|
attrStr = static_cast<NSAttributedString*>(aString);
|
|
|
|
} else {
|
|
|
|
attrStr = [[[NSAttributedString alloc] initWithString:aString] autorelease];
|
|
|
|
}
|
|
|
|
|
|
|
|
mTextInputHandler->SetMarkedText(attrStr, selectedRange, &replacementRange);
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2013-07-11 00:46:35 -07:00
|
|
|
- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)aRange
|
|
|
|
actualRange:(NSRangePointer)actualRange
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, nil);
|
|
|
|
return mTextInputHandler->GetAttributedSubstringFromRange(aRange,
|
|
|
|
actualRange);
|
|
|
|
}
|
|
|
|
|
2013-07-11 00:46:35 -07:00
|
|
|
- (NSRect)firstRectForCharacterRange:(NSRange)aRange
|
|
|
|
actualRange:(NSRangePointer)actualRange
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, NSMakeRect(0.0, 0.0, 0.0, 0.0));
|
|
|
|
return mTextInputHandler->FirstRectForCharacterRange(aRange, actualRange);
|
|
|
|
}
|
|
|
|
|
2013-07-11 00:46:35 -07:00
|
|
|
- (NSInteger)windowLevel
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
|
|
|
NS_ENSURE_TRUE(mTextInputHandler, [[self window] level]);
|
|
|
|
return mTextInputHandler->GetWindowLevel();
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSNormalWindowLevel);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
2012-10-15 05:38:34 -07:00
|
|
|
#ifdef __LP64__
|
2010-06-09 17:56:17 -07:00
|
|
|
- (NSTextInputContext *)inputContext
|
|
|
|
{
|
|
|
|
if (mIsPluginView && mPluginEventModel == NPEventModelCocoa)
|
|
|
|
return [[ComplexTextInputPanel sharedComplexTextInputPanel] inputContext];
|
|
|
|
else
|
|
|
|
return [super inputContext];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-08-16 20:26:17 -07:00
|
|
|
// This is a private API that Cocoa uses.
|
|
|
|
// Cocoa will call this after the menu system returns "NO" for "performKeyEquivalent:".
|
|
|
|
// We want all they key events we can get so just return YES. In particular, this fixes
|
|
|
|
// ctrl-tab - we don't get a "keyDown:" call for that without this.
|
|
|
|
- (BOOL)_wantsKeyDownForEvent:(NSEvent*)event
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2008-02-28 21:47:41 -08:00
|
|
|
- (void)keyDown:(NSEvent*)theEvent
|
|
|
|
{
|
2008-06-30 09:30:22 -07:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2013-05-24 09:27:52 -07:00
|
|
|
#if !defined(RELEASE_BUILD) || defined(DEBUG)
|
2013-07-16 19:08:44 -07:00
|
|
|
if (mGeckoChild && mTextInputHandler && mTextInputHandler->IsFocused()) {
|
2013-07-19 14:21:25 -07:00
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
|
|
NSWindow* window = [self window];
|
2013-08-01 18:35:34 -07:00
|
|
|
NSString* info = [NSString stringWithFormat:@"\nview [%@], window [%@], key event [%@], window is key %i, is fullscreen %i, app is active %i",
|
|
|
|
self, window, theEvent, [window isKeyWindow], ([window styleMask] & (1 << 14)) != 0,
|
|
|
|
[NSApp isActive]];
|
2013-07-19 14:21:25 -07:00
|
|
|
nsAutoCString additionalInfo([info UTF8String]);
|
|
|
|
#endif
|
2013-07-16 19:08:44 -07:00
|
|
|
if (mIsPluginView) {
|
|
|
|
if (TextInputHandler::IsSecureEventInputEnabled()) {
|
2013-07-19 14:21:25 -07:00
|
|
|
#define CRASH_MESSAGE "While a plugin has focus, we must not be in secure mode"
|
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
|
|
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("\nBug 893973: ") +
|
|
|
|
NS_LITERAL_CSTRING(CRASH_MESSAGE));
|
|
|
|
CrashReporter::AppendAppNotesToCrashReport(additionalInfo);
|
|
|
|
#endif
|
|
|
|
MOZ_CRASH(CRASH_MESSAGE);
|
|
|
|
#undef CRASH_MESSAGE
|
2013-07-16 19:08:44 -07:00
|
|
|
}
|
|
|
|
} else if (mGeckoChild->GetInputContext().IsPasswordEditor() &&
|
|
|
|
!TextInputHandler::IsSecureEventInputEnabled()) {
|
2013-07-19 14:21:25 -07:00
|
|
|
#define CRASH_MESSAGE "A password editor has focus, but not in secure input mode"
|
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
|
|
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("\nBug 893973: ") +
|
|
|
|
NS_LITERAL_CSTRING(CRASH_MESSAGE));
|
|
|
|
CrashReporter::AppendAppNotesToCrashReport(additionalInfo);
|
|
|
|
#endif
|
|
|
|
MOZ_CRASH(CRASH_MESSAGE);
|
|
|
|
#undef CRASH_MESSAGE
|
2013-07-16 19:08:44 -07:00
|
|
|
} else if (!mGeckoChild->GetInputContext().IsPasswordEditor() &&
|
|
|
|
TextInputHandler::IsSecureEventInputEnabled()) {
|
2013-07-19 14:21:25 -07:00
|
|
|
#define CRASH_MESSAGE "A non-password editor has focus, but in secure input mode"
|
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
|
|
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("\nBug 893973: ") +
|
|
|
|
NS_LITERAL_CSTRING(CRASH_MESSAGE));
|
|
|
|
CrashReporter::AppendAppNotesToCrashReport(additionalInfo);
|
|
|
|
#endif
|
|
|
|
MOZ_CRASH(CRASH_MESSAGE);
|
|
|
|
#undef CRASH_MESSAGE
|
2013-07-16 19:08:44 -07:00
|
|
|
}
|
2013-05-24 09:27:52 -07:00
|
|
|
}
|
|
|
|
#endif // #if !defined(RELEASE_BUILD) || defined(DEBUG)
|
|
|
|
|
2011-07-20 17:33:16 -07:00
|
|
|
if (mGeckoChild && mTextInputHandler && mIsPluginView) {
|
2011-02-23 20:48:12 -08:00
|
|
|
mTextInputHandler->HandleKeyDownEventForPlugin(theEvent);
|
2008-06-30 09:30:22 -07:00
|
|
|
return;
|
2010-06-09 17:56:17 -07:00
|
|
|
}
|
2008-06-30 09:30:22 -07:00
|
|
|
|
2011-07-20 17:33:16 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2011-09-28 23:19:26 -07:00
|
|
|
bool handled = false;
|
2011-07-20 17:33:16 -07:00
|
|
|
if (mGeckoChild && mTextInputHandler) {
|
|
|
|
handled = mTextInputHandler->HandleKeyDownEvent(theEvent);
|
|
|
|
}
|
|
|
|
|
2010-08-16 20:26:17 -07:00
|
|
|
// We always allow keyboard events to propagate to keyDown: but if they are not
|
|
|
|
// handled we give special Application menu items a chance to act.
|
|
|
|
if (!handled && sApplicationMenu) {
|
|
|
|
[sApplicationMenu performKeyEquivalent:theEvent];
|
|
|
|
}
|
2008-06-30 09:30:22 -07:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2008-02-28 21:47:41 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
- (void)keyUp:(NSEvent*)theEvent
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2011-07-20 17:33:16 -07:00
|
|
|
NS_ENSURE_TRUE(mGeckoChild, );
|
2011-01-20 17:08:11 -08:00
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-01-15 15:11:55 -08:00
|
|
|
|
2008-06-30 09:30:22 -07:00
|
|
|
if (mIsPluginView) {
|
2011-02-23 20:48:12 -08:00
|
|
|
mTextInputHandler->HandleKeyUpEventForPlugin(theEvent);
|
2008-06-30 09:30:22 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-20 17:33:16 -07:00
|
|
|
mTextInputHandler->HandleKeyUpEvent(theEvent);
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)flagsChanged:(NSEvent*)theEvent
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2011-07-20 17:33:16 -07:00
|
|
|
NS_ENSURE_TRUE(mGeckoChild, );
|
2007-06-15 15:34:48 -07:00
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2011-07-20 17:33:16 -07:00
|
|
|
mTextInputHandler->HandleFlagsChanged(theEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-10-13 11:07:27 -07:00
|
|
|
- (BOOL) isFirstResponder
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
|
|
|
NSResponder* resp = [[self window] firstResponder];
|
|
|
|
return (resp == (NSResponder*)self);
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
|
|
|
|
}
|
|
|
|
|
2010-03-08 04:35:25 -08:00
|
|
|
- (BOOL)isDragInProgress
|
|
|
|
{
|
|
|
|
if (!mDragService)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDragSession> dragSession;
|
|
|
|
mDragService->GetCurrentSession(getter_AddRefs(dragSession));
|
2012-07-30 07:20:58 -07:00
|
|
|
return dragSession != nullptr;
|
2010-03-08 04:35:25 -08:00
|
|
|
}
|
|
|
|
|
2010-07-16 05:48:02 -07:00
|
|
|
- (BOOL)inactiveWindowAcceptsMouseEvent:(NSEvent*)aEvent
|
|
|
|
{
|
2010-08-09 09:12:50 -07:00
|
|
|
// If we're being destroyed assume the default -- return YES.
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return YES;
|
|
|
|
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent geckoEvent(true, NS_MOUSE_ACTIVATE, mGeckoChild,
|
|
|
|
WidgetMouseEvent::eReal);
|
2010-07-16 05:48:02 -07:00
|
|
|
[self convertCocoaMouseEvent:aEvent toGeckoEvent:&geckoEvent];
|
|
|
|
return !mGeckoChild->DispatchWindowEvent(geckoEvent);
|
|
|
|
}
|
|
|
|
|
2011-03-01 13:15:23 -08:00
|
|
|
// Don't focus a plugin if the user has clicked on a DOM element above it.
|
|
|
|
// In this case the user has actually clicked on the plugin's ChildView
|
|
|
|
// (underneath the non-plugin DOM element). But we shouldn't allow the
|
|
|
|
// ChildView to be focused. See bug 627649.
|
|
|
|
- (BOOL)currentEventShouldFocusPlugin
|
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
NSEvent* currentEvent = [NSApp currentEvent];
|
|
|
|
if ([currentEvent type] != NSLeftMouseDown)
|
|
|
|
return YES;
|
|
|
|
|
2011-03-31 05:44:00 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
2012-10-18 08:53:32 -07:00
|
|
|
// hitTest needs coordinates in device pixels
|
2011-03-01 13:15:23 -08:00
|
|
|
NSPoint eventLoc = nsCocoaUtils::ScreenLocationForEvent(currentEvent);
|
|
|
|
eventLoc.y = nsCocoaUtils::FlippedScreenY(eventLoc.y);
|
2013-08-02 00:05:16 -07:00
|
|
|
LayoutDeviceIntPoint widgetLoc = LayoutDeviceIntPoint::FromUntyped(
|
|
|
|
mGeckoChild->CocoaPointsToDevPixels(eventLoc) -
|
|
|
|
mGeckoChild->WidgetToScreenOffset());
|
2011-03-01 13:15:23 -08:00
|
|
|
|
2013-10-01 00:23:00 -07:00
|
|
|
WidgetQueryContentEvent hitTest(true, NS_QUERY_DOM_WIDGET_HITTEST,
|
|
|
|
mGeckoChild);
|
2011-03-01 13:15:23 -08:00
|
|
|
hitTest.InitForQueryDOMWidgetHittest(widgetLoc);
|
2011-03-31 05:44:00 -07:00
|
|
|
// This might destroy our widget (and null out mGeckoChild).
|
2011-03-01 13:15:23 -08:00
|
|
|
mGeckoChild->DispatchWindowEvent(hitTest);
|
2011-03-31 05:44:00 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return NO;
|
2011-03-01 13:15:23 -08:00
|
|
|
if (hitTest.mSucceeded && !hitTest.mReply.mWidgetIsHit)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2010-11-15 13:12:50 -08:00
|
|
|
// Don't focus a plugin if we're in a left click-through that will fail (see
|
|
|
|
// [ChildView isInFailingLeftClickThrough] above).
|
2011-03-01 13:15:23 -08:00
|
|
|
- (BOOL)shouldFocusPlugin:(BOOL)getFocus
|
2010-04-25 13:58:03 -07:00
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
2010-11-15 13:12:50 -08:00
|
|
|
return NO;
|
|
|
|
|
|
|
|
nsCocoaWindow* windowWidget = mGeckoChild->GetXULWindowWidget();
|
|
|
|
if (windowWidget && !windowWidget->ShouldFocusPlugin())
|
|
|
|
return NO;
|
|
|
|
|
2011-03-01 13:15:23 -08:00
|
|
|
if (getFocus && ![self currentEventShouldFocusPlugin])
|
|
|
|
return NO;
|
|
|
|
|
2010-11-15 13:12:50 -08:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns NO if the plugin shouldn't be focused/unfocused.
|
2011-03-01 13:15:23 -08:00
|
|
|
- (BOOL)updatePluginFocusStatus:(BOOL)getFocus
|
2010-11-15 13:12:50 -08:00
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
|
|
|
return NO;
|
|
|
|
|
2011-03-01 13:15:23 -08:00
|
|
|
if (![self shouldFocusPlugin:getFocus])
|
2010-11-15 13:12:50 -08:00
|
|
|
return NO;
|
2010-04-25 13:58:03 -07:00
|
|
|
|
2011-03-01 13:15:23 -08:00
|
|
|
if (mPluginEventModel == NPEventModelCocoa) {
|
2013-09-26 23:20:54 -07:00
|
|
|
WidgetPluginEvent pluginEvent(true, NS_PLUGIN_FOCUS_EVENT, mGeckoChild);
|
2011-03-01 13:15:23 -08:00
|
|
|
NPCocoaEvent cocoaEvent;
|
2011-07-20 17:33:16 -07:00
|
|
|
nsCocoaUtils::InitNPCocoaEvent(&cocoaEvent);
|
2011-03-01 13:15:23 -08:00
|
|
|
cocoaEvent.type = NPCocoaEventFocusChanged;
|
|
|
|
cocoaEvent.data.focus.hasFocus = getFocus;
|
2011-07-20 17:33:16 -07:00
|
|
|
nsCocoaUtils::InitPluginEvent(pluginEvent, cocoaEvent);
|
2011-03-01 13:15:23 -08:00
|
|
|
mGeckoChild->DispatchWindowEvent(pluginEvent);
|
2010-11-15 13:12:50 -08:00
|
|
|
|
2011-03-01 13:15:23 -08:00
|
|
|
if (getFocus)
|
|
|
|
[self sendFocusEvent:NS_PLUGIN_FOCUS];
|
|
|
|
}
|
2010-11-15 13:12:50 -08:00
|
|
|
|
|
|
|
return YES;
|
2010-04-25 13:58:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// We must always call through to our superclass, even when mGeckoChild is
|
|
|
|
// nil -- otherwise the keyboard focus can end up in the wrong NSView.
|
|
|
|
- (BOOL)becomeFirstResponder
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
2011-03-01 13:15:23 -08:00
|
|
|
if (mIsPluginView) {
|
|
|
|
if (![self updatePluginFocusStatus:YES])
|
2010-11-15 13:12:50 -08:00
|
|
|
return NO;
|
2010-04-25 13:58:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return [super becomeFirstResponder];
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(YES);
|
|
|
|
}
|
|
|
|
|
2007-06-21 16:58:16 -07:00
|
|
|
// We must always call through to our superclass, even when mGeckoChild is
|
|
|
|
// nil -- otherwise the keyboard focus can end up in the wrong NSView.
|
2007-03-22 10:30:00 -07:00
|
|
|
- (BOOL)resignFirstResponder
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
2011-03-01 13:15:23 -08:00
|
|
|
if (mIsPluginView) {
|
|
|
|
if (![self updatePluginFocusStatus:NO])
|
2010-11-15 13:12:50 -08:00
|
|
|
return NO;
|
2010-04-25 13:58:03 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [super resignFirstResponder];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2010-04-25 13:58:03 -07:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(YES);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)viewsWindowDidBecomeKey
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!mGeckoChild)
|
2007-06-15 15:34:48 -07:00
|
|
|
return;
|
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-01-15 15:11:55 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// check to see if the window implements the mozWindow protocol. This
|
|
|
|
// allows embedders to avoid re-entrant calls to -makeKeyAndOrderFront,
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
// which can happen because these activate calls propagate out
|
2007-03-22 10:30:00 -07:00
|
|
|
// to the embedder via nsIEmbeddingSiteWindow::SetFocus().
|
|
|
|
BOOL isMozWindow = [[self window] respondsToSelector:@selector(setSuppressMakeKeyFront:)];
|
|
|
|
if (isMozWindow)
|
|
|
|
[[self window] setSuppressMakeKeyFront:YES];
|
|
|
|
|
2012-08-15 11:52:42 -07:00
|
|
|
nsIWidgetListener* listener = mGeckoChild->GetWidgetListener();
|
|
|
|
if (listener)
|
|
|
|
listener->WindowActivated();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (isMozWindow)
|
|
|
|
[[self window] setSuppressMakeKeyFront:NO];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)viewsWindowDidResignKey
|
|
|
|
{
|
|
|
|
if (!mGeckoChild)
|
2007-06-15 15:34:48 -07:00
|
|
|
return;
|
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-01-15 15:11:55 -08:00
|
|
|
|
2012-08-15 11:52:42 -07:00
|
|
|
nsIWidgetListener* listener = mGeckoChild->GetWidgetListener();
|
|
|
|
if (listener)
|
|
|
|
listener->WindowDeactivated();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-06-21 16:58:16 -07:00
|
|
|
// If the call to removeFromSuperview isn't delayed from nsChildView::
|
|
|
|
// TearDownView(), the NSView hierarchy might get changed during calls to
|
|
|
|
// [ChildView drawRect:], which leads to "beyond bounds" exceptions in
|
|
|
|
// NSCFArray. For more info see bmo bug 373122. Apple's docs claim that
|
2007-05-30 11:25:44 -07:00
|
|
|
// removeFromSuperviewWithoutNeedingDisplay "can be safely invoked during
|
|
|
|
// display" (whatever "display" means). But it's _not_ true that it can be
|
2007-06-21 16:58:16 -07:00
|
|
|
// safely invoked during calls to [NSView drawRect:]. We use
|
|
|
|
// removeFromSuperview here because there's no longer any danger of being
|
|
|
|
// "invoked during display", and because doing do clears up bmo bug 384343.
|
2007-05-30 11:25:44 -07:00
|
|
|
- (void)delayedTearDown
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-06-21 16:58:16 -07:00
|
|
|
[self removeFromSuperview];
|
2007-05-30 11:25:44 -07:00
|
|
|
[self release];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-05-30 11:25:44 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
// drag'n'drop stuff
|
|
|
|
#define kDragServiceContractID "@mozilla.org/widget/dragservice;1"
|
|
|
|
|
2010-03-08 04:35:25 -08:00
|
|
|
- (NSDragOperation)dragOperationForSession:(nsIDragSession*)aDragSession
|
|
|
|
{
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t dragAction;
|
2010-03-08 04:35:25 -08:00
|
|
|
aDragSession->GetDragAction(&dragAction);
|
|
|
|
if (nsIDragService::DRAGDROP_ACTION_LINK & dragAction)
|
|
|
|
return NSDragOperationLink;
|
|
|
|
if (nsIDragService::DRAGDROP_ACTION_COPY & dragAction)
|
|
|
|
return NSDragOperationCopy;
|
|
|
|
if (nsIDragService::DRAGDROP_ACTION_MOVE & dragAction)
|
|
|
|
return NSDragOperationGeneric;
|
|
|
|
return NSDragOperationNone;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// This is a utility function used by NSView drag event methods
|
|
|
|
// to send events. It contains all of the logic needed for Gecko
|
2010-03-08 04:35:25 -08:00
|
|
|
// dragging to work. Returns the appropriate cocoa drag operation code.
|
2012-08-22 08:56:38 -07:00
|
|
|
- (NSDragOperation)doDragAction:(uint32_t)aMessage sender:(id)aSender
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
2007-06-29 20:19:41 -07:00
|
|
|
if (!mGeckoChild)
|
2010-03-08 04:35:25 -08:00
|
|
|
return NSDragOperationNone;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-16 19:24:05 -07:00
|
|
|
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView doDragAction: entered\n"));
|
|
|
|
|
2007-06-29 20:19:41 -07:00
|
|
|
if (!mDragService) {
|
|
|
|
CallGetService(kDragServiceContractID, &mDragService);
|
|
|
|
NS_ASSERTION(mDragService, "Couldn't get a drag service - big problem!");
|
|
|
|
if (!mDragService)
|
2010-03-08 04:35:25 -08:00
|
|
|
return NSDragOperationNone;
|
2007-06-29 20:19:41 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aMessage == NS_DRAGDROP_ENTER)
|
|
|
|
mDragService->StartDragSession();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDragSession> dragSession;
|
|
|
|
mDragService->GetCurrentSession(getter_AddRefs(dragSession));
|
|
|
|
if (dragSession) {
|
2007-04-11 21:37:39 -07:00
|
|
|
if (aMessage == NS_DRAGDROP_OVER) {
|
|
|
|
// fire the drag event at the source. Just ignore whether it was
|
|
|
|
// cancelled or not as there isn't actually a means to stop the drag
|
|
|
|
mDragService->FireDragEventAtSource(NS_DRAGDROP_DRAG);
|
2011-09-30 17:20:33 -07:00
|
|
|
dragSession->SetCanDrop(false);
|
2007-04-11 21:37:39 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
else if (aMessage == NS_DRAGDROP_DROP) {
|
2008-07-21 06:26:34 -07:00
|
|
|
// We make the assumption that the dragOver handlers have correctly set
|
2007-03-22 10:30:00 -07:00
|
|
|
// the |canDrop| property of the Drag Session.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool canDrop = false;
|
2008-08-27 05:07:27 -07:00
|
|
|
if (!NS_SUCCEEDED(dragSession->GetCanDrop(&canDrop)) || !canDrop) {
|
2010-02-01 07:11:08 -08:00
|
|
|
[self doDragAction:NS_DRAGDROP_EXIT sender:aSender];
|
|
|
|
|
2008-08-27 05:07:27 -07:00
|
|
|
nsCOMPtr<nsIDOMNode> sourceNode;
|
|
|
|
dragSession->GetSourceNode(getter_AddRefs(sourceNode));
|
|
|
|
if (!sourceNode) {
|
2011-09-30 17:20:33 -07:00
|
|
|
mDragService->EndDragSession(false);
|
2008-08-27 05:07:27 -07:00
|
|
|
}
|
2010-03-08 04:35:25 -08:00
|
|
|
return NSDragOperationNone;
|
2008-08-27 05:07:27 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-02-23 15:30:39 -08:00
|
|
|
unsigned int modifierFlags = [[NSApp currentEvent] modifierFlags];
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t action = nsIDragService::DRAGDROP_ACTION_MOVE;
|
2007-03-22 10:30:00 -07:00
|
|
|
// force copy = option, alias = cmd-option, default is move
|
|
|
|
if (modifierFlags & NSAlternateKeyMask) {
|
|
|
|
if (modifierFlags & NSCommandKeyMask)
|
|
|
|
action = nsIDragService::DRAGDROP_ACTION_LINK;
|
|
|
|
else
|
|
|
|
action = nsIDragService::DRAGDROP_ACTION_COPY;
|
|
|
|
}
|
|
|
|
dragSession->SetDragAction(action);
|
|
|
|
}
|
|
|
|
|
2007-10-09 11:46:30 -07:00
|
|
|
// set up gecko event
|
2013-10-01 00:23:02 -07:00
|
|
|
WidgetDragEvent geckoEvent(true, aMessage, mGeckoChild);
|
2012-04-24 20:00:02 -07:00
|
|
|
nsCocoaUtils::InitInputEvent(geckoEvent, [NSApp currentEvent]);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-10-09 11:46:30 -07:00
|
|
|
// Use our own coordinates in the gecko event.
|
|
|
|
// Convert event from gecko global coords to gecko view coords.
|
2012-09-29 04:36:09 -07:00
|
|
|
NSPoint draggingLoc = [aSender draggingLocation];
|
|
|
|
NSPoint localPoint = [self convertPoint:draggingLoc fromView:nil];
|
|
|
|
|
2013-08-02 00:05:16 -07:00
|
|
|
geckoEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(
|
|
|
|
mGeckoChild->CocoaPointsToDevPixels(localPoint));
|
2007-10-09 11:46:30 -07:00
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2007-10-09 11:46:30 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
2008-01-15 15:11:55 -08:00
|
|
|
if (!mGeckoChild)
|
2010-03-08 04:35:25 -08:00
|
|
|
return NSDragOperationNone;
|
|
|
|
|
|
|
|
if (dragSession) {
|
|
|
|
switch (aMessage) {
|
|
|
|
case NS_DRAGDROP_ENTER:
|
|
|
|
case NS_DRAGDROP_OVER:
|
|
|
|
return [self dragOperationForSession:dragSession];
|
|
|
|
case NS_DRAGDROP_EXIT:
|
|
|
|
case NS_DRAGDROP_DROP: {
|
|
|
|
nsCOMPtr<nsIDOMNode> sourceNode;
|
|
|
|
dragSession->GetSourceNode(getter_AddRefs(sourceNode));
|
|
|
|
if (!sourceNode) {
|
|
|
|
// We're leaving a window while doing a drag that was
|
|
|
|
// initiated in a different app. End the drag session,
|
|
|
|
// since we're done with it for now (until the user
|
|
|
|
// drags back into mozilla).
|
2011-09-30 17:20:33 -07:00
|
|
|
mDragService->EndDragSession(false);
|
2010-03-08 04:35:25 -08:00
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-08 04:35:25 -08:00
|
|
|
return NSDragOperationGeneric;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
2010-03-08 04:35:25 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSDragOperationNone);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
2007-07-16 19:24:05 -07:00
|
|
|
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView draggingEntered: entered\n"));
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// there should never be a globalDragPboard when "draggingEntered:" is
|
|
|
|
// called, but just in case we'll take care of it here.
|
|
|
|
[globalDragPboard release];
|
|
|
|
|
|
|
|
// Set the global drag pasteboard that will be used for this drag session.
|
|
|
|
// This will be set back to nil when the drag session ends (mouse exits
|
|
|
|
// the view or a drop happens within the view).
|
|
|
|
globalDragPboard = [[sender draggingPasteboard] retain];
|
|
|
|
|
2010-03-08 04:35:25 -08:00
|
|
|
return [self doDragAction:NS_DRAGDROP_ENTER sender:sender];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSDragOperationNone);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
|
|
|
|
{
|
2007-07-16 19:24:05 -07:00
|
|
|
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView draggingUpdated: entered\n"));
|
|
|
|
|
2010-03-08 04:35:25 -08:00
|
|
|
return [self doDragAction:NS_DRAGDROP_OVER sender:sender];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)draggingExited:(id <NSDraggingInfo>)sender
|
|
|
|
{
|
2007-07-16 19:24:05 -07:00
|
|
|
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView draggingExited: entered\n"));
|
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2007-03-22 10:30:00 -07:00
|
|
|
[self doDragAction:NS_DRAGDROP_EXIT sender:sender];
|
2007-10-10 05:19:47 -07:00
|
|
|
NS_IF_RELEASE(mDragService);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
|
|
|
|
{
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2010-03-08 04:35:25 -08:00
|
|
|
BOOL handled = [self doDragAction:NS_DRAGDROP_DROP sender:sender] != NSDragOperationNone;
|
2007-10-10 05:19:47 -07:00
|
|
|
NS_IF_RELEASE(mDragService);
|
|
|
|
return handled;
|
2007-06-29 20:19:41 -07:00
|
|
|
}
|
|
|
|
|
2011-04-25 18:37:20 -07:00
|
|
|
// NSDraggingSource
|
|
|
|
- (void)draggedImage:(NSImage *)anImage movedTo:(NSPoint)aPoint
|
|
|
|
{
|
|
|
|
// Get the drag service if it isn't already cached. The drag service
|
|
|
|
// isn't cached when dragging over a different application.
|
|
|
|
nsCOMPtr<nsIDragService> dragService = mDragService;
|
|
|
|
if (!dragService) {
|
|
|
|
dragService = do_GetService(kDragServiceContractID);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dragService) {
|
|
|
|
NSPoint pnt = [NSEvent mouseLocation];
|
|
|
|
FlipCocoaScreenCoordinate(pnt);
|
|
|
|
dragService->DragMoved(NSToIntRound(pnt.x), NSToIntRound(pnt.y));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-29 20:19:41 -07:00
|
|
|
// NSDraggingSource
|
|
|
|
- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
gDraggedTransferables = nullptr;
|
2007-07-17 16:02:40 -07:00
|
|
|
|
2009-02-17 07:51:12 -08:00
|
|
|
NSEvent *currentEvent = [NSApp currentEvent];
|
|
|
|
gUserCancelledDrag = ([currentEvent type] == NSKeyDown &&
|
2012-07-03 22:59:50 -07:00
|
|
|
[currentEvent keyCode] == kVK_Escape);
|
2009-02-17 07:51:12 -08:00
|
|
|
|
2007-06-29 20:19:41 -07:00
|
|
|
if (!mDragService) {
|
|
|
|
CallGetService(kDragServiceContractID, &mDragService);
|
|
|
|
NS_ASSERTION(mDragService, "Couldn't get a drag service - big problem!");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mDragService) {
|
2009-04-13 06:00:29 -07:00
|
|
|
// set the dragend point from the current mouse location
|
|
|
|
nsDragService* dragService = static_cast<nsDragService *>(mDragService);
|
|
|
|
NSPoint pnt = [NSEvent mouseLocation];
|
|
|
|
FlipCocoaScreenCoordinate(pnt);
|
2009-04-16 08:58:23 -07:00
|
|
|
dragService->SetDragEndPoint(nsIntPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y)));
|
2009-04-13 06:00:29 -07:00
|
|
|
|
2009-05-26 16:23:15 -07:00
|
|
|
// XXX: dropEffect should be updated per |operation|.
|
|
|
|
// As things stand though, |operation| isn't well handled within "our"
|
|
|
|
// events, that is, when the drop happens within the window: it is set
|
|
|
|
// either to NSDragOperationGeneric or to NSDragOperationNone.
|
|
|
|
// For that reason, it's not yet possible to override dropEffect per the
|
|
|
|
// given OS value, and it's also unclear what's the correct dropEffect
|
|
|
|
// value for NSDragOperationGeneric that is passed by other applications.
|
|
|
|
// All that said, NSDragOperationNone is still reliable.
|
|
|
|
if (operation == NSDragOperationNone) {
|
|
|
|
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
|
|
|
|
dragService->GetDataTransfer(getter_AddRefs(dataTransfer));
|
2012-02-07 10:02:32 -08:00
|
|
|
if (dataTransfer)
|
|
|
|
dataTransfer->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE);
|
2009-05-26 16:23:15 -07:00
|
|
|
}
|
|
|
|
|
2011-09-30 17:20:33 -07:00
|
|
|
mDragService->EndDragSession(true);
|
2007-06-29 20:19:41 -07:00
|
|
|
NS_RELEASE(mDragService);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
[globalDragPboard release];
|
|
|
|
globalDragPboard = nil;
|
2009-11-06 02:21:41 -08:00
|
|
|
[gLastDragMouseDownEvent release];
|
|
|
|
gLastDragMouseDownEvent = nil;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-06-29 20:19:41 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-06-29 20:19:41 -07:00
|
|
|
// NSDraggingSource
|
|
|
|
// this is just implemented so we comply with the NSDraggingSource informal protocol
|
2009-08-31 18:00:13 -07:00
|
|
|
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
|
2007-06-29 20:19:41 -07:00
|
|
|
{
|
|
|
|
return UINT_MAX;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-07-16 19:24:05 -07:00
|
|
|
// This method is a callback typically invoked in response to a drag ending on the desktop
|
|
|
|
// or a Findow folder window; the argument passed is a path to the drop location, to be used
|
|
|
|
// in constructing a complete pathname for the file(s) we want to create as a result of
|
|
|
|
// the drag.
|
2009-08-31 18:00:13 -07:00
|
|
|
- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDestination
|
2007-07-16 19:24:05 -07:00
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-07-16 19:24:05 -07:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView namesOfPromisedFilesDroppedAtDestination: entering callback for promised files\n"));
|
|
|
|
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> targFile;
|
2011-09-30 17:20:33 -07:00
|
|
|
NS_NewLocalFile(EmptyString(), true, getter_AddRefs(targFile));
|
2007-07-16 19:24:05 -07:00
|
|
|
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(targFile);
|
|
|
|
if (!macLocalFile) {
|
|
|
|
NS_ERROR("No Mac local file");
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)dropDestination))) {
|
|
|
|
NS_ERROR("failed InitWithCFURL");
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2007-07-17 16:02:40 -07:00
|
|
|
if (!gDraggedTransferables)
|
|
|
|
return nil;
|
2007-07-16 19:24:05 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t transferableCount;
|
2007-07-17 16:02:40 -07:00
|
|
|
rv = gDraggedTransferables->Count(&transferableCount);
|
2007-07-16 19:24:05 -07:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return nil;
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < transferableCount; i++) {
|
2007-07-16 19:24:05 -07:00
|
|
|
nsCOMPtr<nsISupports> genericItem;
|
2007-07-17 16:02:40 -07:00
|
|
|
gDraggedTransferables->GetElementAt(i, getter_AddRefs(genericItem));
|
2007-07-16 19:24:05 -07:00
|
|
|
nsCOMPtr<nsITransferable> item(do_QueryInterface(genericItem));
|
|
|
|
if (!item) {
|
|
|
|
NS_ERROR("no transferable");
|
|
|
|
return nil;
|
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
item->Init(nullptr);
|
2007-07-16 19:24:05 -07:00
|
|
|
|
2012-06-05 19:08:30 -07:00
|
|
|
item->SetTransferData(kFilePromiseDirectoryMime, macLocalFile, sizeof(nsIFile*));
|
2007-07-16 19:24:05 -07:00
|
|
|
|
|
|
|
// now request the kFilePromiseMime data, which will invoke the data provider
|
|
|
|
// If successful, the returned data is a reference to the resulting file.
|
|
|
|
nsCOMPtr<nsISupports> fileDataPrimitive;
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t dataSize = 0;
|
2007-07-16 19:24:05 -07:00
|
|
|
item->GetTransferData(kFilePromiseMime, getter_AddRefs(fileDataPrimitive), &dataSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSPasteboard* generalPboard = [NSPasteboard pasteboardWithName:NSDragPboard];
|
|
|
|
NSData* data = [generalPboard dataForType:@"application/x-moz-file-promise-dest-filename"];
|
|
|
|
NSString* name = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
|
|
NSArray* rslt = [NSArray arrayWithObject:name];
|
|
|
|
|
|
|
|
[name release];
|
|
|
|
|
|
|
|
return rslt;
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-07-16 19:24:05 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-12-15 12:56:29 -08:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
// Support for the "Services" menu. We currently only support sending strings
|
2009-03-17 19:04:01 -07:00
|
|
|
// and HTML to system services.
|
2008-12-15 12:56:29 -08:00
|
|
|
|
|
|
|
- (id)validRequestorForSendType:(NSString *)sendType
|
|
|
|
returnType:(NSString *)returnType
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
|
|
|
// sendType contains the type of data that the service would like this
|
|
|
|
// application to send to it. sendType is nil if the service is not
|
|
|
|
// requesting any data.
|
|
|
|
//
|
|
|
|
// returnType contains the type of data the the service would like to
|
|
|
|
// return to this application (e.g., to overwrite the selection).
|
|
|
|
// returnType is nil if the service will not return any data.
|
|
|
|
//
|
|
|
|
// The following condition thus triggers when the service expects a string
|
2010-01-10 17:45:45 -08:00
|
|
|
// or HTML from us or no data at all AND when the service will either not
|
|
|
|
// send back any data to us or will send a string or HTML back to us.
|
|
|
|
|
|
|
|
#define IsSupportedType(typeStr) ([typeStr isEqual:NSStringPboardType] || [typeStr isEqual:NSHTMLPboardType])
|
|
|
|
|
|
|
|
id result = nil;
|
2008-12-15 12:56:29 -08:00
|
|
|
|
2010-01-10 17:45:45 -08:00
|
|
|
if ((!sendType || IsSupportedType(sendType)) &&
|
|
|
|
(!returnType || IsSupportedType(returnType))) {
|
2008-12-15 12:56:29 -08:00
|
|
|
if (mGeckoChild) {
|
2010-01-10 17:45:45 -08:00
|
|
|
// Assume that this object will be able to handle this request.
|
|
|
|
result = self;
|
2009-03-17 19:04:01 -07:00
|
|
|
|
2010-01-10 17:45:45 -08:00
|
|
|
// Keep the ChildView alive during this operation.
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
|
|
|
|
|
|
|
// Determine if there is a selection (if sending to the service).
|
|
|
|
if (sendType) {
|
2013-10-01 00:23:00 -07:00
|
|
|
WidgetQueryContentEvent event(true, NS_QUERY_CONTENT_STATE,
|
|
|
|
mGeckoChild);
|
2010-03-10 13:24:40 -08:00
|
|
|
// This might destroy our widget (and null out mGeckoChild).
|
2010-01-10 17:45:45 -08:00
|
|
|
mGeckoChild->DispatchWindowEvent(event);
|
2010-03-10 13:24:40 -08:00
|
|
|
if (!mGeckoChild || !event.mSucceeded || !event.mReply.mHasSelection)
|
2010-01-10 17:45:45 -08:00
|
|
|
result = nil;
|
|
|
|
}
|
2009-12-30 14:29:26 -08:00
|
|
|
|
2010-01-10 17:45:45 -08:00
|
|
|
// Determine if we can paste (if receiving data from the service).
|
2010-03-10 13:24:40 -08:00
|
|
|
if (mGeckoChild && returnType) {
|
2013-09-26 23:20:54 -07:00
|
|
|
WidgetContentCommandEvent command(true,
|
|
|
|
NS_CONTENT_COMMAND_PASTE_TRANSFERABLE,
|
|
|
|
mGeckoChild, true);
|
2010-03-10 13:24:40 -08:00
|
|
|
// This might possibly destroy our widget (and null out mGeckoChild).
|
2010-01-10 17:45:45 -08:00
|
|
|
mGeckoChild->DispatchWindowEvent(command);
|
2010-03-10 13:24:40 -08:00
|
|
|
if (!mGeckoChild || !command.mSucceeded || !command.mIsEnabled)
|
2010-01-10 17:45:45 -08:00
|
|
|
result = nil;
|
|
|
|
}
|
2009-03-17 19:04:01 -07:00
|
|
|
}
|
2008-12-15 12:56:29 -08:00
|
|
|
}
|
|
|
|
|
2010-01-10 17:45:45 -08:00
|
|
|
#undef IsSupportedType
|
|
|
|
|
|
|
|
// Give the superclass a chance if this object will not handle this request.
|
|
|
|
if (!result)
|
|
|
|
result = [super validRequestorForSendType:sendType returnType:returnType];
|
|
|
|
|
|
|
|
return result;
|
2008-12-15 12:56:29 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard
|
|
|
|
types:(NSArray *)types
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2009-03-17 19:04:01 -07:00
|
|
|
|
|
|
|
// Make sure that the service will accept strings or HTML.
|
|
|
|
if ([types containsObject:NSStringPboardType] == NO &&
|
|
|
|
[types containsObject:NSHTMLPboardType] == NO)
|
2008-12-15 12:56:29 -08:00
|
|
|
return NO;
|
|
|
|
|
2009-03-17 19:04:01 -07:00
|
|
|
// Bail out if there is no Gecko object.
|
2008-12-15 12:56:29 -08:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return NO;
|
2009-03-17 19:04:01 -07:00
|
|
|
|
|
|
|
// Obtain the current selection.
|
2013-10-01 00:23:00 -07:00
|
|
|
WidgetQueryContentEvent event(true,
|
|
|
|
NS_QUERY_SELECTION_AS_TRANSFERABLE,
|
|
|
|
mGeckoChild);
|
2009-03-17 19:04:01 -07:00
|
|
|
mGeckoChild->DispatchWindowEvent(event);
|
|
|
|
if (!event.mSucceeded || !event.mReply.mTransferable)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
// Transform the transferable to an NSDictionary.
|
|
|
|
NSDictionary* pasteboardOutputDict = nsClipboard::PasteboardDictFromTransferable(event.mReply.mTransferable);
|
|
|
|
if (!pasteboardOutputDict)
|
2008-12-15 12:56:29 -08:00
|
|
|
return NO;
|
|
|
|
|
2009-03-17 19:04:01 -07:00
|
|
|
// Declare the pasteboard types.
|
|
|
|
unsigned int typeCount = [pasteboardOutputDict count];
|
|
|
|
NSMutableArray * types = [NSMutableArray arrayWithCapacity:typeCount];
|
|
|
|
[types addObjectsFromArray:[pasteboardOutputDict allKeys]];
|
|
|
|
[pboard declareTypes:types owner:nil];
|
|
|
|
|
|
|
|
// Write the data to the pasteboard.
|
|
|
|
for (unsigned int i = 0; i < typeCount; i++) {
|
|
|
|
NSString* currentKey = [types objectAtIndex:i];
|
|
|
|
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
|
|
|
|
|
|
|
if (currentKey == NSStringPboardType ||
|
|
|
|
currentKey == kCorePboardType_url ||
|
|
|
|
currentKey == kCorePboardType_urld ||
|
|
|
|
currentKey == kCorePboardType_urln) {
|
|
|
|
[pboard setString:currentValue forType:currentKey];
|
|
|
|
} else if (currentKey == NSHTMLPboardType) {
|
|
|
|
[pboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue)) forType:currentKey];
|
|
|
|
} else if (currentKey == NSTIFFPboardType) {
|
|
|
|
[pboard setData:currentValue forType:currentKey];
|
|
|
|
} else if (currentKey == NSFilesPromisePboardType) {
|
|
|
|
[pboard setPropertyList:currentValue forType:currentKey];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
2008-12-15 12:56:29 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
|
|
|
|
}
|
|
|
|
|
2010-01-10 17:45:45 -08:00
|
|
|
// Called if the service wants us to replace the current selection.
|
2008-12-15 12:56:29 -08:00
|
|
|
- (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pboard
|
|
|
|
{
|
2010-01-10 17:45:45 -08:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return NO;
|
2012-07-30 07:20:58 -07:00
|
|
|
trans->Init(nullptr);
|
2010-01-10 17:45:45 -08:00
|
|
|
|
|
|
|
trans->AddDataFlavor(kUnicodeMime);
|
|
|
|
trans->AddDataFlavor(kHTMLMime);
|
|
|
|
|
|
|
|
rv = nsClipboard::TransferableFromPasteboard(trans, pboard);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return NO;
|
|
|
|
|
2011-09-30 17:20:33 -07:00
|
|
|
NS_ENSURE_TRUE(mGeckoChild, false);
|
2010-01-10 17:45:45 -08:00
|
|
|
|
2013-09-26 23:20:54 -07:00
|
|
|
WidgetContentCommandEvent command(true,
|
|
|
|
NS_CONTENT_COMMAND_PASTE_TRANSFERABLE,
|
|
|
|
mGeckoChild);
|
2010-01-10 17:45:45 -08:00
|
|
|
command.mTransferable = trans;
|
|
|
|
mGeckoChild->DispatchWindowEvent(command);
|
|
|
|
|
|
|
|
return command.mSucceeded && command.mIsEnabled;
|
2008-12-15 12:56:29 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
|
|
|
|
/* Every ChildView has a corresponding mozDocAccessible object that is doing all
|
|
|
|
the heavy lifting. The topmost ChildView corresponds to a mozRootAccessible
|
|
|
|
object.
|
|
|
|
|
|
|
|
All ChildView needs to do is to route all accessibility calls (from the NSAccessibility APIs)
|
|
|
|
down to its object, pretending that they are the same.
|
|
|
|
*/
|
|
|
|
- (id<mozAccessible>)accessible
|
|
|
|
{
|
2007-06-15 15:34:48 -07:00
|
|
|
if (!mGeckoChild)
|
|
|
|
return nil;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
id<mozAccessible> nativeAccessible = nil;
|
2008-01-15 15:11:55 -08:00
|
|
|
|
2008-04-07 21:38:52 -07:00
|
|
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
2008-01-15 15:11:55 -08:00
|
|
|
nsCOMPtr<nsIWidget> kungFuDeathGrip2(mGeckoChild);
|
2012-11-17 18:01:44 -08:00
|
|
|
nsRefPtr<a11y::Accessible> accessible = mGeckoChild->GetDocumentAccessible();
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!accessible)
|
2008-01-15 15:11:55 -08:00
|
|
|
return nil;
|
|
|
|
|
2012-08-20 07:27:01 -07:00
|
|
|
accessible->GetNativeInterface((void**)&nativeAccessible);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG_hakan
|
|
|
|
NSAssert(![nativeAccessible isExpired], @"native acc is expired!!!");
|
|
|
|
#endif
|
2012-08-20 07:27:01 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return nativeAccessible;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Implementation of formal mozAccessible formal protocol (enabling mozViews
|
|
|
|
to talk to mozAccessible objects in the accessibility module). */
|
|
|
|
|
|
|
|
- (BOOL)hasRepresentedView
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)representedView
|
|
|
|
{
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isRoot
|
|
|
|
{
|
|
|
|
return [[self accessible] isRoot];
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
- (void)printHierarchy
|
|
|
|
{
|
|
|
|
[[self accessible] printHierarchy];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
// general
|
|
|
|
|
|
|
|
- (BOOL)accessibilityIsIgnored
|
|
|
|
{
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityIsIgnored];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [[self accessible] accessibilityIsIgnored];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)accessibilityHitTest:(NSPoint)point
|
|
|
|
{
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityHitTest:point];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [[self accessible] accessibilityHitTest:point];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)accessibilityFocusedUIElement
|
|
|
|
{
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityFocusedUIElement];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [[self accessible] accessibilityFocusedUIElement];
|
|
|
|
}
|
|
|
|
|
|
|
|
// actions
|
|
|
|
|
|
|
|
- (NSArray*)accessibilityActionNames
|
|
|
|
{
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityActionNames];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [[self accessible] accessibilityActionNames];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*)accessibilityActionDescription:(NSString*)action
|
|
|
|
{
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityActionDescription:action];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [[self accessible] accessibilityActionDescription:action];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)accessibilityPerformAction:(NSString*)action
|
|
|
|
{
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityPerformAction:action];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [[self accessible] accessibilityPerformAction:action];
|
|
|
|
}
|
|
|
|
|
|
|
|
// attributes
|
|
|
|
|
|
|
|
- (NSArray*)accessibilityAttributeNames
|
|
|
|
{
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityAttributeNames];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [[self accessible] accessibilityAttributeNames];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute
|
|
|
|
{
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityIsAttributeSettable:attribute];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return [[self accessible] accessibilityIsAttributeSettable:attribute];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)accessibilityAttributeValue:(NSString*)attribute
|
|
|
|
{
|
2008-02-20 15:47:05 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2012-08-20 07:27:01 -07:00
|
|
|
if (!mozilla::a11y::ShouldA11yBeEnabled())
|
|
|
|
return [super accessibilityAttributeValue:attribute];
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
id<mozAccessible> accessible = [self accessible];
|
2012-08-20 07:27:01 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// if we're the root (topmost) accessible, we need to return our native AXParent as we
|
|
|
|
// traverse outside to the hierarchy of whoever embeds us. thus, fall back on NSView's
|
|
|
|
// default implementation for this attribute.
|
|
|
|
if ([attribute isEqualToString:NSAccessibilityParentAttribute] && [accessible isRoot]) {
|
|
|
|
id parentAccessible = [super accessibilityAttributeValue:attribute];
|
|
|
|
return parentAccessible;
|
|
|
|
}
|
|
|
|
|
|
|
|
return [accessible accessibilityAttributeValue:attribute];
|
2008-02-20 15:47:05 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* ACCESSIBILITY */
|
|
|
|
|
|
|
|
@end
|
2007-04-15 06:43:55 -07:00
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
void
|
|
|
|
ChildViewMouseTracker::OnDestroyView(ChildView* aView)
|
|
|
|
{
|
2011-08-08 07:43:13 -07:00
|
|
|
if (sLastMouseEventView == aView) {
|
2009-09-22 19:31:37 -07:00
|
|
|
sLastMouseEventView = nil;
|
2011-08-13 07:25:39 -07:00
|
|
|
[sLastMouseMoveEvent release];
|
|
|
|
sLastMouseMoveEvent = nil;
|
2011-08-08 07:43:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChildViewMouseTracker::OnDestroyWindow(NSWindow* aWindow)
|
|
|
|
{
|
|
|
|
if (sWindowUnderMouse == aWindow) {
|
|
|
|
sWindowUnderMouse = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChildViewMouseTracker::MouseEnteredWindow(NSEvent* aEvent)
|
|
|
|
{
|
|
|
|
sWindowUnderMouse = [aEvent window];
|
|
|
|
ReEvaluateMouseEnterState(aEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChildViewMouseTracker::MouseExitedWindow(NSEvent* aEvent)
|
|
|
|
{
|
|
|
|
if (sWindowUnderMouse == [aEvent window]) {
|
|
|
|
sWindowUnderMouse = nil;
|
|
|
|
ReEvaluateMouseEnterState(aEvent);
|
|
|
|
}
|
2009-09-22 19:31:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildViewMouseTracker::ReEvaluateMouseEnterState(NSEvent* aEvent, ChildView* aOldView)
|
2009-09-22 19:31:37 -07:00
|
|
|
{
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildView* oldView = aOldView ? aOldView : sLastMouseEventView;
|
2009-12-11 13:56:59 -08:00
|
|
|
sLastMouseEventView = ViewForEvent(aEvent);
|
|
|
|
if (sLastMouseEventView != oldView) {
|
2009-09-22 19:31:37 -07:00
|
|
|
// Send enter and / or exit events.
|
2013-10-01 23:38:27 -07:00
|
|
|
WidgetMouseEvent::exitType type =
|
|
|
|
[sLastMouseEventView window] == [oldView window] ?
|
|
|
|
WidgetMouseEvent::eChild : WidgetMouseEvent::eTopLevel;
|
2009-10-21 00:02:13 -07:00
|
|
|
[oldView sendMouseEnterOrExitEvent:aEvent enter:NO type:type];
|
2009-09-22 19:31:37 -07:00
|
|
|
// After the cursor exits the window set it to a visible regular arrow cursor.
|
2013-10-01 23:38:27 -07:00
|
|
|
if (type == WidgetMouseEvent::eTopLevel) {
|
2009-09-22 19:31:37 -07:00
|
|
|
[[nsCursorManager sharedInstance] setCursor:eCursor_standard];
|
|
|
|
}
|
2009-12-11 13:56:59 -08:00
|
|
|
[sLastMouseEventView sendMouseEnterOrExitEvent:aEvent enter:YES type:type];
|
2009-09-22 19:31:37 -07:00
|
|
|
}
|
2009-12-11 13:56:59 -08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:25:39 -07:00
|
|
|
void
|
|
|
|
ChildViewMouseTracker::ResendLastMouseMoveEvent()
|
|
|
|
{
|
|
|
|
if (sLastMouseMoveEvent) {
|
|
|
|
MouseMoved(sLastMouseMoveEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-11 13:56:59 -08:00
|
|
|
void
|
|
|
|
ChildViewMouseTracker::MouseMoved(NSEvent* aEvent)
|
|
|
|
{
|
2011-08-08 07:43:13 -07:00
|
|
|
MouseEnteredWindow(aEvent);
|
2009-12-11 13:56:59 -08:00
|
|
|
[sLastMouseEventView handleMouseMoved:aEvent];
|
2011-08-13 07:25:39 -07:00
|
|
|
if (sLastMouseMoveEvent != aEvent) {
|
|
|
|
[sLastMouseMoveEvent release];
|
|
|
|
sLastMouseMoveEvent = [aEvent retain];
|
|
|
|
}
|
2009-09-22 19:31:37 -07:00
|
|
|
}
|
|
|
|
|
2011-08-17 15:30:52 -07:00
|
|
|
void
|
|
|
|
ChildViewMouseTracker::MouseScrolled(NSEvent* aEvent)
|
|
|
|
{
|
|
|
|
if (!nsCocoaUtils::IsMomentumScrollEvent(aEvent)) {
|
|
|
|
// Store the position so we can pin future momentum scroll events.
|
|
|
|
sLastScrollEventScreenLocation = nsCocoaUtils::ScreenLocationForEvent(aEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
ChildView*
|
|
|
|
ChildViewMouseTracker::ViewForEvent(NSEvent* aEvent)
|
|
|
|
{
|
2011-08-08 07:43:13 -07:00
|
|
|
NSWindow* window = sWindowUnderMouse;
|
2010-07-16 05:48:02 -07:00
|
|
|
if (!window)
|
2009-09-22 19:31:37 -07:00
|
|
|
return nil;
|
|
|
|
|
|
|
|
NSPoint windowEventLocation = nsCocoaUtils::EventLocationForWindow(aEvent, window);
|
|
|
|
NSView* view = [[[window contentView] superview] hitTest:windowEventLocation];
|
2013-02-05 13:40:34 -08:00
|
|
|
|
2010-07-16 05:48:02 -07:00
|
|
|
if (![view isKindOfClass:[ChildView class]])
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
ChildView* childView = (ChildView*)view;
|
2010-08-09 09:12:50 -07:00
|
|
|
// If childView is being destroyed return nil.
|
|
|
|
if (![childView widget])
|
|
|
|
return nil;
|
2010-07-16 05:48:02 -07:00
|
|
|
return WindowAcceptsEvent(window, aEvent, childView) ? childView : nil;
|
2009-09-22 19:31:37 -07:00
|
|
|
}
|
|
|
|
|
2013-09-17 16:36:03 -07:00
|
|
|
void
|
2013-10-01 00:23:02 -07:00
|
|
|
ChildViewMouseTracker::AttachPluginEvent(WidgetMouseEventBase& aMouseEvent,
|
2013-09-17 16:36:03 -07:00
|
|
|
ChildView* aView,
|
|
|
|
NSEvent* aNativeMouseEvent,
|
|
|
|
int aPluginEventType,
|
|
|
|
void* aPluginEventHolder)
|
|
|
|
{
|
|
|
|
if (![aView isPluginView] ||
|
|
|
|
[aView pluginEventModel] != NPEventModelCocoa) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NPCocoaEvent* cocoaEvent = (NPCocoaEvent*)aPluginEventHolder;
|
|
|
|
nsCocoaUtils::InitNPCocoaEvent(cocoaEvent);
|
|
|
|
NSPoint point = [aView convertPoint:[aNativeMouseEvent locationInWindow]
|
|
|
|
fromView:nil];
|
|
|
|
NPCocoaEventType type = (NPCocoaEventType)aPluginEventType;
|
|
|
|
// XXX We should consider dropping this code, which causes data.mouse.pluginX
|
|
|
|
// and data.mouse.pluginY to be set to '5' for mouse-entered and mouse-exited
|
|
|
|
// events. But note that it's been in the tree since the Cocoa NPAPI event
|
|
|
|
// model was first implemented four years ago, without any known complaints.
|
|
|
|
//
|
|
|
|
// Similar code first appeared (without explanation) in a very early version
|
|
|
|
// ("fix 0.3") of the patch for bug 435041 ("Implement Cocoa NPAPI event
|
|
|
|
// model for Mac OS X"). But there's no trace of it in the WebKit code that
|
|
|
|
// was used as a model for much of that patch.
|
2013-09-30 10:05:48 -07:00
|
|
|
#if (0)
|
2013-09-17 16:36:03 -07:00
|
|
|
if (type == NPCocoaEventMouseEntered ||
|
|
|
|
type == NPCocoaEventMouseExited) {
|
|
|
|
point.x = point.y = 5;
|
|
|
|
}
|
2013-09-30 10:05:48 -07:00
|
|
|
#endif
|
2013-09-17 16:36:03 -07:00
|
|
|
NSUInteger clickCount = 0;
|
|
|
|
if (type != NPCocoaEventMouseEntered &&
|
|
|
|
type != NPCocoaEventMouseExited &&
|
|
|
|
type != NPCocoaEventScrollWheel) {
|
|
|
|
clickCount = [aNativeMouseEvent clickCount];
|
|
|
|
}
|
|
|
|
cocoaEvent->type = type;
|
|
|
|
cocoaEvent->data.mouse.modifierFlags = [aNativeMouseEvent modifierFlags];
|
|
|
|
cocoaEvent->data.mouse.pluginX = point.x;
|
|
|
|
cocoaEvent->data.mouse.pluginY = point.y;
|
|
|
|
cocoaEvent->data.mouse.buttonNumber = [aNativeMouseEvent buttonNumber];
|
|
|
|
cocoaEvent->data.mouse.clickCount = clickCount;
|
|
|
|
cocoaEvent->data.mouse.deltaX = [aNativeMouseEvent deltaX];
|
|
|
|
cocoaEvent->data.mouse.deltaY = [aNativeMouseEvent deltaY];
|
|
|
|
cocoaEvent->data.mouse.deltaZ = [aNativeMouseEvent deltaZ];
|
|
|
|
aMouseEvent.pluginEvent = cocoaEvent;
|
|
|
|
}
|
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
BOOL
|
2010-07-16 05:48:02 -07:00
|
|
|
ChildViewMouseTracker::WindowAcceptsEvent(NSWindow* aWindow, NSEvent* aEvent,
|
|
|
|
ChildView* aView, BOOL aIsClickThrough)
|
2009-09-22 19:31:37 -07:00
|
|
|
{
|
|
|
|
// Right mouse down events may get through to all windows, even to a top level
|
|
|
|
// window with an open sheet.
|
2010-05-14 03:21:25 -07:00
|
|
|
if (!aWindow || [aEvent type] == NSRightMouseDown)
|
2009-09-22 19:31:37 -07:00
|
|
|
return YES;
|
|
|
|
|
|
|
|
id delegate = [aWindow delegate];
|
|
|
|
if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]])
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
nsIWidget *windowWidget = [(WindowDelegate *)delegate geckoWidget];
|
|
|
|
if (!windowWidget)
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
nsWindowType windowType;
|
|
|
|
windowWidget->GetWindowType(windowType);
|
|
|
|
|
2010-05-14 03:21:25 -07:00
|
|
|
NSWindow* topLevelWindow = nil;
|
|
|
|
|
2009-09-22 19:31:37 -07:00
|
|
|
switch (windowType) {
|
|
|
|
case eWindowType_popup:
|
|
|
|
// If this is a context menu, it won't have a parent. So we'll always
|
|
|
|
// accept mouse move events on context menus even when none of our windows
|
|
|
|
// is active, which is the right thing to do.
|
|
|
|
// For panels, the parent window is the XUL window that owns the panel.
|
2010-07-16 05:48:02 -07:00
|
|
|
return WindowAcceptsEvent([aWindow parentWindow], aEvent, aView, aIsClickThrough);
|
2009-09-22 19:31:37 -07:00
|
|
|
|
|
|
|
case eWindowType_toplevel:
|
|
|
|
case eWindowType_dialog:
|
2010-05-14 03:21:25 -07:00
|
|
|
if ([aWindow attachedSheet])
|
|
|
|
return NO;
|
2009-09-22 19:31:37 -07:00
|
|
|
|
2010-05-14 03:21:25 -07:00
|
|
|
topLevelWindow = aWindow;
|
|
|
|
break;
|
2009-09-22 19:31:37 -07:00
|
|
|
case eWindowType_sheet: {
|
|
|
|
nsIWidget* parentWidget = windowWidget->GetSheetWindowParent();
|
|
|
|
if (!parentWidget)
|
|
|
|
return YES;
|
|
|
|
|
2010-05-14 03:21:25 -07:00
|
|
|
topLevelWindow = (NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
break;
|
2009-09-22 19:31:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return YES;
|
|
|
|
}
|
2010-05-14 03:21:25 -07:00
|
|
|
|
|
|
|
if (!topLevelWindow ||
|
2010-07-16 05:48:02 -07:00
|
|
|
([topLevelWindow isMainWindow] && !aIsClickThrough) ||
|
2010-05-14 03:21:25 -07:00
|
|
|
[aEvent type] == NSOtherMouseDown ||
|
|
|
|
(([aEvent modifierFlags] & NSCommandKeyMask) != 0 &&
|
|
|
|
[aEvent type] != NSMouseMoved))
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
// If we're here then we're dealing with a left click or mouse move on an
|
2010-07-16 05:48:02 -07:00
|
|
|
// inactive window or something similar. Ask Gecko what to do.
|
|
|
|
return [aView inactiveWindowAcceptsMouseEvent:aEvent];
|
2009-09-22 19:31:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
2009-02-06 09:36:04 -08:00
|
|
|
@interface NSView (MethodSwizzling)
|
|
|
|
- (BOOL)nsChildView_NSView_mouseDownCanMoveWindow;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSView (MethodSwizzling)
|
|
|
|
|
|
|
|
// All top-level browser windows belong to the ToolbarWindow class and have
|
|
|
|
// NSTexturedBackgroundWindowMask turned on in their "style" (see particularly
|
|
|
|
// [ToolbarWindow initWithContentRect:...] in nsCocoaWindow.mm). This style
|
|
|
|
// normally means the window "may be moved by clicking and dragging anywhere
|
|
|
|
// in the window background", but we've suppressed this by giving the
|
|
|
|
// ChildView class a mouseDownCanMoveWindow method that always returns NO.
|
|
|
|
// Normally a ToolbarWindow's contentView (not a ChildView) returns YES when
|
|
|
|
// NSTexturedBackgroundWindowMask is turned on. But normally this makes no
|
|
|
|
// difference. However, under some (probably very unusual) circumstances
|
|
|
|
// (and only on Leopard) it *does* make a difference -- for example it
|
|
|
|
// triggers bmo bugs 431902 and 476393. So here we make sure that a
|
|
|
|
// ToolbarWindow's contentView always returns NO from the
|
|
|
|
// mouseDownCanMoveWindow method.
|
|
|
|
- (BOOL)nsChildView_NSView_mouseDownCanMoveWindow
|
|
|
|
{
|
|
|
|
NSWindow *ourWindow = [self window];
|
|
|
|
NSView *contentView = [ourWindow contentView];
|
|
|
|
if ([ourWindow isKindOfClass:[ToolbarWindow class]] && (self == contentView))
|
2013-02-05 13:40:34 -08:00
|
|
|
return [ourWindow isMovableByWindowBackground];
|
2009-02-06 09:36:04 -08:00
|
|
|
return [self nsChildView_NSView_mouseDownCanMoveWindow];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2011-08-18 13:39:54 -07:00
|
|
|
|
|
|
|
#ifdef __LP64__
|
|
|
|
// When using blocks, at least on OS X 10.7, the OS sometimes calls
|
|
|
|
// +[NSEvent removeMonitor:] more than once on a single event monitor, which
|
|
|
|
// causes crashes. See bug 678607. We hook these methods to work around
|
|
|
|
// the problem.
|
|
|
|
@interface NSEvent (MethodSwizzling)
|
|
|
|
+ (id)nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:(unsigned long long)mask handler:(id)block;
|
|
|
|
+ (void)nsChildView_NSEvent_removeMonitor:(id)eventMonitor;
|
|
|
|
@end
|
|
|
|
|
|
|
|
// This is a local copy of the AppKit frameworks sEventObservers hashtable.
|
|
|
|
// It only stores "local monitors". We use it to ensure that +[NSEvent
|
|
|
|
// removeMonitor:] is never called more than once on the same local monitor.
|
|
|
|
static NSHashTable *sLocalEventObservers = nil;
|
|
|
|
|
|
|
|
@implementation NSEvent (MethodSwizzling)
|
|
|
|
|
|
|
|
+ (id)nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:(unsigned long long)mask handler:(id)block
|
|
|
|
{
|
|
|
|
if (!sLocalEventObservers) {
|
|
|
|
sLocalEventObservers = [[NSHashTable hashTableWithOptions:
|
|
|
|
NSHashTableStrongMemory | NSHashTableObjectPointerPersonality] retain];
|
|
|
|
}
|
|
|
|
id retval =
|
|
|
|
[self nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:mask handler:block];
|
|
|
|
if (sLocalEventObservers && retval && ![sLocalEventObservers containsObject:retval]) {
|
|
|
|
[sLocalEventObservers addObject:retval];
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void)nsChildView_NSEvent_removeMonitor:(id)eventMonitor
|
|
|
|
{
|
|
|
|
if (sLocalEventObservers && [eventMonitor isKindOfClass: ::NSClassFromString(@"_NSLocalEventObserver")]) {
|
|
|
|
if (![sLocalEventObservers containsObject:eventMonitor]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[sLocalEventObservers removeObject:eventMonitor];
|
|
|
|
}
|
|
|
|
[self nsChildView_NSEvent_removeMonitor:eventMonitor];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
#endif // #ifdef __LP64__
|