Cocoa : Bug fix for continuous grab feature implementation
authorDamien Plisson <damien.plisson@yahoo.fr>
Fri, 9 Oct 2009 17:42:31 +0000 (17:42 +0000)
committerDamien Plisson <damien.plisson@yahoo.fr>
Fri, 9 Oct 2009 17:42:31 +0000 (17:42 +0000)
intern/ghost/intern/GHOST_SystemCocoa.mm
intern/ghost/intern/GHOST_WindowCocoa.h
intern/ghost/intern/GHOST_WindowCocoa.mm

index 2dfdcf7bcec69236deabfa48cd55b17651fd7b40..8bbe446616dc487661054ae6d8c68bc407a898cd 100644 (file)
@@ -812,9 +812,9 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32
        //Quartz Display Services uses the old coordinates (top left origin)
        yf = [[NSScreen mainScreen] frame].size.height -yf;
        
-       CGAssociateMouseAndMouseCursorPosition(false);
+       //CGAssociateMouseAndMouseCursorPosition(false);
        CGWarpMouseCursorPosition(CGPointMake(xf, yf));
-       CGAssociateMouseAndMouseCursorPosition(true);
+       //CGAssociateMouseAndMouseCursorPosition(true);
 
     return GHOST_kSuccess;
 }
@@ -1151,7 +1151,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                        
                                        window->getCursorWarpAccum(x_accum, y_accum);
                                        x_accum += [event deltaX];
-                                       y_accum += [event deltaY];
+                                       y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ...
                                        window->setCursorWarpAccum(x_accum, y_accum);
                                        
                                        pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum));
@@ -1159,6 +1159,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                else { //Normal cursor operation: send mouse position in window
                                        NSPoint mousePos = [event locationInWindow];
                                        pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y));
+                                       window->setCursorWarpAccum(0, 0); //Mouse motion occured between two cursor warps, so we can reset the delta counter
                                }
                                break;
                        }
index 7a39d9ab54a77977335e7254b4ffa668d627fd67..bc0dd9db13dd274b5e4aba2aa70c51bc97c45442 100644 (file)
@@ -236,6 +236,11 @@ protected:
         */
        virtual GHOST_TSuccess setWindowCursorVisibility(bool visible);
        
+       /**
+        * Sets the cursor warp accumulator. Overriden for workaround due to Cocoa next event after cursor set giving delta values non zero
+        */
+       inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y);
+       
        /**
         * Sets the cursor grab on the window using
         * native window system calls.
index 1d604553cc1371db92a33ca041a0e4dbb4f2ee2b..205c18e29ba6d12c654bc12ffb1c5d45e2ac4503 100644 (file)
@@ -712,18 +712,33 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
        return GHOST_kSuccess;
 }
 
+
+//Override this method to provide set feature even if not in warp
+inline bool GHOST_WindowCocoa::setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y)
+{
+       m_cursorWarpAccumPos[0]= x;
+       m_cursorWarpAccumPos[1]= y;
+       
+       return GHOST_kSuccess;
+}
+
+
 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool restore)
 {
+       printf("\ncursor grab %i",grab);
        if (grab)
        {
+               //No need to perform grab without warp as it is always on in OS X
                if(warp) {
-                       m_systemCocoa->getCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]);
-                       
-                       setCursorWarpAccum(0, 0);
-                       setWindowCursorVisibility(false);
+                       GHOST_TInt32 x_old,y_old;
+
                        m_cursorWarp= true;
+                       m_systemCocoa->getCursorPosition(x_old,y_old);
+                       screenToClient(x_old, y_old, m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]);
+                       //Warp position is stored in client (window base) coordinates
+                       setWindowCursorVisibility(false);
+                       return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
                }
-               return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
        }
        else {
                if(m_cursorWarp)
@@ -732,34 +747,37 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool
                        /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
                        if(restore) {
                                GHOST_Rect bounds;
-                               GHOST_TInt32 x_new, y_new, x_rel, y_rel;
+                               GHOST_TInt32 x_new, y_new, x_cur, y_cur;
                                
                                getClientBounds(bounds);
-                               printf("\ncursor ungrab with restore");
                                x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0];
                                y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1];
                                
-                               screenToClient(x_new, y_new, x_rel, y_rel);
+                               if(x_new < 0)           x_new = 0;
+                               if(y_new < 0)           y_new = 0;
+                               if(x_new > bounds.getWidth())   x_new = bounds.getWidth();
+                               if(y_new > bounds.getHeight())  y_new = bounds.getHeight();
                                
-                               if(x_rel < 0)           x_new = (x_new-x_rel) + 2;
-                               if(y_rel < 0)           y_new = (y_new-y_rel) + 2;
-                               if(x_rel > bounds.getWidth())   x_new -= (x_rel-bounds.getWidth()) + 2;
-                               if(y_rel > bounds.getHeight())  y_new -= (y_rel-bounds.getHeight()) + 2;
-                               
-                               clientToScreen(x_new, y_new, x_rel, y_rel);
-                               m_systemCocoa->setCursorPosition(x_rel, y_rel);
+                               //get/set cursor position works in screen coordinates
+                               clientToScreen(x_new, y_new, x_cur, y_cur);
+                               m_systemCocoa->setCursorPosition(x_cur, y_cur);
                                
+                               //As Cocoa will give as first deltaX,deltaY this change in cursor position, we need to compensate for it
+                               //Issue appearing in case of two transform operations conducted w/o mouse motion in between
+                               x_new=m_cursorWarpAccumPos[0];
+                               y_new=m_cursorWarpAccumPos[1];
+                               setCursorWarpAccum(-x_new, -y_new);
                        }
                        else {
                                m_systemCocoa->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]);
+                               setCursorWarpAccum(0, 0);
                        }
                        
-                       setCursorWarpAccum(0, 0);
                        m_cursorWarp= false;
+                       return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
                }
-               return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
        }
-       
+       return GHOST_kSuccess;
 }
        
 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)