Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / intern / ghost / intern / GHOST_SystemCocoa.mm
index efd79cc17e63680714df45da00ba2af597716ca9..ffc858d2fc52717eb00b32cf9097be8f4469b9e9 100644 (file)
@@ -1,5 +1,4 @@
-/**
- * $Id$
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -21,8 +20,8 @@
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s):     Maarten Gribnau 05/2001
- *                                     Damien Plisson 09/2009
+ * Contributors: Maarten Gribnau 05/2001
+ *               Damien Plisson 09/2009
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 #include "GHOST_EventButton.h"
 #include "GHOST_EventCursor.h"
 #include "GHOST_EventWheel.h"
-#include "GHOST_EventNDOF.h"
 #include "GHOST_EventTrackpad.h"
 #include "GHOST_EventDragnDrop.h"
 #include "GHOST_EventString.h"
-
 #include "GHOST_TimerManager.h"
 #include "GHOST_TimerTask.h"
 #include "GHOST_WindowManager.h"
 #include "GHOST_WindowCocoa.h"
-#include "GHOST_NDOFManager.h"
+#ifdef WITH_INPUT_NDOF
+#include "GHOST_NDOFManagerCocoa.h"
+#endif
+
 #include "AssertMacros.h"
 
 #pragma mark KeyMap, mouse converters
@@ -596,6 +596,11 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
        
     GHOST_TSuccess success = GHOST_System::init();
     if (success) {
+
+#ifdef WITH_INPUT_NDOF
+               m_ndofManager = new GHOST_NDOFManagerCocoa(*this);
+#endif
+
                //ProcessSerialNumber psn;
                
                //Carbon stuff to move window & menu to foreground
@@ -773,26 +778,6 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
     return window;
 }
 
-GHOST_TSuccess GHOST_SystemCocoa::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual)
-{      
-       GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow();
-       *window = currentWindow;
-       
-       if(!currentWindow) return GHOST_kFailure;
-       
-       return currentWindow->setState(GHOST_kWindowStateFullScreen);
-}
-
-GHOST_TSuccess GHOST_SystemCocoa::endFullScreen(void)
-{      
-       GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow();
-       if(!currentWindow) return GHOST_kFailure;
-       
-       return currentWindow->setState(GHOST_kWindowStateNormal);
-}
-
-
-       
 /**
  * @note : returns coordinates in Cocoa screen coordinates
  */
@@ -806,37 +791,11 @@ GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt3
     return GHOST_kSuccess;
 }
 
-void GHOST_SystemCocoa::pushEventCursor(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window, GHOST_TInt32 x, GHOST_TInt32 y)
-{
-       GHOST_Rect cBnds;
-       window->getClientBounds(cBnds);
-       y = (cBnds.getHeight() - 1) - y;
-
-       GHOST_TInt32 screen_x, screen_y;
-       window->clientToScreen(x, y, screen_x, screen_y);
-
-       pushEvent(new GHOST_EventCursor(msec, type, window, screen_x, screen_y));
-}
-
-void GHOST_SystemCocoa::pushEventTrackpad(GHOST_TUns64 msec, GHOST_IWindow* window, GHOST_TTrackpadEventSubTypes subtype, GHOST_TInt32 x, GHOST_TInt32 y, GHOST_TInt32 deltaX, GHOST_TInt32 deltaY)
-{
-       GHOST_Rect cBnds;
-       window->getClientBounds(cBnds);
-       y = (cBnds.getHeight() - 1) - y;
-       deltaY = -deltaY;
-
-       GHOST_TInt32 screen_x, screen_y;
-       window->clientToScreen(x, y, screen_x, screen_y);
-
-       pushEvent(new GHOST_EventTrackpad(msec, window, subtype, screen_x, screen_y, deltaX, deltaY));
-}
-
 /**
  * @note : expect Cocoa screen coordinates
  */
 GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
 {
-       GHOST_TInt32 wx,wy;
        GHOST_WindowCocoa* window = (GHOST_WindowCocoa*)m_windowManager->getActiveWindow();
        if (!window) return GHOST_kFailure;
 
@@ -847,8 +806,7 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32
        CGAssociateMouseAndMouseCursorPosition(true);
        
        //Force mouse move event (not pushed by Cocoa)
-       window->screenToClient(x, y, wx, wy);
-       pushEventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, wx,wy);
+       pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x, y));
        m_outsideLoopEventProcessed = true;
        
        return GHOST_kSuccess;
@@ -1054,6 +1012,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
        return GHOST_kSuccess;
 }
 
+void GHOST_SystemCocoa::notifyExternalEventProcessed()
+{
+       m_outsideLoopEventProcessed = true;
+}
+
 //Note: called from NSWindow delegate
 GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window)
 {
@@ -1460,9 +1423,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
 GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 {
        NSEvent *event = (NSEvent *)eventPtr;
-    GHOST_Window* window;
+    GHOST_WindowCocoa* window;
        
-       window = (GHOST_Window*)m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
+       window = (GHOST_WindowCocoa*)m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
        if (!window) {
                //printf("\nW failure for event 0x%x",[event type]);
                return GHOST_kFailure;
@@ -1526,7 +1489,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                switch (window->getCursorGrabMode()) {
                                        case GHOST_kGrabHide: //Cursor hidden grab operation : no cursor move
                                        {
-                                               GHOST_TInt32 x_warp, y_warp, x_accum, y_accum;
+                                               GHOST_TInt32 x_warp, y_warp, x_accum, y_accum, x, y;
                                                
                                                window->getCursorGrabInitPos(x_warp, y_warp);
                                                
@@ -1535,7 +1498,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                                y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ...
                                                window->setCursorGrabAccum(x_accum, y_accum);
                                                
-                                               pushEventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum);
+                                               window->clientToScreenIntern(x_warp+x_accum, y_warp+y_accum, x, y);
+                                               pushEvent(new GHOST_EventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, x, y));
                                        }
                                                break;
                                        case GHOST_kGrabWrap: //Wrap cursor at area/window boundaries
@@ -1574,19 +1538,24 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                                m_cursorDelta_y = y_mouse-mousePos.y;
                                                
                                                //Set new cursor position
-                                               window->clientToScreen(x_mouse, y_mouse, x_cur, y_cur);
+                                               window->clientToScreenIntern(x_mouse, y_mouse, x_cur, y_cur);
                                                setMouseCursorPosition(x_cur, y_cur); /* wrap */
                                                
                                                //Post event
                                                window->getCursorGrabInitPos(x_cur, y_cur);
-                                               pushEventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, x_cur + x_accum, y_cur + y_accum);
+                                               window->clientToScreenIntern(x_cur + x_accum, y_cur + y_accum, x, y);
+                                               pushEvent(new GHOST_EventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, x, y));
                                        }
                                                break;
                                        default:
                                        {
                                                //Normal cursor operation: send mouse position in window
                                                NSPoint mousePos = [event locationInWindow];
-                                               pushEventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, mousePos.x, mousePos.y);
+                                               GHOST_TInt32 x, y;
+
+                                               window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
+                                               pushEvent(new GHOST_EventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, x, y));
+
                                                m_cursorDelta_x=0;
                                                m_cursorDelta_y=0; //Mouse motion occurred between two cursor warps, so we can reset the delta counter
                                        }
@@ -1601,6 +1570,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                        GHOST_TInt32 delta;
                                        
                                        double deltaF = [event deltaY];
+
+                                       if (deltaF == 0.0) deltaF = [event deltaX]; // make blender decide if it's horizontal scroll
                                        if (deltaF == 0.0) break; //discard trackpad delta=0 events
                                        
                                        delta = deltaF > 0.0 ? 1 : -1;
@@ -1608,6 +1579,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                }
                                else {
                                        NSPoint mousePos = [event locationInWindow];
+                                       GHOST_TInt32 x, y;
                                        double dx = [event deltaX];
                                        double dy = -[event deltaY];
                                        
@@ -1624,7 +1596,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                        if (dy<0.0) dy-=0.5; else dy+=0.5;
                                        if (dy< -deltaMax) dy= -deltaMax; else if (dy>deltaMax) dy=deltaMax;
 
-                                       pushEventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventScroll, mousePos.x, mousePos.y, dx, dy);
+                                       window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
+                                       dy = -dy;
+
+                                       pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventScroll, x, y, dx, dy));
                                }
                        }
                        break;
@@ -1632,16 +1607,20 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                case NSEventTypeMagnify:
                        {
                                NSPoint mousePos = [event locationInWindow];
-                               pushEventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventMagnify, mousePos.x, mousePos.y,
-                                                                                                 [event magnification]*250.0 + 0.1, 0);
+                               GHOST_TInt32 x, y;
+                               window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
+                               pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventMagnify, x, y,
+                                                                                                 [event magnification]*250.0 + 0.1, 0));
                        }
                        break;
 
                case NSEventTypeRotate:
                        {
                                NSPoint mousePos = [event locationInWindow];
-                               pushEventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventRotate, mousePos.x, mousePos.y,
-                                                                                                 -[event rotation] * 5.0, 0);
+                               GHOST_TInt32 x, y;
+                               window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
+                               pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventRotate, x, y,
+                                                                                                 -[event rotation] * 5.0, 0));
                        }
                case NSEventTypeBeginGesture:
                        m_isGestureInProgress = true;
@@ -1674,8 +1653,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
                //printf("\nW failure for event 0x%x",[event type]);
                return GHOST_kFailure;
        }
+
+       char utf8_buf[6]= {'\0'};
+       ascii = 0;
        
        switch ([event type]) {
+
                case NSKeyDown:
                case NSKeyUp:
                        charsIgnoringModifiers = [event charactersIgnoringModifiers];
@@ -1687,28 +1670,30 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
                                keyCode = convertKey([event keyCode],0,
                                                                         [event type] == NSKeyDown?kUCKeyActionDown:kUCKeyActionUp);
 
-                               
+                       /* handling both unicode or ascii */
                        characters = [event characters];
-                       if ([characters length]>0) { //Check for dead keys
-                               //Convert characters to iso latin 1 encoding
-                               convertedCharacters = [characters dataUsingEncoding:NSISOLatin1StringEncoding];
-                               if ([convertedCharacters length]>0)
-                                       ascii =((char*)[convertedCharacters bytes])[0];
-                               else
-                                       ascii = 0; //Character not available in iso latin 1 encoding
+                       if ([characters length]>0) {
+                               convertedCharacters = [characters dataUsingEncoding:NSUTF8StringEncoding];
+                               
+                               for (int x = 0; x < [convertedCharacters length]; x++) {
+                                       utf8_buf[x] = ((char*)[convertedCharacters bytes])[x];
+                               }
+
+                               /* ascii is a subset of unicode */
+                               if ([convertedCharacters length] == 1) {
+                                       ascii = utf8_buf[0];
+                               }
                        }
-                       else
-                               ascii= 0;
-                       
+
                        if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask))
                                break; //Cmd-Q is directly handled by Cocoa
 
                        if ([event type] == NSKeyDown) {
-                               pushEvent( new GHOST_EventKey([event timestamp]*1000, GHOST_kEventKeyDown, window, keyCode, ascii) );
-                               //printf("\nKey down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii);
+                               pushEvent( new GHOST_EventKey([event timestamp]*1000, GHOST_kEventKeyDown, window, keyCode, ascii, utf8_buf) );
+                               //printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii, utf8_buf);
                        } else {
-                               pushEvent( new GHOST_EventKey([event timestamp]*1000, GHOST_kEventKeyUp, window, keyCode, ascii) );
-                               //printf("\nKey up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii);
+                               pushEvent( new GHOST_EventKey([event timestamp]*1000, GHOST_kEventKeyUp, window, keyCode, 0, '\0') );
+                               //printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii, utf8_buf);
                        }
                        break;