Mouse move events can be double processed, causes menu flicker and other issues. b=406362 r=smichaud sr=roc
authorjoshmoz@gmail.com
Wed, 05 Dec 2007 15:17:08 -0800
changeset 8779 699b3d0070ec64782e166ce412b827ac7d855587
parent 8778 afa937f28c935982623d47ea3bbd8f2cdf66e026
child 8780 be07ec7dd93d669c93408512fbb658fd9ce789cb
push idunknown
push userunknown
push dateunknown
reviewerssmichaud, roc
bugs406362
milestone1.9b2pre
Mouse move events can be double processed, causes menu flicker and other issues. b=406362 r=smichaud sr=roc
widget/src/cocoa/nsChildView.mm
widget/src/cocoa/nsCocoaUtils.h
widget/src/cocoa/nsCocoaUtils.mm
widget/src/cocoa/nsCocoaWindow.mm
widget/src/cocoa/nsScreenCocoa.mm
widget/src/cocoa/nsScreenManagerCocoa.mm
widget/src/cocoa/nsToolkit.mm
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -151,18 +151,16 @@ nsIWidget         * gRollupWidget   = ns
 - (BOOL)childViewHasPlugin;
 
 - (BOOL)isRectObscuredBySubview:(NSRect)inRect;
 
 - (void)processPendingRedraws;
 
 - (BOOL)ensureCorrectMouseEventTarget:(NSEvent *)anEvent;
 
-+ (BOOL)isEvent:(NSEvent*)anEvent overWindow:(NSWindow*)aWindow;
-
 - (void)maybeInitContextMenuTracking;
 
 - (nsChildView *)getGeckoChild;
 
 #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;
@@ -218,17 +216,17 @@ ConvertGeckoRectToMacRect(const nsRect& 
   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
 FlipCocoaScreenCoordinate (NSPoint &inPoint)
 {  
-  inPoint.y = FlippedScreenY(inPoint.y);
+  inPoint.y = nsCocoaUtils::FlippedScreenY(inPoint.y);
 }
   
 
 static PRUint32
 UnderlineAttributeToTextRangeType(PRUint32 aUnderlineStyle, NSRange selRange)
 {
 #ifdef DEBUG_IME
   NSLog(@"****in underlineAttributeToTextRangeType = %d", aUnderlineStyle);
@@ -2316,107 +2314,116 @@ NSEvent* gLastDragEvent = nil;
                                                 clickCount:[theEvent clickCount]
                                                   pressure:[theEvent pressure]];
     [self rightMouseDown:clickHoldEvent];
   }
 }
 #endif
 
 
-// If gRollupWidget exists, mouse events that happen over it should be rerouted
-// to it if they've been sent elsewhere. Returns NO if the event was rerouted,
-// YES otherwise. The return value indicates whether or not the event already had
-// the correct target.
-// This is needed when the user tries to navigate a context menu while keeping
-// the mouse-button down (left or right mouse button) -- the OS thinks this is
-// a dragging operation, so it sends events (mouseMoved and mouseUp) to the
+// Events should always go to the window that is directly under the point where
+// the event happened, with one exception. If there is no window under the event,
+// mouse moved events should go to the rollup widget if it exists. The return value
+// of this method indicates whether or not the event was supposed to be sent to this
+// view. If the return value is YES, then this view should continue to process the
+// event. If the return value is NO, the event was rerouted and this view should not
+// process the event.
+//
+// Rerouting may be needed when the user tries to navigate a context menu while
+// keeping the mouse-button down (left or right mouse button) -- the OS thinks this
+// is a dragging operation, so it sends events (mouseMoved and mouseUp) to the
 // window where the dragging operation started (the parent of the context
 // menu window).  It also works around a bizarre Apple bug - if (while a context
 // menu is open) you move the mouse over another app's window and then back over
 // the context menu, mouseMoved events will be sent to the window underneath the
 // context menu.
-- (BOOL)ensureCorrectMouseEventTarget:(NSEvent *)anEvent
+- (BOOL)ensureCorrectMouseEventTarget:(NSEvent*)anEvent
 {
-  if (!gRollupWidget)
+  NSWindow* windowUnderMouse = nsCocoaUtils::FindWindowUnderPoint(nsCocoaUtils::ScreenLocationForEvent(anEvent));
+
+  if (windowUnderMouse == mWindow)
     return YES;
 
-  // Return YES if we can't get a native window for the rollup widget or if our window
-  // is the popup window.
-  NSWindow *popupWindow = (NSWindow*) gRollupWidget->GetNativeData(NS_NATIVE_WINDOW);
-  if (!popupWindow || (mWindow == popupWindow))
-    return YES;
-
-  // Don't bother retargeting if the event is not over the popup window.
-  NSPoint windowEventLocation = [anEvent locationInWindow];
-  NSPoint screenEventLocation = [mWindow convertBaseToScreen:windowEventLocation];
-  if (!NSPointInRect(screenEventLocation, [popupWindow frame]))
-    return YES;
+  if (!windowUnderMouse) {
+    if ([anEvent type] == NSMouseMoved) {
+      if (gRollupWidget) {
+        // If a mouse moved event is not over any window and there is a rollup widget, the event
+        // should go to the rollup widget.
+        NSWindow* rollupWindow = (NSWindow*)gRollupWidget->GetNativeData(NS_NATIVE_WINDOW);
+        if (mWindow == rollupWindow)
+          return YES;
+        else
+          windowUnderMouse = rollupWindow;
+      }
+      else {
+        // If the event is not over a window and is a mouse moved event but there is no rollup widget,
+        // then we don't want it to get handled. Essentially, reroute it to nowhere.
+        return NO;
+      }
+    }
+    else {
+      // If the event is not over a window and is not a mouse moved event, then we don't
+      // want it to get handled. Essentially, reroute it to nowhere.
+      return NO;
+    }
+  }
 
   NSEventType type = [anEvent type];
-  NSPoint locationInPopupWindow = [popupWindow convertScreenToBase:screenEventLocation];
+  NSPoint newWindowLocation = nsCocoaUtils::EventLocationForWindow(anEvent, windowUnderMouse);
   NSEvent *newEvent = nil;
 
   // If anEvent is a mouseUp event, send an extra mouseDown event before
   // sending a mouseUp event -- this is needed to support selection by
   // dragging the mouse to a menu item and then releasing it.  We retain
-  // popupWindow in case it gets destroyed as a result of the extra
+  // the window in case it gets destroyed as a result of the extra
   // mouseDown (and release it below).
-  if ((type == NSLeftMouseUp) || (type == NSRightMouseUp)) {
-    [popupWindow retain];
+  if (type == NSLeftMouseUp || type == NSRightMouseUp) {
+    [windowUnderMouse retain];
     NSEventType extraEventType;
     switch (type) {
       case NSLeftMouseUp:
         extraEventType = NSLeftMouseDown;
         break;
       case NSRightMouseUp:
         extraEventType = NSRightMouseDown;
         break;
       default:
         extraEventType = (NSEventType) 0;
         break;
     }
     newEvent = [NSEvent mouseEventWithType:extraEventType
-                                  location:locationInPopupWindow
+                                  location:newWindowLocation
                              modifierFlags:[anEvent modifierFlags]
                                  timestamp:GetCurrentEventTime()
-                              windowNumber:[popupWindow windowNumber]
+                              windowNumber:[windowUnderMouse windowNumber]
                                    context:nil
                                eventNumber:0
                                 clickCount:1
                                   pressure:0.0];
-    [popupWindow sendEvent:newEvent];
+    [windowUnderMouse sendEvent:newEvent];
   }
 
   newEvent = [NSEvent mouseEventWithType:type
-                                location:locationInPopupWindow
+                                location:newWindowLocation
                            modifierFlags:[anEvent modifierFlags]
                                timestamp:GetCurrentEventTime()
-                            windowNumber:[popupWindow windowNumber]
+                            windowNumber:[windowUnderMouse windowNumber]
                                  context:nil
                              eventNumber:0
                               clickCount:1
                                 pressure:0.0];
-  [popupWindow sendEvent:newEvent];
-
-  if ((type == NSLeftMouseUp) || (type == NSRightMouseUp))
-    [popupWindow release];
+  [windowUnderMouse sendEvent:newEvent];
+
+  if (type == NSLeftMouseUp || type == NSRightMouseUp)
+    [windowUnderMouse release];
 
   return NO;
 }
 
 
-+ (BOOL)isEvent:(NSEvent*)anEvent overWindow:(NSWindow*)aWindow
-{
-  if (!aWindow)
-    return NO;
-  NSPoint screenEventLocation = [[anEvent window] convertBaseToScreen:[anEvent locationInWindow]];
-  return NSPointInRect(screenEventLocation, [aWindow frame]);
-}
-
-
 // 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
 {
   if (!gRollupWidget)
@@ -2481,17 +2488,17 @@ class nsNonNativeContextMenuEvent : publ
 - (BOOL)maybeRollup:(NSEvent*)theEvent
 {
   if (mLastMenuForEventEvent == theEvent)
     return PR_FALSE;
 
   PRBool retVal = PR_FALSE;
   if (gRollupWidget && gRollupListener) {
     NSWindow* currentPopup = static_cast<NSWindow*>(gRollupWidget->GetNativeData(NS_NATIVE_WINDOW));
-    if (![ChildView isEvent:theEvent overWindow:currentPopup]) {
+    if (!nsCocoaUtils::IsEventOverWindow(theEvent, currentPopup)) {
       PRBool rollup = PR_TRUE;
       if ([theEvent type] == NSScrollWheel) {
         gRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
         // We don't want the event passed on for scrollwheel events if we're
         // not supposed to close the popup.  Otherwise the background window
         // will scroll when a custom context menu or the autoscroll popup is
         // open (and the mouse isn't over the popup) -- which doesn't seem right.
         // This change resolves bmo bug 344367.
@@ -2509,17 +2516,17 @@ class nsNonNativeContextMenuEvent : publ
           PRUint32 count = 0;
           widgetChain->Count(&count);
           for (PRUint32 i = 0; i < count; i++) {
             nsCOMPtr<nsISupports> genericWidget;
             widgetChain->GetElementAt(i, getter_AddRefs(genericWidget));
             nsCOMPtr<nsIWidget> widget(do_QueryInterface(genericWidget));
             if (widget) {
               NSWindow* currWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
-              if ([ChildView isEvent:theEvent overWindow:currWindow]) {
+              if (nsCocoaUtils::IsEventOverWindow(theEvent, currWindow)) {
                 rollup = PR_FALSE;
                 break;
               }
             }
           } // foreach parent menu widget
         }
       } // if rollup listener knows about menus
 
@@ -2641,104 +2648,50 @@ static nsEventStatus SendGeckoMouseEnter
   nsEventStatus status;
   widget->DispatchEvent(&event, status);
   return status;
 }
 
 
 - (void)mouseMoved:(NSEvent*)theEvent
 {
-  NSPoint windowEventLocation = [theEvent locationInWindow];
+  NSPoint windowEventLocation = nsCocoaUtils::EventLocationForWindow(theEvent, mWindow);
   NSPoint screenEventLocation = [mWindow convertBaseToScreen:windowEventLocation];
   NSPoint viewEventLocation = [self convertPoint:windowEventLocation fromView:nil];
 
   // Installing a mouseMoved handler on the EventMonitor target (in
   // nsToolkit::RegisterForAllProcessMouseEvents()) means that some of the
   // events received here come from other processes.  For this reason we need
   // to avoid processing them unless they're over a context menu -- otherwise
   // tooltips and other mouse-hover effects will "work" even when our app
   // doesn't have the focus.
   BOOL mouseEventIsOverRollupWidget = NO;
   if (gRollupWidget) {
     NSWindow *popupWindow = (NSWindow*)gRollupWidget->GetNativeData(NS_NATIVE_WINDOW);
-    mouseEventIsOverRollupWidget = [ChildView isEvent:theEvent overWindow:popupWindow];
+    mouseEventIsOverRollupWidget = nsCocoaUtils::IsEventOverWindow(theEvent, popupWindow);
   }
+
   if (![NSApp isActive] && !mouseEventIsOverRollupWidget) {
     if (sLastViewEntered) {
       nsIWidget* lastViewEnteredWidget = [(NSView<mozView>*)sLastViewEntered widget];
       SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_EXIT, lastViewEnteredWidget, nsMouseEvent::eReal, &viewEventLocation);
       sLastViewEntered = nil;
     }
     return;
   }
 
   if (![self ensureCorrectMouseEventTarget:theEvent])
     return;
 
-  // If this is a popup window and the event is not over it, then we may want
-  // to send the event to another window.  (Even with bmo bug 378645 fixed
-  // ("popup windows still receive native mouse move events after being
-  // closed"), the following is still needed to deal with mouseMoved events
-  // that happen over other objects while a context menu is up (and has the
-  // focus).)
-  if ([mWindow level] == NSPopUpMenuWindowLevel &&
-      !NSPointInRect(screenEventLocation, [mWindow frame])) {
-    NSWindow* otherWindowForEvent = nil;
-    
-    // look for another popup window that is under the mouse
-    NSArray* appWindows = [NSApp windows];
-    unsigned int appWindowsCount = [appWindows count];
-    for (unsigned int i = 0; i < appWindowsCount; i++) {
-      NSWindow* currentWindow = [appWindows objectAtIndex:i];
-      if (currentWindow != mWindow &&
-          [currentWindow level] == NSPopUpMenuWindowLevel &&
-          [currentWindow isVisible] &&
-          NSPointInRect(screenEventLocation, [currentWindow frame])) {
-        // found another popup window to send the event to
-        otherWindowForEvent = currentWindow;
-        break;
-      }
-    }
-    
-    if (!otherWindowForEvent) {
-      // If the event is outside this active popup window but not over another popup window,
-      // see if the event is over the main window and route it there if so.
-      NSWindow* mainWindow = [NSApp mainWindow];
-      if (NSPointInRect(screenEventLocation, [mainWindow frame])) {
-        otherWindowForEvent = mainWindow;
-      }
-    }
-    
-    if (otherWindowForEvent) {
-      NSPoint locationInOtherWindow = [otherWindowForEvent convertScreenToBase:screenEventLocation];
-      NSView* targetView = [[otherWindowForEvent contentView] hitTest:locationInOtherWindow];
-      if (targetView) {
-        NSEvent* newEvent = [NSEvent mouseEventWithType:NSMouseMoved
-                                               location:locationInOtherWindow
-                                          modifierFlags:[theEvent modifierFlags]
-                                              timestamp:[theEvent timestamp]
-                                           windowNumber:[otherWindowForEvent windowNumber]
-                                                context:nil
-                                            eventNumber:[theEvent eventNumber]
-                                             clickCount:0
-                                               pressure:0.0];
-        [targetView mouseMoved:newEvent];
-      }
-      return;
-    }
-    // at this point we mimic GTK2 by sending the event to our popup window if we
-    // couldn't find an alternative
-  }
-
   NSView* view = [[mWindow contentView] hitTest:windowEventLocation];
   if (view) {
     // we shouldn't handle this if the hit view is not us
     if (view != (NSView*)self) {
       [view mouseMoved:theEvent];
-      return;      
+      return;
     }
   }
   else {
     // If the hit test returned nil then the mouse isn't over the window. If thse mouse
     // exited the window then send mouse exit to the last view in the window it was over.
     if (sLastViewEntered) {
       // NSLog(@"sending NS_MOUSE_EXIT event with point %f,%f\n", viewEventLocation.x, viewEventLocation.y);
       nsIWidget* lastViewEnteredWidget = [(NSView<mozView>*)sLastViewEntered widget];
--- a/widget/src/cocoa/nsCocoaUtils.h
+++ b/widget/src/cocoa/nsCocoaUtils.h
@@ -40,29 +40,48 @@
 
 #ifndef nsCocoaUtils_h_
 #define nsCocoaUtils_h_
 
 #import <Cocoa/Cocoa.h>
 
 #include "nsRect.h"
 
-//
-// Returns the given y coordinate, which must be in screen coordinates,
-// flipped from Gecko to Cocoa or Cocoa to Gecko.
-//
-float FlippedScreenY(float y);
+class nsCocoaUtils
+{
+  public:
+  // Returns the height of the primary screen (the one with the menu bar, which
+  // is documented to be the first in the |screens| array).
+  static float MenuBarScreenHeight();
 
-/*
- * Gecko rects (nsRect) contain an origin (x,y) in a coordinate
- * system with (0,0) in the top-left of the primary screen. Cocoa rects
- * (NSRect) contain an origin (x,y) in a coordinate system with (0,0)
- * in the bottom-left of the primary screen. Both nsRect and NSRect
- * contain width/height info, with no difference in their use.
- */
-NSRect geckoRectToCocoaRect(const nsRect &geckoRect);
-
-//
-// See explanation for geckoRectToCocoaRect, guess what this does...
-//
-nsRect cocoaRectToGeckoRect(const NSRect &cocoaRect);
+  // Returns the given y coordinate, which must be in screen coordinates,
+  // flipped from Gecko to Cocoa or Cocoa to Gecko.
+  static float FlippedScreenY(float y);
+  
+  // Gecko rects (nsRect) contain an origin (x,y) in a coordinate
+  // system with (0,0) in the top-left of the primary screen. Cocoa rects
+  // (NSRect) contain an origin (x,y) in a coordinate system with (0,0)
+  // in the bottom-left of the primary screen. Both nsRect and NSRect
+  // contain width/height info, with no difference in their use.
+  static NSRect GeckoRectToCocoaRect(const nsRect &geckoRect);
+  
+  // See explanation for geckoRectToCocoaRect, guess what this does...
+  static nsRect CocoaRectToGeckoRect(const NSRect &cocoaRect);
+  
+  // Gives the location for the event in screen coordinates. Do not call this
+  // unless the window the event was originally targeted at is still alive!
+  static NSPoint ScreenLocationForEvent(NSEvent* anEvent);
+  
+  // Determines if an event happened over a window, whether or not the event
+  // is for the window. Does not take window z-order into account.
+  static BOOL IsEventOverWindow(NSEvent* anEvent, NSWindow* aWindow);
+  
+  // Events are set up so that their coordinates refer to the window to which they
+  // were originally sent. If we reroute the event somewhere else, we'll have
+  // to get the window coordinates this way. Do not call this unless the window
+  // the event was originally targeted at is still alive!
+  static NSPoint EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow);
+  
+  // Finds the foremost window that is under the mouse for the current application.
+  static NSWindow* FindWindowUnderPoint(NSPoint aPoint);  
+};
 
 #endif // nsCocoaUtils_h_
--- a/widget/src/cocoa/nsCocoaUtils.mm
+++ b/widget/src/cocoa/nsCocoaUtils.mm
@@ -35,47 +35,87 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsCocoaUtils.h"
 
-// Returns the height of the primary screen (the one with the menu bar, which
-// is documented to be the first in the |screens| array).
-float MenuBarScreenHeight()
+
+float nsCocoaUtils::MenuBarScreenHeight()
 {
   NSArray* allScreens = [NSScreen screens];
   if ([allScreens count])
     return [[allScreens objectAtIndex:0] frame].size.height;
   else
     return 0; // If there are no screens, there's not much we can say.
 }
 
 
-float FlippedScreenY(float y)
+float nsCocoaUtils::FlippedScreenY(float y)
 {
   return MenuBarScreenHeight() - y;
 }
 
 
-NSRect geckoRectToCocoaRect(const nsRect &geckoRect)
+NSRect nsCocoaUtils::GeckoRectToCocoaRect(const nsRect &geckoRect)
 {
   // We only need to change the Y coordinate by starting with the primary screen
   // height, subtracting the gecko Y coordinate, and subtracting the height.
   return NSMakeRect(geckoRect.x,
                     MenuBarScreenHeight() - (geckoRect.y + geckoRect.height),
                     geckoRect.width,
                     geckoRect.height);
 }
 
 
-nsRect cocoaRectToGeckoRect(const NSRect &cocoaRect)
+nsRect nsCocoaUtils::CocoaRectToGeckoRect(const NSRect &cocoaRect)
 {
   // We only need to change the Y coordinate by starting with the primary screen
   // height and subtracting both the cocoa y origin and the height of the
   // cocoa rect.
   return nsRect((nscoord)cocoaRect.origin.x,
                 (nscoord)(MenuBarScreenHeight() - (cocoaRect.origin.y + cocoaRect.size.height)),
                 (nscoord)cocoaRect.size.width,
                 (nscoord)cocoaRect.size.height);
 }
+
+
+NSPoint nsCocoaUtils::ScreenLocationForEvent(NSEvent* anEvent)
+{
+  return [[anEvent window] convertBaseToScreen:[anEvent locationInWindow]];
+}
+
+
+BOOL nsCocoaUtils::IsEventOverWindow(NSEvent* anEvent, NSWindow* aWindow)
+{
+  return NSPointInRect(ScreenLocationForEvent(anEvent), [aWindow frame]);
+}
+
+
+NSPoint nsCocoaUtils::EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow)
+{
+  return [aWindow convertScreenToBase:ScreenLocationForEvent(anEvent)];
+}
+
+
+NSWindow* nsCocoaUtils::FindWindowUnderPoint(NSPoint aPoint)
+{
+  int windowCount;
+  NSCountWindows(&windowCount);
+  int* windowList = (int*)malloc(sizeof(int) * windowCount);
+  if (!windowList)
+    return nil;
+  // The list we get back here is in order from front to back.
+  NSWindowList(windowCount, windowList);
+
+  for (int i = 0; i < windowCount; i++) {
+    NSWindow* currentWindow = [NSApp windowWithWindowNumber:windowList[i]];
+    if (currentWindow && NSPointInRect(aPoint, [currentWindow frame])) {
+      free(windowList);
+      return currentWindow;
+    }
+  }
+
+  free(windowList);
+  return nil;
+}
--- a/widget/src/cocoa/nsCocoaWindow.mm
+++ b/widget/src/cocoa/nsCocoaWindow.mm
@@ -336,17 +336,17 @@ nsresult nsCocoaWindow::StandardCreate(n
      *
      * Note: This means that if you put a secondary screen on top of your main
      * screen and open a window in the top screen, it'll be incorrectly shifted
      * down by the height of the menu bar. Same thing would happen in Carbon.
      *
      * Note: If you pass a rect with 0,0 for an origin, the window ends up in a
      * weird place for some reason. This stops that without breaking popups.
      */
-    NSRect rect = geckoRectToCocoaRect(aRect);
+    NSRect rect = nsCocoaUtils::GeckoRectToCocoaRect(aRect);
     
     // compensate for difference between frame and content area height (e.g. title bar)
     NSRect newWindowFrame = [NSWindow frameRectForContentRect:rect styleMask:features];
 
     rect.origin.y -= (newWindowFrame.size.height - rect.size.height);
     
     if (mWindowType != eWindowType_popup)
       rect.origin.y -= ::GetMBarHeight();
@@ -743,17 +743,17 @@ NS_IMETHODIMP nsCocoaWindow::ConstrainPo
 
 NS_IMETHODIMP nsCocoaWindow::Move(PRInt32 aX, PRInt32 aY)
 {
   if (!mWindow || (mBounds.x == aX && mBounds.y == aY))
     return NS_OK;
 
   // The point we have is in Gecko coordinates (origin top-left). Convert
   // it to Cocoa ones (origin bottom-left).
-  NSPoint coord = {aX, FlippedScreenY(aY)};
+  NSPoint coord = {aX, nsCocoaUtils::FlippedScreenY(aY)};
   [mWindow setFrameTopLeftPoint:coord];
 
   return NS_OK;
 }
 
 
 // Position the window behind the given window
 NS_METHOD nsCocoaWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
@@ -792,25 +792,25 @@ NS_METHOD nsCocoaWindow::SetSizeMode(PRI
 }
 
 
 NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
 {
   if (!WindowSizeAllowed(aWidth, aHeight))
     return NS_ERROR_FAILURE;
 
-  nsRect windowBounds(cocoaRectToGeckoRect([mWindow frame]));
+  nsRect windowBounds(nsCocoaUtils::CocoaRectToGeckoRect([mWindow frame]));
   BOOL isMoving = (windowBounds.x != aX || windowBounds.y != aY);
   BOOL isResizing = (windowBounds.width != aWidth || windowBounds.height != aHeight);
 
   if (IsResizing() || !mWindow || (!isMoving && !isResizing))
     return NS_OK;
 
   nsRect geckoRect(aX, aY, aWidth, aHeight);
-  NSRect newFrame = geckoRectToCocoaRect(geckoRect);
+  NSRect newFrame = nsCocoaUtils::GeckoRectToCocoaRect(geckoRect);
 
   // We have to report the size event -first-, to make sure that content
   // repositions itself.  Cocoa views are anchored at the bottom left,
   // so if we don't do this our child view will end up being stuck in the
   // wrong place during a resize.
   if (isResizing)
     ReportSizeEvent(&newFrame);
 
@@ -835,24 +835,24 @@ NS_IMETHODIMP nsCocoaWindow::Resize(PRIn
 }
 
 
 NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
 {
   if (!WindowSizeAllowed(aWidth, aHeight))
     return NS_ERROR_FAILURE;
 
-  nsRect windowBounds(cocoaRectToGeckoRect([mWindow frame]));
+  nsRect windowBounds(nsCocoaUtils::CocoaRectToGeckoRect([mWindow frame]));
   return Resize(windowBounds.x, windowBounds.y, aWidth, aHeight, aRepaint);
 }
 
 
 NS_IMETHODIMP nsCocoaWindow::GetScreenBounds(nsRect &aRect)
 {
-  nsRect windowFrame = cocoaRectToGeckoRect([mWindow frame]);
+  nsRect windowFrame = nsCocoaUtils::CocoaRectToGeckoRect([mWindow frame]);
   aRect.x = windowFrame.x;
   aRect.y = windowFrame.y;
   aRect.width = windowFrame.width;
   aRect.height = windowFrame.height;
   // printf("GetScreenBounds: output: %d,%d,%d,%d\n", aRect.x, aRect.y, aRect.width, aRect.height);
   return NS_OK;
 }
 
@@ -1060,30 +1060,30 @@ NS_IMETHODIMP nsCocoaWindow::SetFocus(PR
 NS_IMETHODIMP nsCocoaWindow::ShowMenuBar(PRBool aShow)
 {
   return NS_ERROR_FAILURE;
 }
 
 
 NS_IMETHODIMP nsCocoaWindow::WidgetToScreen(const nsRect& aOldRect, nsRect& aNewRect)
 {
-  nsRect r = cocoaRectToGeckoRect([mWindow contentRectForFrameRect:[mWindow frame]]);
+  nsRect r = nsCocoaUtils::CocoaRectToGeckoRect([mWindow contentRectForFrameRect:[mWindow frame]]);
 
   aNewRect.x = r.x + aOldRect.x;
   aNewRect.y = r.y + aOldRect.y;
   aNewRect.width = aOldRect.width;
   aNewRect.height = aOldRect.height;
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP nsCocoaWindow::ScreenToWidget(const nsRect& aOldRect, nsRect& aNewRect)
 {
-  nsRect r = cocoaRectToGeckoRect([mWindow contentRectForFrameRect:[mWindow frame]]);
+  nsRect r = nsCocoaUtils::CocoaRectToGeckoRect([mWindow contentRectForFrameRect:[mWindow frame]]);
 
   aNewRect.x = aOldRect.x - r.x;
   aNewRect.y = aOldRect.y - r.y;
   aNewRect.width = aOldRect.width;
   aNewRect.height = aOldRect.height;
 
   return NS_OK;
 }
@@ -1722,21 +1722,19 @@ void patternDraw(void* aInfo, CGContextR
     case NSRightMouseUp:
     case NSOtherMouseDown:
     case NSOtherMouseUp:
     case NSMouseMoved:
     case NSLeftMouseDragged:
     case NSRightMouseDragged:
     case NSOtherMouseDragged:
       if ((contentView = [self contentView]) != nil) {
-        // Since [anEvent window] might not be us, we can't use [anEvent
-        // locationInWindow].
-        windowLocation = [self mouseLocationOutsideOfEventStream];
-        target = [contentView hitTest:[contentView convertPoint:
-                                      windowLocation fromView:nil]];
+        // 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]];
       }
       break;
     default:
       break;
   }
   if (target) {
     switch (type) {
       case NSScrollWheel:
--- a/widget/src/cocoa/nsScreenCocoa.mm
+++ b/widget/src/cocoa/nsScreenCocoa.mm
@@ -51,30 +51,30 @@ nsScreenCocoa::nsScreenCocoa (NSScreen *
 nsScreenCocoa::~nsScreenCocoa ()
 {
     [mScreen release];
 }
 
 NS_IMETHODIMP
 nsScreenCocoa::GetRect(PRInt32 *outX, PRInt32 *outY, PRInt32 *outWidth, PRInt32 *outHeight)
 {
-    nsRect r = cocoaRectToGeckoRect([mScreen frame]);
+    nsRect r = nsCocoaUtils::CocoaRectToGeckoRect([mScreen frame]);
 
     *outX = r.x;
     *outY = r.y;
     *outWidth = r.width;
     *outHeight = r.height;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScreenCocoa::GetAvailRect(PRInt32 *outX, PRInt32 *outY, PRInt32 *outWidth, PRInt32 *outHeight)
 {
-    nsRect r = cocoaRectToGeckoRect([mScreen visibleFrame]);
+    nsRect r = nsCocoaUtils::CocoaRectToGeckoRect([mScreen visibleFrame]);
 
     *outX = r.x;
     *outY = r.y;
     *outWidth = r.width;
     *outHeight = r.height;
 
     return NS_OK;
 }
--- a/widget/src/cocoa/nsScreenManagerCocoa.mm
+++ b/widget/src/cocoa/nsScreenManagerCocoa.mm
@@ -69,17 +69,17 @@ nsScreenManagerCocoa::ScreenForCocoaScre
     return sc.get();
 }
 
 NS_IMETHODIMP
 nsScreenManagerCocoa::ScreenForRect (PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
                                      nsIScreen **outScreen)
 {
     NSEnumerator *screenEnum = [[NSScreen screens] objectEnumerator];
-    NSRect inRect = geckoRectToCocoaRect(nsRect(aX, aY, aWidth, aHeight));
+    NSRect inRect = nsCocoaUtils::GeckoRectToCocoaRect(nsRect(aX, aY, aWidth, aHeight));
     NSScreen *screenWindowIsOn = [NSScreen mainScreen];
     float greatestArea = 0;
 
     while (NSScreen *screen = [screenEnum nextObject]) {
         NSDictionary *desc = [screen deviceDescription];
         if ([desc objectForKey:NSDeviceIsScreen] == nil)
             continue;
 
--- a/widget/src/cocoa/nsToolkit.mm
+++ b/widget/src/cocoa/nsToolkit.mm
@@ -199,17 +199,17 @@ static OSStatus EventMonitorHandler(Even
 // 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
 // coordinates" system), which has a bottom-left origin.
 static NSPoint ConvertCGGlobalToCocoaScreen(CGPoint aPoint)
 {
   NSPoint cocoaPoint;
   cocoaPoint.x = aPoint.x;
-  cocoaPoint.y = FlippedScreenY(aPoint.y);
+  cocoaPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y);
   return cocoaPoint;
 }
 
 
 // Since our event tap is "listen only", events arrive here a little after
 // they've already been processed.
 static CGEventRef EventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
 {