Merge backout of changeset fee47b64b378.

This commit is contained in:
Markus Stange 2011-08-09 13:14:50 +02:00
commit dde3628746
7 changed files with 303 additions and 186 deletions

View File

@ -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);
};
//-------------------------------------------------------------------------

View File

@ -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)

View File

@ -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)

View File

@ -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
{

View File

@ -83,6 +83,7 @@ protected:
CFRunLoopSourceRef mSleepWakeNotificationRLS;
io_object_t mPowerNotifier;
EventHandlerRef mEventMonitorHandler;
CFMachPortRef mEventTapPort;
CFRunLoopSourceRef mEventTapRLS;
};

View File

@ -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);

View File

@ -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 },
]],
];