mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-24 02:35:41 +00:00
Merge backout of changeset fee47b64b378.
This commit is contained in:
commit
dde3628746
@ -294,16 +294,16 @@ public:
|
||||
|
||||
static void MouseMoved(NSEvent* aEvent);
|
||||
static void OnDestroyView(ChildView* aView);
|
||||
static void OnDestroyWindow(NSWindow* aWindow);
|
||||
static BOOL WindowAcceptsEvent(NSWindow* aWindow, NSEvent* aEvent,
|
||||
ChildView* aView, BOOL isClickThrough = NO);
|
||||
static void MouseExitedWindow(NSEvent* aEvent);
|
||||
static void MouseEnteredWindow(NSEvent* aEvent);
|
||||
static void ReEvaluateMouseEnterState(NSEvent* aEvent = nil);
|
||||
static ChildView* ViewForEvent(NSEvent* aEvent);
|
||||
|
||||
static ChildView* sLastMouseEventView;
|
||||
static NSWindow* sWindowUnderMouse;
|
||||
|
||||
private:
|
||||
|
||||
static NSWindow* WindowForEvent(NSEvent* aEvent);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -112,6 +112,14 @@ extern "C" {
|
||||
CG_EXTERN void CGContextResetCTM(CGContextRef);
|
||||
CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform);
|
||||
CG_EXTERN void CGContextResetClip(CGContextRef);
|
||||
|
||||
// CGSPrivate.h
|
||||
typedef NSInteger CGSConnection;
|
||||
typedef NSInteger CGSWindow;
|
||||
extern CGSConnection _CGSDefaultConnection();
|
||||
extern CGError CGSGetScreenRectForWindow(const CGSConnection cid, CGSWindow wid, CGRect *outRect);
|
||||
extern CGError CGSGetWindowLevel(const CGSConnection cid, CGSWindow wid, CGWindowLevel *level);
|
||||
extern CGError CGSGetWindowAlpha(const CGSConnection cid, const CGSWindow wid, float* alpha);
|
||||
}
|
||||
|
||||
// defined in nsMenuBarX.mm
|
||||
@ -125,7 +133,6 @@ PRBool gChildViewMethodsSwizzled = PR_FALSE;
|
||||
extern nsISupportsArray *gDraggedTransferables;
|
||||
|
||||
ChildView* ChildViewMouseTracker::sLastMouseEventView = nil;
|
||||
NSWindow* ChildViewMouseTracker::sWindowUnderMouse = nil;
|
||||
|
||||
#ifdef INVALIDATE_DEBUGGING
|
||||
static void blinkRect(Rect* r);
|
||||
@ -1229,24 +1236,6 @@ nsresult nsChildView::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
|
||||
if (!event)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
[NSApp sendEvent:event];
|
||||
return NS_OK;
|
||||
|
||||
@ -3245,6 +3234,11 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
||||
mGeckoChild->DispatchEvent(&event, status);
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent*)aEvent
|
||||
{
|
||||
ChildViewMouseTracker::MouseMoved(aEvent);
|
||||
}
|
||||
|
||||
- (void)handleMouseMoved:(NSEvent*)theEvent
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
@ -4762,33 +4756,8 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
||||
void
|
||||
ChildViewMouseTracker::OnDestroyView(ChildView* aView)
|
||||
{
|
||||
if (sLastMouseEventView == aView) {
|
||||
if (sLastMouseEventView == aView)
|
||||
sLastMouseEventView = nil;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -4812,19 +4781,20 @@ ChildViewMouseTracker::ReEvaluateMouseEnterState(NSEvent* aEvent)
|
||||
void
|
||||
ChildViewMouseTracker::MouseMoved(NSEvent* aEvent)
|
||||
{
|
||||
MouseEnteredWindow(aEvent);
|
||||
ReEvaluateMouseEnterState(aEvent);
|
||||
[sLastMouseEventView handleMouseMoved:aEvent];
|
||||
}
|
||||
|
||||
ChildView*
|
||||
ChildViewMouseTracker::ViewForEvent(NSEvent* aEvent)
|
||||
{
|
||||
NSWindow* window = sWindowUnderMouse;
|
||||
NSWindow* window = WindowForEvent(aEvent);
|
||||
if (!window)
|
||||
return nil;
|
||||
|
||||
NSPoint windowEventLocation = nsCocoaUtils::EventLocationForWindow(aEvent, window);
|
||||
NSView* view = [[[window contentView] superview] hitTest:windowEventLocation];
|
||||
NS_ASSERTION(view, "How can the mouse be over a window but not over a view in that window?");
|
||||
if (![view isKindOfClass:[ChildView class]])
|
||||
return nil;
|
||||
|
||||
@ -4835,6 +4805,102 @@ ChildViewMouseTracker::ViewForEvent(NSEvent* aEvent)
|
||||
return WindowAcceptsEvent(window, aEvent, childView) ? childView : nil;
|
||||
}
|
||||
|
||||
static CGWindowLevel kDockWindowLevel = 0;
|
||||
static CGWindowLevel kPopupWindowLevel = 0;
|
||||
|
||||
static BOOL WindowNumberIsUnderPoint(NSInteger aWindowNumber, NSPoint aPoint) {
|
||||
NSWindow* window = [NSApp windowWithWindowNumber:aWindowNumber];
|
||||
if (window) {
|
||||
// This is one of our own windows.
|
||||
return NSMouseInRect(aPoint, [window frame], NO);
|
||||
}
|
||||
|
||||
CGSConnection cid = _CGSDefaultConnection();
|
||||
|
||||
if (!kDockWindowLevel) {
|
||||
// These constants are in fact function calls, so cache them.
|
||||
kDockWindowLevel = kCGDockWindowLevel;
|
||||
kPopupWindowLevel = kCGPopUpMenuWindowLevel;
|
||||
}
|
||||
|
||||
// Some things put transparent windows on top of everything. Ignore them.
|
||||
CGWindowLevel level;
|
||||
if ((kCGErrorSuccess == CGSGetWindowLevel(cid, aWindowNumber, &level)) &&
|
||||
(level == kDockWindowLevel || // Transparent layer, spanning the whole screen
|
||||
level > kPopupWindowLevel)) // Snapz Pro X while recording a screencast
|
||||
return false;
|
||||
|
||||
// Ignore transparent windows.
|
||||
float alpha;
|
||||
if ((kCGErrorSuccess == CGSGetWindowAlpha(cid, aWindowNumber, &alpha)) &&
|
||||
alpha < 0.1f)
|
||||
return false;
|
||||
|
||||
CGRect rect;
|
||||
if (kCGErrorSuccess != CGSGetScreenRectForWindow(cid, aWindowNumber, &rect))
|
||||
return false;
|
||||
|
||||
CGPoint point = { aPoint.x, nsCocoaUtils::FlippedScreenY(aPoint.y) };
|
||||
return CGRectContainsPoint(rect, point);
|
||||
}
|
||||
|
||||
// Find the window number of the window under the given point, regardless of
|
||||
// which app the window belongs to. Returns 0 if no window was found.
|
||||
static NSInteger WindowNumberAtPoint(NSPoint aPoint) {
|
||||
// We'd like to use the new windowNumberAtPoint API on 10.6 but we can't rely
|
||||
// on it being up-to-date. For example, if we've just opened a window,
|
||||
// windowNumberAtPoint might not know about it yet, so we'd send events to the
|
||||
// wrong window. See bug 557986.
|
||||
// So we'll have to find the right window manually by iterating over all
|
||||
// windows on the screen and testing whether the mouse is inside the window's
|
||||
// rect. We do this using private CGS functions.
|
||||
// Another way of doing it would be to use tracking rects, but those are
|
||||
// view-controlled, so they need to be reset whenever an NSView changes its
|
||||
// size or position, which is expensive. See bug 300904 comment 20.
|
||||
// A problem with using the CGS functions is that we only look at the windows'
|
||||
// rects, not at the transparency of the actual pixel the mouse is over. This
|
||||
// means that we won't treat transparent pixels as transparent to mouse
|
||||
// events, which is a disadvantage over using tracking rects and leads to the
|
||||
// crummy window level workarounds in WindowNumberIsUnderPoint.
|
||||
// But speed is more important.
|
||||
|
||||
// Get the window list.
|
||||
NSInteger windowCount;
|
||||
NSCountWindows(&windowCount);
|
||||
NSInteger* windowList = (NSInteger*)malloc(sizeof(NSInteger) * windowCount);
|
||||
if (!windowList)
|
||||
return nil;
|
||||
|
||||
// The list we get back here is in order from front to back.
|
||||
NSWindowList(windowCount, windowList);
|
||||
for (NSInteger i = 0; i < windowCount; i++) {
|
||||
NSInteger windowNumber = windowList[i];
|
||||
if (WindowNumberIsUnderPoint(windowNumber, aPoint)) {
|
||||
free(windowList);
|
||||
return windowNumber;
|
||||
}
|
||||
}
|
||||
|
||||
free(windowList);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find Gecko window under the mouse. Returns nil if the mouse isn't over
|
||||
// any of our windows.
|
||||
NSWindow*
|
||||
ChildViewMouseTracker::WindowForEvent(NSEvent* anEvent)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
NSPoint screenPoint = nsCocoaUtils::ScreenLocationForEvent(anEvent);
|
||||
NSInteger windowNumber = WindowNumberAtPoint(screenPoint);
|
||||
|
||||
// This will return nil if windowNumber belongs to a window that we don't own.
|
||||
return [NSApp windowWithWindowNumber:windowNumber];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
BOOL
|
||||
ChildViewMouseTracker::WindowAcceptsEvent(NSWindow* aWindow, NSEvent* aEvent,
|
||||
ChildView* aView, BOOL aIsClickThrough)
|
||||
|
@ -81,8 +81,6 @@ typedef struct _nsCocoaWindowList {
|
||||
// is ridiculously slow, so we cache it in the toplevel window for all
|
||||
// descendants to use.
|
||||
float mDPI;
|
||||
|
||||
NSTrackingArea* mTrackingArea;
|
||||
}
|
||||
|
||||
- (void)importState:(NSDictionary*)aState;
|
||||
@ -96,12 +94,6 @@ typedef struct _nsCocoaWindowList {
|
||||
- (void)invalidateShadow;
|
||||
- (float)getDPI;
|
||||
|
||||
- (void)mouseEntered:(NSEvent*)aEvent;
|
||||
- (void)mouseExited:(NSEvent*)aEvent;
|
||||
- (void)mouseMoved:(NSEvent*)aEvent;
|
||||
- (void)updateTrackingArea;
|
||||
- (NSView*)trackingAreaView;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSWindow (Undocumented)
|
||||
|
@ -642,6 +642,7 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
||||
parentIsSheet) {
|
||||
piParentWidget->GetSheetWindowParent(&topNonSheetWindow);
|
||||
[NSApp endSheet:nativeParentWindow];
|
||||
[nativeParentWindow setAcceptsMouseMovedEvents:NO];
|
||||
}
|
||||
|
||||
nsCocoaWindow* sheetShown = nsnull;
|
||||
@ -656,6 +657,7 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
||||
// Only set contextInfo if our parent isn't a sheet.
|
||||
NSWindow* contextInfo = parentIsSheet ? nil : mSheetWindowParent;
|
||||
[TopLevelWindowData deactivateInWindow:mSheetWindowParent];
|
||||
[mWindow setAcceptsMouseMovedEvents:YES];
|
||||
[NSApp beginSheet:mWindow
|
||||
modalForWindow:mSheetWindowParent
|
||||
modalDelegate:mDelegate
|
||||
@ -682,6 +684,7 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
||||
NSInteger windowNumber = [mWindow windowNumber];
|
||||
[mWindow _setWindowNumber:-1];
|
||||
[mWindow _setWindowNumber:windowNumber];
|
||||
[mWindow setAcceptsMouseMovedEvents:YES];
|
||||
// For reasons that aren't yet clear, calls to [NSWindow orderFront:] or
|
||||
// [NSWindow makeKeyAndOrderFront:] can sometimes trigger "Error (1000)
|
||||
// creating CGSWindow", which in turn triggers an internal inconsistency
|
||||
@ -713,6 +716,7 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
||||
ordered:NSWindowAbove];
|
||||
}
|
||||
else {
|
||||
[mWindow setAcceptsMouseMovedEvents:YES];
|
||||
NS_OBJC_BEGIN_TRY_LOGONLY_BLOCK;
|
||||
[mWindow makeKeyAndOrderFront:nil];
|
||||
NS_OBJC_END_TRY_LOGONLY_BLOCK;
|
||||
@ -739,6 +743,8 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
||||
// hide the sheet
|
||||
[NSApp endSheet:mWindow];
|
||||
|
||||
[mWindow setAcceptsMouseMovedEvents:NO];
|
||||
|
||||
[TopLevelWindowData deactivateInWindow:mWindow];
|
||||
|
||||
nsCocoaWindow* siblingSheetToShow = nsnull;
|
||||
@ -768,6 +774,7 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
||||
// If there are no sibling sheets, but the parent is a sheet, restore
|
||||
// it. It wasn't sent any deactivate events when it was hidden, so
|
||||
// don't call through Show, just let the OS put it back up.
|
||||
[nativeParentWindow setAcceptsMouseMovedEvents:YES];
|
||||
[NSApp beginSheet:nativeParentWindow
|
||||
modalForWindow:sheetParent
|
||||
modalDelegate:[nativeParentWindow delegate]
|
||||
@ -780,6 +787,7 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
||||
NS_OBJC_BEGIN_TRY_LOGONLY_BLOCK;
|
||||
[sheetParent makeKeyAndOrderFront:nil];
|
||||
NS_OBJC_END_TRY_LOGONLY_BLOCK;
|
||||
[sheetParent setAcceptsMouseMovedEvents:YES];
|
||||
}
|
||||
SendSetZLevelEvent();
|
||||
}
|
||||
@ -805,6 +813,10 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
||||
if (mWindowType == eWindowType_popup)
|
||||
[NSApp _removeWindowFromCache:mWindow];
|
||||
|
||||
// it's very important to turn off mouse moved events when hiding a window, otherwise
|
||||
// the windows' tracking rects will interfere with each other. (bug 356528)
|
||||
[mWindow setAcceptsMouseMovedEvents:NO];
|
||||
|
||||
// If our popup window is a non-native context menu, tell the OS (and
|
||||
// other programs) that a menu has closed.
|
||||
if ([mWindow isKindOfClass:[PopupWindow class]] &&
|
||||
@ -1405,6 +1417,7 @@ NS_IMETHODIMP nsCocoaWindow::SetFocus(PRBool aState)
|
||||
mPopupContentView->SetFocus(aState);
|
||||
}
|
||||
else if (aState && ([mWindow isVisible] || [mWindow isMiniaturized])) {
|
||||
[mWindow setAcceptsMouseMovedEvents:YES];
|
||||
[mWindow makeKeyAndOrderFront:nil];
|
||||
SendSetZLevelEvent();
|
||||
}
|
||||
@ -1753,9 +1766,6 @@ PRBool nsCocoaWindow::ShouldFocusPlugin()
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)aNotification
|
||||
{
|
||||
BaseWindow* window = [aNotification object];
|
||||
[window updateTrackingArea];
|
||||
|
||||
if (!mGeckoWindow)
|
||||
return;
|
||||
|
||||
@ -1963,11 +1973,6 @@ GetDPI(NSWindow* aWindow)
|
||||
return (heightPx / scaleFactor) / (heightMM / MM_PER_INCH_FLOAT);
|
||||
}
|
||||
|
||||
@interface BaseWindow(Private)
|
||||
- (void)removeTrackingArea;
|
||||
- (void)cursorUpdated:(NSEvent*)aEvent;
|
||||
@end
|
||||
|
||||
@implementation BaseWindow
|
||||
|
||||
- (id)initWithContentRect:(NSRect)aContentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)aFlag
|
||||
@ -1979,8 +1984,6 @@ GetDPI(NSWindow* aWindow)
|
||||
mInactiveTitlebarColor = nil;
|
||||
mScheduledShadowInvalidation = NO;
|
||||
mDPI = GetDPI(self);
|
||||
mTrackingArea = nil;
|
||||
[self updateTrackingArea];
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -1989,8 +1992,6 @@ GetDPI(NSWindow* aWindow)
|
||||
{
|
||||
[mActiveTitlebarColor release];
|
||||
[mInactiveTitlebarColor release];
|
||||
[self removeTrackingArea];
|
||||
ChildViewMouseTracker::OnDestroyWindow(self);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@ -2076,55 +2077,6 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton";
|
||||
return mDPI;
|
||||
}
|
||||
|
||||
- (NSView*)trackingAreaView
|
||||
{
|
||||
NSView* contentView = [self contentView];
|
||||
return [contentView superview] ? [contentView superview] : contentView;
|
||||
}
|
||||
|
||||
- (void)removeTrackingArea
|
||||
{
|
||||
if (mTrackingArea) {
|
||||
[[self trackingAreaView] removeTrackingArea:mTrackingArea];
|
||||
[mTrackingArea release];
|
||||
mTrackingArea = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateTrackingArea
|
||||
{
|
||||
[self removeTrackingArea];
|
||||
|
||||
NSView* view = [self trackingAreaView];
|
||||
const NSTrackingAreaOptions options =
|
||||
NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways;
|
||||
mTrackingArea = [[NSTrackingArea alloc] initWithRect:[view bounds]
|
||||
options:options
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[view addTrackingArea:mTrackingArea];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent*)aEvent
|
||||
{
|
||||
ChildViewMouseTracker::MouseEnteredWindow(aEvent);
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent*)aEvent
|
||||
{
|
||||
ChildViewMouseTracker::MouseExitedWindow(aEvent);
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent*)aEvent
|
||||
{
|
||||
ChildViewMouseTracker::MouseMoved(aEvent);
|
||||
}
|
||||
|
||||
- (void)cursorUpdated:(NSEvent*)aEvent
|
||||
{
|
||||
// Nothing to do here, but NSTrackingArea wants us to implement this method.
|
||||
}
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||
{
|
||||
// Claim the window doesn't respond to this so that the system
|
||||
@ -2507,6 +2459,87 @@ TitlebarDrawCallback(void* aInfo, CGContextRef aContext)
|
||||
|
||||
@implementation PopupWindow
|
||||
|
||||
// The OS treats our custom popup windows very strangely -- many mouse events
|
||||
// sent to them never reach their target NSView objects. (That these windows
|
||||
// are borderless and of level NSPopUpMenuWindowLevel may have something to do
|
||||
// with it.) The best solution is to pre-empt the OS, as follows. (All
|
||||
// events for a given NSWindow object go through its sendEvent: method.)
|
||||
- (void)sendEvent:(NSEvent *)anEvent
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
NSView *target = nil;
|
||||
NSView *contentView = nil;
|
||||
NSEventType type = [anEvent type];
|
||||
NSPoint windowLocation = NSZeroPoint;
|
||||
switch (type) {
|
||||
case NSScrollWheel:
|
||||
case NSLeftMouseDown:
|
||||
case NSLeftMouseUp:
|
||||
case NSRightMouseDown:
|
||||
case NSRightMouseUp:
|
||||
case NSOtherMouseDown:
|
||||
case NSOtherMouseUp:
|
||||
case NSMouseMoved:
|
||||
case NSLeftMouseDragged:
|
||||
case NSRightMouseDragged:
|
||||
case NSOtherMouseDragged:
|
||||
if ((contentView = [self contentView])) {
|
||||
// Since [anEvent window] might not be us, we can't use [anEvent locationInWindow].
|
||||
windowLocation = nsCocoaUtils::EventLocationForWindow(anEvent, self);
|
||||
target = [contentView hitTest:[contentView convertPoint:windowLocation fromView:nil]];
|
||||
// If the hit test failed, the event is targeted here but is not over the window.
|
||||
// Send it to our content view.
|
||||
if (!target)
|
||||
target = contentView;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (target) {
|
||||
switch (type) {
|
||||
case NSScrollWheel:
|
||||
[target scrollWheel:anEvent];
|
||||
break;
|
||||
case NSLeftMouseUp:
|
||||
[target mouseUp:anEvent];
|
||||
break;
|
||||
case NSRightMouseDown:
|
||||
[target rightMouseDown:anEvent];
|
||||
break;
|
||||
case NSRightMouseUp:
|
||||
[target rightMouseUp:anEvent];
|
||||
break;
|
||||
case NSOtherMouseDown:
|
||||
[target otherMouseDown:anEvent];
|
||||
break;
|
||||
case NSOtherMouseUp:
|
||||
[target otherMouseUp:anEvent];
|
||||
break;
|
||||
case NSMouseMoved:
|
||||
[target mouseMoved:anEvent];
|
||||
break;
|
||||
case NSLeftMouseDragged:
|
||||
[target mouseDragged:anEvent];
|
||||
break;
|
||||
case NSRightMouseDragged:
|
||||
[target rightMouseDragged:anEvent];
|
||||
break;
|
||||
case NSOtherMouseDragged:
|
||||
[target otherMouseDragged:anEvent];
|
||||
break;
|
||||
default:
|
||||
[super sendEvent:anEvent];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
[super sendEvent:anEvent];
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
|
||||
backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
|
||||
{
|
||||
|
@ -83,6 +83,7 @@ protected:
|
||||
CFRunLoopSourceRef mSleepWakeNotificationRLS;
|
||||
io_object_t mPowerNotifier;
|
||||
|
||||
EventHandlerRef mEventMonitorHandler;
|
||||
CFMachPortRef mEventTapPort;
|
||||
CFRunLoopSourceRef mEventTapRLS;
|
||||
};
|
||||
|
@ -87,6 +87,7 @@ static PRUintn gToolkitTLSIndex = 0;
|
||||
nsToolkit::nsToolkit()
|
||||
: mInited(false)
|
||||
, mSleepWakeNotificationRLS(nsnull)
|
||||
, mEventMonitorHandler(nsnull)
|
||||
, mEventTapPort(nsnull)
|
||||
, mEventTapRLS(nsnull)
|
||||
{
|
||||
@ -201,6 +202,18 @@ nsToolkit::RemoveSleepWakeNotifcations()
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
// This is the callback used in RegisterForAllProcessMouseEvents.
|
||||
static OSStatus EventMonitorHandler(EventHandlerCallRef aCaller, EventRef aEvent, void* aRefcon)
|
||||
{
|
||||
// Up to Mac OS 10.4 (or when building with the 10.4 SDK), installing a Carbon
|
||||
// event handler like this one caused the OS to post the equivalent Cocoa
|
||||
// events to [NSApp sendEvent:]. When using the 10.5 SDK, this doesn't happen
|
||||
// any more, so we need to do it manually.
|
||||
[NSApp sendEvent:[NSEvent eventWithEventRef:aEvent]];
|
||||
|
||||
return eventNotHandledErr;
|
||||
}
|
||||
|
||||
// Converts aPoint from the CoreGraphics "global display coordinate" system
|
||||
// (which includes all displays/screens and has a top-left origin) to its
|
||||
// (presumed) Cocoa counterpart (assumed to be the same as the "screen
|
||||
@ -262,6 +275,12 @@ nsToolkit::RegisterForAllProcessMouseEvents()
|
||||
return;
|
||||
#endif /* MOZ_USE_NATIVE_POPUP_WINDOWS */
|
||||
|
||||
if (!mEventMonitorHandler) {
|
||||
EventTypeSpec kEvents[] = {{kEventClassMouse, kEventMouseMoved}};
|
||||
InstallEventHandler(GetEventMonitorTarget(), EventMonitorHandler,
|
||||
GetEventTypeCount(kEvents), kEvents, 0,
|
||||
&mEventMonitorHandler);
|
||||
}
|
||||
if (!mEventTapRLS) {
|
||||
// Using an event tap for mouseDown events (instead of installing a
|
||||
// handler for them on the EventMonitor target) works around an Apple
|
||||
@ -301,6 +320,10 @@ nsToolkit::UnregisterAllProcessMouseEventHandlers()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
if (mEventMonitorHandler) {
|
||||
RemoveEventHandler(mEventMonitorHandler);
|
||||
mEventMonitorHandler = nsnull;
|
||||
}
|
||||
if (mEventTapRLS) {
|
||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventTapRLS,
|
||||
kCFRunLoopDefaultMode);
|
||||
|
@ -72,14 +72,12 @@
|
||||
}
|
||||
|
||||
function onTestsFinished() {
|
||||
clearTimeout(gAfterLoopExecution);
|
||||
observe(window, eventMonitor, false);
|
||||
observe(gRightWindow, eventMonitor, false);
|
||||
observe(gPopup, eventMonitor, false);
|
||||
gRightWindow.close();
|
||||
var openerSimpleTest = window.opener.wrappedJSObject.SimpleTest;
|
||||
window.close();
|
||||
openerSimpleTest.finish();
|
||||
window.opener.wrappedJSObject.SimpleTest.finish();
|
||||
}
|
||||
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
@ -130,8 +128,6 @@
|
||||
|
||||
var gExpectedEvents = [];
|
||||
var gRightWindow = null, gPopup = null;
|
||||
var gCurrentMouseX = 0, gCurrentMouseY = 0;
|
||||
var gAfterLoopExecution = 0;
|
||||
|
||||
function testMouse(x, y, msg, elem, win, exp, flags, callback) {
|
||||
clearExpectedEvents();
|
||||
@ -141,16 +137,14 @@
|
||||
gExpectedEvents.push(expEv);
|
||||
});
|
||||
printDebug("sending event: " + x + ", " + y + " (" + msg + ")\n");
|
||||
gCurrentMouseX = x;
|
||||
gCurrentMouseY = y;
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
utils.sendNativeMouseEvent(x, y, msg, flags || 0, elem);
|
||||
gAfterLoopExecution = setTimeout(function () {
|
||||
SimpleTest.executeSoon(function () {
|
||||
clearExpectedEvents();
|
||||
callback();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
function eventListenOnce(elem, name, callback) {
|
||||
@ -188,15 +182,10 @@
|
||||
}
|
||||
|
||||
function processEvent(e) {
|
||||
if (e.screenX != gCurrentMouseX || e.screenY != gCurrentMouseY) {
|
||||
todo(false, "Oh no! Received a stray event from a confused tracking area. Aborting test.");
|
||||
onTestsFinished();
|
||||
return;
|
||||
}
|
||||
var expectedEvent = gExpectedEvents.shift();
|
||||
if (!expectedEvent) {
|
||||
ok(false, "received event I didn't expect: " + eventToString(e));
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if (e.type != expectedEvent.type) {
|
||||
// Didn't get expectedEvent.
|
||||
@ -317,10 +306,6 @@
|
||||
{ type: "mouseup", target: rightElem },
|
||||
{ type: "click", target: rightElem },
|
||||
]],
|
||||
// Move the mouse back over the left window, which is inactive.
|
||||
[150, 170, NSMouseMoved, null, left, [
|
||||
{ type: "mouseout", target: rightElem },
|
||||
]],
|
||||
// Now we're being sneaky. The left window is inactive, but *right*-clicks to it
|
||||
// should still get through. Test that.
|
||||
// Ideally we'd be bracketing that event with over and out events, too, but it
|
||||
@ -342,6 +327,7 @@
|
||||
// Still, mouseout and mouseover events should fire.
|
||||
function raiseLeftWindow(callback) {
|
||||
clearExpectedEvents();
|
||||
gExpectedEvents.push({ screenX: 150, screenY: 170, type: "mouseout", target: rightElem });
|
||||
gExpectedEvents.push({ screenX: 150, screenY: 170, type: "mouseover", target: leftElem });
|
||||
focusAndThen(left, function () { SimpleTest.executeSoon(callback); });
|
||||
},
|
||||
@ -405,20 +391,25 @@
|
||||
// Install the tooltip, but don't show it yet.
|
||||
function setTooltip(callback) {
|
||||
rightElem.setAttribute("tooltip", "tip");
|
||||
gExpectedEvents.push({ screenX: 410, screenY: 180, type: "mousemove", target: rightElem });
|
||||
eventListenOnce(rightElem, "popupshown", callback);
|
||||
gCurrentMouseX = 410;
|
||||
gCurrentMouseY = 180;
|
||||
var utils = right.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
utils.sendNativeMouseEvent(410, 180, NSMouseMoved, 0, null);
|
||||
callback();
|
||||
},
|
||||
// Now the tooltip is visible.
|
||||
// Move the mouse a little to the right.
|
||||
[411, 180, NSMouseMoved, null, right, [
|
||||
// Move the mouse to trigger the appearance of the tooltip.
|
||||
[410, 180, NSMouseMoved, null, right, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
// Move another pixel.
|
||||
// Wait for the tooltip to appear.
|
||||
function (callback) {
|
||||
eventListenOnce(rightElem, "popupshown", callback);
|
||||
},
|
||||
// Now the tooltip is visible.
|
||||
// Move the mouse a little to the right, but send the event to the tooltip's
|
||||
// widget, even though the mouse is not over the tooltip, because that's what
|
||||
// Mac OS X does.
|
||||
[411, 180, NSMouseMoved, tooltip, right, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
// Move another pixel. This time send the event to the right widget.
|
||||
// However, that must not make a difference.
|
||||
[412, 180, NSMouseMoved, null, right, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
@ -443,21 +434,22 @@
|
||||
// Now we move the mouse over the part where the panel rect intersects the
|
||||
// right window's rect. Since the panel is under the window, all the events
|
||||
// should target the right window.
|
||||
// Try with sending to three different targets.
|
||||
[390, 170, NSMouseMoved, null, right, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
[390, 171, NSMouseMoved, null, right, [
|
||||
[390, 171, NSMouseMoved, null, left, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
[391, 171, NSMouseMoved, null, right, [
|
||||
[391, 171, NSMouseMoved, panel, left, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
// Now move off the right window, so that the mouse is directly over the
|
||||
// panel.
|
||||
[260, 170, NSMouseMoved, panel, left, [
|
||||
[260, 170, NSMouseMoved, null, left, [
|
||||
{ type: "mouseout", target: rightElem },
|
||||
]],
|
||||
[260, 171, NSMouseMoved, panel, left, [
|
||||
[260, 171, NSMouseMoved, null, left, [
|
||||
]],
|
||||
[261, 171, NSMouseMoved, panel, left, [
|
||||
]],
|
||||
@ -472,11 +464,11 @@
|
||||
},
|
||||
// Now mouse events should get through to the panel (which is now over the
|
||||
// right window).
|
||||
[387, 170, NSMouseMoved, panel, left, [
|
||||
[387, 170, NSMouseMoved, null, right, [
|
||||
{ type: "mouseover", target: panel },
|
||||
{ type: "mousemove", target: panel },
|
||||
]],
|
||||
[387, 171, NSMouseMoved, panel, left, [
|
||||
[387, 171, NSMouseMoved, null, left, [
|
||||
{ type: "mousemove", target: panel },
|
||||
]],
|
||||
[388, 171, NSMouseMoved, panel, left, [
|
||||
@ -494,12 +486,12 @@
|
||||
// Last test for this part: Hit testing in the Canyon of Nowhere -
|
||||
// the pixel row directly south of the panel, over the left window.
|
||||
// Before bug 515003 we wrongly thought the mouse wasn't over any window.
|
||||
[173, 200, NSMouseMoved, null, left, [
|
||||
[173, 200, NSMouseMoved, panel, left, [
|
||||
{ type: "mouseout", target: panel },
|
||||
{ type: "mouseover", target: leftElem },
|
||||
{ type: "mousemove", target: leftElem },
|
||||
]],
|
||||
[173, 201, NSMouseMoved, null, left, [
|
||||
[173, 201, NSMouseMoved, panel, left, [
|
||||
{ type: "mousemove", target: leftElem },
|
||||
]],
|
||||
|
||||
@ -575,28 +567,32 @@
|
||||
{ type: "mouseup", target: rightElem },
|
||||
{ type: "click", target: rightElem },
|
||||
]],
|
||||
// Move the mouse back over the left window, which is inactive.
|
||||
[150, 170, NSMouseMoved, null, left, [
|
||||
{ type: "mouseout", target: rightElem },
|
||||
{ type: "mouseover", target: leftElem },
|
||||
{ type: "mousemove", target: leftElem },
|
||||
]],
|
||||
// Right-click it.
|
||||
// Now we're being sneaky. The left window is inactive, but *right*-clicks to it
|
||||
// should still get through. Test that.
|
||||
// Ideally we'd be bracketing that event with over and out events, too, but it
|
||||
// probably doesn't matter too much.
|
||||
[150, 170, NSRightMouseDown, null, left, [
|
||||
{ type: "mouseover", target: leftElem, shouldFireButDoesnt: true },
|
||||
{ type: "mousedown", target: leftElem },
|
||||
{ type: "mouseout", target: leftElem, shouldFireButDoesnt: true },
|
||||
]],
|
||||
// Let go of the mouse.
|
||||
[150, 170, NSRightMouseUp, null, left, [
|
||||
{ type: "mouseover", target: leftElem, shouldFireButDoesnt: true },
|
||||
{ type: "mouseup", target: leftElem },
|
||||
{ type: "click", target: leftElem },
|
||||
{ type: "mouseout", target: leftElem, shouldFireButDoesnt: true },
|
||||
]],
|
||||
// Right clicking hasn't focused it, so the window is still inactive.
|
||||
// Let's focus it; this time without the mouse, for variaton's sake.
|
||||
// Still, mouseout and mouseover events should fire.
|
||||
function raiseLeftWindow(callback) {
|
||||
clearExpectedEvents();
|
||||
gExpectedEvents.push({ screenX: 150, screenY: 170, type: "mouseout", target: rightElem });
|
||||
gExpectedEvents.push({ screenX: 150, screenY: 170, type: "mouseover", target: leftElem });
|
||||
focusAndThen(left, function () { SimpleTest.executeSoon(callback); });
|
||||
},
|
||||
// It's active and should still respond to mousemove events.
|
||||
// It's active, so it should respond to mousemove events now.
|
||||
[150, 170, NSMouseMoved, null, left, [
|
||||
{ type: "mousemove", target: leftElem },
|
||||
]],
|
||||
@ -657,22 +653,27 @@
|
||||
|
||||
// Time for our next trick: a tooltip!
|
||||
// Install the tooltip, but don't show it yet.
|
||||
function setTooltip2(callback) {
|
||||
function setTooltip(callback) {
|
||||
rightElem.setAttribute("tooltip", "tip");
|
||||
gExpectedEvents.push({ screenX: 410, screenY: 180, type: "mousemove", target: rightElem });
|
||||
eventListenOnce(rightElem, "popupshown", callback);
|
||||
gCurrentMouseX = 410;
|
||||
gCurrentMouseY = 180;
|
||||
var utils = right.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
utils.sendNativeMouseEvent(410, 180, NSMouseMoved, 0, null);
|
||||
callback();
|
||||
},
|
||||
// Now the tooltip is visible.
|
||||
// Move the mouse a little to the right.
|
||||
[411, 180, NSMouseMoved, null, right, [
|
||||
// Move the mouse to trigger the appearance of the tooltip.
|
||||
[410, 180, NSMouseMoved, null, right, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
// Move another pixel.
|
||||
// Wait for the tooltip to appear.
|
||||
function (callback) {
|
||||
eventListenOnce(rightElem, "popupshown", callback);
|
||||
},
|
||||
// Now the tooltip is visible.
|
||||
// Move the mouse a little to the right, but send the event to the tooltip's
|
||||
// widget, even though the mouse is not over the tooltip, because that's what
|
||||
// Mac OS X does.
|
||||
[411, 180, NSMouseMoved, tooltip, right, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
// Move another pixel. This time send the event to the right widget.
|
||||
// However, that must not make a difference.
|
||||
[412, 180, NSMouseMoved, null, right, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
@ -697,23 +698,24 @@
|
||||
// Now we move the mouse over the part where the panel rect intersects the
|
||||
// right window's rect. Since the panel is under the window, all the events
|
||||
// should target the right window.
|
||||
// Try with sending to three different targets.
|
||||
[390, 170, NSMouseMoved, null, right, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
[390, 171, NSMouseMoved, null, right, [
|
||||
[390, 171, NSMouseMoved, null, left, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
[391, 171, NSMouseMoved, null, right, [
|
||||
[391, 171, NSMouseMoved, panel, left, [
|
||||
{ type: "mousemove", target: rightElem },
|
||||
]],
|
||||
// Now move off the right window, so that the mouse is directly over the
|
||||
// panel.
|
||||
[260, 170, NSMouseMoved, panel, left, [
|
||||
[260, 170, NSMouseMoved, null, left, [
|
||||
{ type: "mouseout", target: rightElem },
|
||||
{ type: "mouseover", target: panel },
|
||||
{ type: "mousemove", target: panel },
|
||||
]],
|
||||
[260, 171, NSMouseMoved, panel, left, [
|
||||
[260, 171, NSMouseMoved, null, left, [
|
||||
{ type: "mousemove", target: panel },
|
||||
]],
|
||||
[261, 171, NSMouseMoved, panel, left, [
|
||||
@ -731,10 +733,10 @@
|
||||
function raiseLeftWindowTakeTwo(callback) {
|
||||
focusAndThen(left, callback);
|
||||
},
|
||||
[387, 170, NSMouseMoved, panel, left, [
|
||||
[387, 170, NSMouseMoved, null, right, [
|
||||
{ type: "mousemove", target: panel },
|
||||
]],
|
||||
[387, 171, NSMouseMoved, panel, left, [
|
||||
[387, 171, NSMouseMoved, null, left, [
|
||||
{ type: "mousemove", target: panel },
|
||||
]],
|
||||
[388, 171, NSMouseMoved, panel, left, [
|
||||
@ -752,12 +754,12 @@
|
||||
// Last test for today: Hit testing in the Canyon of Nowhere -
|
||||
// the pixel row directly south of the panel, over the left window.
|
||||
// Before bug 515003 we wrongly thought the mouse wasn't over any window.
|
||||
[173, 200, NSMouseMoved, null, left, [
|
||||
[173, 200, NSMouseMoved, panel, left, [
|
||||
{ type: "mouseout", target: panel },
|
||||
{ type: "mouseover", target: leftElem },
|
||||
{ type: "mousemove", target: leftElem },
|
||||
]],
|
||||
[173, 201, NSMouseMoved, null, left, [
|
||||
[173, 201, NSMouseMoved, panel, left, [
|
||||
{ type: "mousemove", target: leftElem },
|
||||
]],
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user