From 365f7999eb3756d1e0eaae130d9efaa7d890ad77 Mon Sep 17 00:00:00 2001
From: Marco Antognini <antognini.marco@gmail.com>
Date: Fri, 28 Jun 2013 13:58:54 +0200
Subject: [PATCH] Fix mouse moved event on OS X when dragging the cursor (close
 #277)

---
 src/SFML/Window/OSX/SFOpenGLView.mm | 74 +++++++++++++++++++++--------
 1 file changed, 54 insertions(+), 20 deletions(-)

diff --git a/src/SFML/Window/OSX/SFOpenGLView.mm b/src/SFML/Window/OSX/SFOpenGLView.mm
index d809019c..ad345d94 100644
--- a/src/SFML/Window/OSX/SFOpenGLView.mm
+++ b/src/SFML/Window/OSX/SFOpenGLView.mm
@@ -63,6 +63,13 @@ BOOL isValidTextUnicode(NSEvent* event);
 ////////////////////////////////////////////////////////////
 -(BOOL)isMouseInside;
 
+////////////////////////////////////////////////////////////
+/// Update the mouse state (in or out) and fire an event
+/// if its state has changed.
+/// 
+////////////////////////////////////////////////////////////
+-(void)updateMouseState;
+
 ////////////////////////////////////////////////////////////
 /// Convert the NSEvent mouse button type to SFML type.
 ///
@@ -204,15 +211,7 @@ BOOL isValidTextUnicode(NSEvent* event);
 -(void)frameDidChange:(NSNotification *)notification
 {
     // Update mouse internal state.
-    BOOL mouseWasIn = m_mouseIsIn;
-    m_mouseIsIn = [self isMouseInside];
-    
-    // Send event if needed.
-    if (mouseWasIn && !m_mouseIsIn) {
-        [self mouseExited:nil];
-    } else if (!mouseWasIn && m_mouseIsIn) {
-        [self mouseEntered:nil];
-    }
+    [self updateMouseState];
     
     // Adapt tracking area for mouse mouse event.
     [self removeTrackingRect:m_trackingTag];
@@ -247,6 +246,21 @@ BOOL isValidTextUnicode(NSEvent* event);
 }
 
 
+////////////////////////////////////////////////////////
+-(void)updateMouseState
+{
+    BOOL mouseWasIn = m_mouseIsIn;
+    m_mouseIsIn = [self isMouseInside];
+    
+    // Send event if needed.
+    if (mouseWasIn && !m_mouseIsIn) {
+        [self mouseExited:nil];
+    } else if (!mouseWasIn && m_mouseIsIn) {
+        [self mouseEntered:nil];
+    }
+}
+
+
 #pragma mark
 #pragma mark Subclassing methods
 
@@ -336,22 +350,39 @@ BOOL isValidTextUnicode(NSEvent* event);
 ////////////////////////////////////////////////////////
 -(void)mouseEntered:(NSEvent *)theEvent
 {
+    // There are two cases when we need to fire an event:
+    // a) the event is nil, meaning that the method was
+    //    called from our code (e.g. updateMouseState)
+    // b) the mouse was outside the view.
+    BOOL shouldFire = (theEvent == nil || m_mouseIsIn == NO);
+
+    // Update status
     m_mouseIsIn = YES;
-    
+
     if (m_requester == 0) return;
-    
-    m_requester->mouseMovedIn();
+
+    // Fire (or not) an event
+    if (shouldFire) {
+        m_requester->mouseMovedIn();
+    }
 }
 
 
 ////////////////////////////////////////////////////////
 -(void)mouseExited:(NSEvent *)theEvent
 {
+    // Similarly to mouseEntered:
+    BOOL shouldFire = (theEvent == nil || m_mouseIsIn == YES);
+
+    // Update status
     m_mouseIsIn = NO;
-    
+
     if (m_requester == 0) return;
-    
-    m_requester->mouseMovedOut();
+
+    // Fire (or not) an event
+    if (shouldFire) {
+        m_requester->mouseMovedOut();
+    }
 }
 
 
@@ -445,12 +476,15 @@ BOOL isValidTextUnicode(NSEvent* event);
 -(void)otherMouseDragged:(NSEvent *)theEvent
 {
     if (m_requester != 0) {
-        // If the event is not useful.
-        if (!m_mouseIsIn) return;
-        
         NSPoint loc = [self cursorPositionFromEvent:theEvent];
-        
-        m_requester->mouseMovedAt(loc.x, loc.y);
+
+        // Make sure the point is inside the view.
+        // (mouseEntered: and mouseExited: are not immediately called
+        //  when the mouse is dragged. That would be too easy!)
+        [self updateMouseState];
+        if (m_mouseIsIn) {
+            m_requester->mouseMovedAt(loc.x, loc.y);
+        }
     }
     
     // If the event is not forwarded by mouseDragged or rightMouseDragged...