Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / intern / ghost / intern / GHOST_SystemCocoa.mm
index 1ab0794548ef035d63b67529e68ba076e43bbb59..ffc858d2fc52717eb00b32cf9097be8f4469b9e9 100644 (file)
@@ -1,5 +1,4 @@
-/**
- * $Id$
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -21,9 +20,8 @@
  *
  * The Original Code is: all of this file.
  *
- * Contributor(s):     Maarten Gribnau 05/2001
- *                                     Damien Plisson 09/2009
- *                                     Mike Erwin 06/2010
+ * Contributors: Maarten Gribnau 05/2001
+ *               Damien Plisson 09/2009
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -32,7 +30,6 @@
 
 /*For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible)*/
 #include <Carbon/Carbon.h>
-//#include <HIToolbox/Events.h>
 
 #include <sys/time.h>
 #include <sys/types.h>
 #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"
+#ifdef WITH_INPUT_NDOF
 #include "GHOST_NDOFManagerCocoa.h"
+#endif
+
 #include "AssertMacros.h"
 
 #pragma mark KeyMap, mouse converters
@@ -555,9 +553,6 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
        m_isGestureInProgress = false;
        m_cursorDelta_x=0;
        m_cursorDelta_y=0;
-       m_tablet_mouse_id = TOOL_ID_NONE;
-       m_tablet_pen_id = TOOL_ID_NONE;
-       m_tablet_pen_mode = GHOST_kTabletModeNone;
        m_outsideLoopEventProcessed = false;
        m_needDelayedApplicationBecomeActiveEventProcessing = false;
        m_displayManager = new GHOST_DisplayManagerCocoa ();
@@ -580,16 +575,15 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
        sysctl( mib, 2, rstring, &len, NULL, 0 );
        
        //Hack on MacBook revision, as multitouch avail. function missing
-       m_hasMultiTouchTrackpad =
-               (strstr(rstring,"MacBookAir") ||
-               (strstr(rstring,"MacBook") && (rstring[strlen(rstring)-3]>='5') && (rstring[strlen(rstring)-3]<='9')));
+       if (strstr(rstring,"MacBookAir") ||
+               (strstr(rstring,"MacBook") && (rstring[strlen(rstring)-3]>='5') && (rstring[strlen(rstring)-3]<='9')))
+               m_hasMultiTouchTrackpad = true;
+       else m_hasMultiTouchTrackpad = false;
        
        free( rstring );
        rstring = NULL;
        
        m_ignoreWindowSizedMessages = false;
-       
-       m_input_fidelity_hint = HI_FI; // just for testing...
 }
 
 GHOST_SystemCocoa::~GHOST_SystemCocoa()
@@ -599,10 +593,21 @@ GHOST_SystemCocoa::~GHOST_SystemCocoa()
 
 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
+               /*if (!GetCurrentProcess(&psn)) {
+                       TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+                       SetFrontProcess(&psn);
+               }*/
                
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
                if (NSApp == nil) {
@@ -741,11 +746,13 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
        NSRect contentRect = [NSWindow contentRectForFrameRect:frame
                                                                                                 styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
        
+       GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top;
+
        //Ensures window top left is inside this available rect
        left = left > contentRect.origin.x ? left : contentRect.origin.x;
-       top = top > contentRect.origin.y ? top : contentRect.origin.y;
-       
-       window = new GHOST_WindowCocoa (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples);
+       bottom = bottom > contentRect.origin.y ? bottom : contentRect.origin.y;
+
+       window = new GHOST_WindowCocoa (this, title, left, bottom, width, height, state, type, stereoVisual, numOfAASamples);
 
     if (window) {
         if (window->getValid()) {
@@ -771,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
  */
@@ -809,23 +796,25 @@ GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt3
  */
 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;
 
+       //Cursor and mouse dissociation placed here not to interfere with continuous grab
+       // (in cont. grab setMouseCursorPosition is directly called)
+       CGAssociateMouseAndMouseCursorPosition(false);
        setMouseCursorPosition(x, y);
+       CGAssociateMouseAndMouseCursorPosition(true);
        
        //Force mouse move event (not pushed by Cocoa)
-       window->screenToClient(x, y, wx, wy);
-       pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, wx,wy));
+       pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x, y));
        m_outsideLoopEventProcessed = true;
        
        return GHOST_kSuccess;
 }
 
-GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(float xf, float yf)
+GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
 {
-//     float xf=(float)x, yf=(float)y;
+       float xf=(float)x, yf=(float)y;
        GHOST_WindowCocoa* window = (GHOST_WindowCocoa*)m_windowManager->getActiveWindow();
        if (!window) return GHOST_kFailure;
 
@@ -849,7 +838,7 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(float xf, float yf)
 
 GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) const
 {
-       keys.set(GHOST_kModifierKeyCommand, (m_modifierMask & NSCommandKeyMask) ? true : false);
+       keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSCommandKeyMask) ? true : false);
        keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSAlternateKeyMask) ? true : false);
        keys.set(GHOST_kModifierKeyLeftShift, (m_modifierMask & NSShiftKeyMask) ? true : false);
        keys.set(GHOST_kModifierKeyLeftControl, (m_modifierMask & NSControlKeyMask) ? true : false);
@@ -879,130 +868,115 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
 {
        bool anyProcessed = false;
        NSEvent *event;
-       NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
-
+       
+       //      SetMouseCoalescingEnabled(false, NULL);
        //TODO : implement timer ??
        
-       do {
-               event = [NSApp nextEventMatchingMask:NSAnyEventMask
-                                                                       untilDate:[NSDate distantPast]
-                                                                         inMode:NSDefaultRunLoopMode
-                                                                        dequeue:YES];
-               if (event==nil)
-                       break;
+       /*do {
+               GHOST_TimerManager* timerMgr = getTimerManager();
                
-               anyProcessed = true;
+                if (waitForEvent) {
+                GHOST_TUns64 next = timerMgr->nextFireTime();
+                double timeOut;
+                
+                if (next == GHOST_kFireTimeNever) {
+                timeOut = kEventDurationForever;
+                } else {
+                timeOut = (double)(next - getMilliSeconds())/1000.0;
+                if (timeOut < 0.0)
+                timeOut = 0.0;
+                }
+                
+                ::ReceiveNextEvent(0, NULL, timeOut, false, &event);
+                }
+                
+                if (timerMgr->fireTimers(getMilliSeconds())) {
+                anyProcessed = true;
+                }*/
                
-               switch ([event type]) {
-                       case NSKeyDown:
-                               if ([event isARepeat])
-                                       break;
-                               // else fall through
-                       case NSKeyUp:
-                       case NSFlagsChanged:
-                               handleKeyEvent(event);
-                               // resend to ensure Mac-wide events are handled
-                               [NSApp sendEvent:event];
-                               break;
-                               
-                       case NSLeftMouseDown:
-                       case NSLeftMouseUp:
-                       case NSLeftMouseDragged:
-                       case NSRightMouseDown:
-                       case NSRightMouseUp:
-                       case NSRightMouseDragged:
-                       case NSOtherMouseDown:
-                       case NSOtherMouseUp:
-                       case NSOtherMouseDragged:
-                       case NSMouseMoved:
-                               switch ([event subtype])
-                                       {
-                                       case NSMouseEventSubtype:
-                                               handleMouseEvent(event);
-                                               break;
-                                       case NSTabletPointEventSubtype:
-                                               if ([event deviceID] == m_tablet_mouse_id)
-                                                       handleMouseEvent(event);
-                                               else
-                                                       handleTabletEvent(event);
-                                               break;
-                                       case NSTabletProximityEventSubtype:
-                                               // I think only LMB down/up sends this.
-                                               // Always preceded by a real NSTabletProximity event, so it's redundant.
-                                               // handleTabletProximity(event);
-                                               break;
-
-                                       // Mac OS 10.6 introduces a Touch subtype
-                                       // that we ignore for now.
-                                       }
-                               break;
-
-                       case NSScrollWheel:
-                               handleMouseEvent(event);
-                               break;
-                               
-                       case NSTabletProximity:
-                               handleTabletProximity(event);
-                               break;
-
-                       case NSTabletPoint:
-                               if ([event deviceID] == m_tablet_pen_id)
-                                       handleTabletEvent(event);
-                               else {
-                                       // Treat tablet mouse like any other mouse.
-                                       // TODO: teach Windows and Linux the same trick
-
-                                       // It continues to send events even when still, to mimic the pen's
-                                       // ability to vary pressure without moving. Since the mouse is
-                                       // unable to vary its pressure, filter them out as noise!
-
-                                       bool didMove = [event deltaX] != 0 and [event deltaY] != 0;
-                                       if (didMove)
-                                               handleMouseEvent(event);
-                                       // LMB Down gets sent for the initial point (and LMB Up for the final), so this is safe.
-                               }
-                               break;
-                               
-                       case NSEventTypeMagnify:
-                       case NSEventTypeRotate:
-                       case NSEventTypeBeginGesture:
-                       case NSEventTypeEndGesture:
-                               handleMouseEvent(event);
-                               // break out into handleGestureEvent?
-                               break;
-
-                       /* Trackpad features, fired only from OS X 10.5.2
-                                case NSEventTypeGesture:
-                                case NSEventTypeSwipe:
-                                break; */
-                               
-                       default:
+               do {
+                       NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+                       event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                                                          untilDate:[NSDate distantPast]
+                                                                                 inMode:NSDefaultRunLoopMode
+                                                                                dequeue:YES];
+                       if (event==nil) {
+                               [pool drain];
                                break;
-                       /*      Unused events:
-                               NSMouseEntered       = 8,
-                               NSMouseExited        = 9,
-                               NSAppKitDefined      = 13,
-                               NSSystemDefined      = 14,
-                               NSApplicationDefined = 15,
-                               NSPeriodic           = 16,
-                               NSCursorUpdate       = 17,*/
-               }
-       } while (event != nil);         
-       
-       [pool drain];
+                       }
+                       
+                       anyProcessed = true;
+                       
+                       switch ([event type]) {
+                               case NSKeyDown:
+                               case NSKeyUp:
+                               case NSFlagsChanged:
+                                       handleKeyEvent(event);
+                                       
+                                       /* Support system-wide keyboard shortcuts, like Expos√©, ...) =>included in always NSApp sendEvent */
+                                       /*              if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged) {
+                                        [NSApp sendEvent:event];
+                                        }*/
+                                       break;
+                                       
+                               case NSLeftMouseDown:
+                               case NSLeftMouseUp:
+                               case NSRightMouseDown:
+                               case NSRightMouseUp:
+                               case NSMouseMoved:
+                               case NSLeftMouseDragged:
+                               case NSRightMouseDragged:
+                               case NSScrollWheel:
+                               case NSOtherMouseDown:
+                               case NSOtherMouseUp:
+                               case NSOtherMouseDragged:
+                               case NSEventTypeMagnify:
+                               case NSEventTypeRotate:
+                               case NSEventTypeBeginGesture:
+                               case NSEventTypeEndGesture:
+                                       handleMouseEvent(event);
+                                       break;
+                                       
+                               case NSTabletPoint:
+                               case NSTabletProximity:
+                                       handleTabletEvent(event,[event type]);
+                                       break;
+                                       
+                                       /* Trackpad features, fired only from OS X 10.5.2
+                                        case NSEventTypeGesture:
+                                        case NSEventTypeSwipe:
+                                        break; */
+                                       
+                                       /*Unused events
+                                        NSMouseEntered       = 8,
+                                        NSMouseExited        = 9,
+                                        NSAppKitDefined      = 13,
+                                        NSSystemDefined      = 14,
+                                        NSApplicationDefined = 15,
+                                        NSPeriodic           = 16,
+                                        NSCursorUpdate       = 17,*/
+                                       
+                               default:
+                                       break;
+                       }
+                       //Resend event to NSApp to ensure Mac wide events are handled
+                       [NSApp sendEvent:event];
+                       [pool drain];
+               } while (event!= nil);          
+       //} while (waitForEvent && !anyProcessed); Needed only for timer implementation
        
-       if (m_needDelayedApplicationBecomeActiveEventProcessing)
-               handleApplicationBecomeActiveEvent();
+       if (m_needDelayedApplicationBecomeActiveEventProcessing) handleApplicationBecomeActiveEvent();
        
        if (m_outsideLoopEventProcessed) {
                m_outsideLoopEventProcessed = false;
                return true;
        }
        
+       m_ignoreWindowSizedMessages = false;
+       
     return anyProcessed;
 }
 
-
 //Note: called from NSApplication delegate
 GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
 {
@@ -1029,7 +1003,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
                pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) );
        }
        if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
-               pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) );
+               pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) );
        }
        
        m_modifierMask = modifiers;
@@ -1038,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)
 {
@@ -1067,8 +1046,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
                        case GHOST_kEventWindowSize:
                                if (!m_ignoreWindowSizedMessages)
                                {
+                                       //Enforce only one resize message per event loop (coalescing all the live resize messages)                                      
                                        window->updateDrawingContext();
                                        pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
+                                       //Mouse up event is trapped by the resizing event loop, so send it anyway to the window manager
+                                       pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonUp, window, convertButton(0)));
+                                       m_ignoreWindowSizedMessages = true;
                                }
                                break;
                        default:
@@ -1170,7 +1153,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
                                        NSEnumerator *enumerator;
                                        NSImageRep *representation;
                                        
-                                       ibuf = IMB_allocImBuf (imgSize.width , imgSize.height, 32, IB_rect, 0);
+                                       ibuf = IMB_allocImBuf (imgSize.width , imgSize.height, 32, IB_rect);
                                        if (!ibuf) {
                                                [droppedImg release];
                                                return GHOST_kFailure;
@@ -1312,6 +1295,11 @@ GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest()
                        NSArray *windowsList = [NSApp orderedWindows];
                        if ([windowsList count]) {
                                [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
+                               //Handle the modifiers keyes changed state issue
+                               //as recovering from the quit dialog is like application
+                               //gaining focus back.
+                               //Main issue fixed is Cmd modifier not being cleared
+                               handleApplicationBecomeActiveEvent();
                        }
                }
 
@@ -1358,7 +1346,7 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
 
        if (confirmOpen == NSAlertAlternateReturn)
        {
-               filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding];
+               filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
                
                temp_buff = (char*) malloc(filenameTextSize+1); 
                
@@ -1366,7 +1354,7 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
                        return GHOST_kFailure;
                }
                
-               strncpy(temp_buff, [filepath cStringUsingEncoding:NSISOLatin1StringEncoding], filenameTextSize);
+               strncpy(temp_buff, [filepath cStringUsingEncoding:NSUTF8StringEncoding], filenameTextSize);
                
                temp_buff[filenameTextSize] = '\0';
 
@@ -1377,193 +1365,141 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
        else return NO;
 }
 
-GHOST_TSuccess GHOST_SystemCocoa::handleTabletProximity(void *eventPtr)
+GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventType)
 {
-       printf("tablet prox: ");
        NSEvent *event = (NSEvent *)eventPtr;
-       GHOST_WindowCocoa* window = (GHOST_WindowCocoa*)
-               m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
-
-       if (!window) {
-               printf("\nW failure for event 0x%x",[event type]);
-               return GHOST_kFailure;
-       }
+       GHOST_IWindow* window;
        
-       GHOST_TabletData& ct = window->GetCocoaTabletData();
-
-       GHOST_TTabletMode active_tool;
-       int* tool_id_ptr;
-
-       switch ([event pointingDeviceType])
-               {
-               case NSPenPointingDevice:
-                       printf("pen ");
-                       active_tool = GHOST_kTabletModeStylus;
-                       tool_id_ptr = &m_tablet_pen_id;
-                       break;
-               case NSEraserPointingDevice:
-                       printf("eraser ");
-                       active_tool = GHOST_kTabletModeEraser;
-                       tool_id_ptr = &m_tablet_pen_id;
-                       break;
-               case NSCursorPointingDevice:
-                       printf("cursor ");
-                       active_tool = GHOST_kTabletModeNone;
-                       tool_id_ptr = &m_tablet_mouse_id;
-                       break;
-               default:
-                       printf("<!> unknown device %d\n", [event pointingDeviceType]);
-                       return GHOST_kFailure; // fail on unknown device
-               }
-
-       if ([event isEnteringProximity]) {
-               printf("entering\n");
-               *tool_id_ptr = [event deviceID];
-
-               ct.Active = active_tool;
-               ct.Pressure = (active_tool == GHOST_kTabletModeNone) ? /*mouse*/ 1 : /*pen*/ 0;
-               ct.Xtilt = 0;
-               ct.Ytilt = 0;
-
-               // this is a good place to remember the tool's capabilities
-               // (later though, after tablet mouse is fixed and (not) coalescing is in place)
-               }
-       else {
-               printf("leaving\n");
-               *tool_id_ptr = TOOL_ID_NONE;
-
-               ct.Active = GHOST_kTabletModeNone;
-               ct.Pressure = 0;
-               ct.Xtilt = 0;
-               ct.Ytilt = 0;
-               }
-
-       return GHOST_kSuccess;
-}
-
-GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
-{
-       puts("tablet point");
-       NSEvent *event = (NSEvent*)eventPtr;
-       GHOST_WindowCocoa* window = (GHOST_WindowCocoa*)
-               m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
-
+       window = m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
        if (!window) {
                //printf("\nW failure for event 0x%x",[event type]);
                return GHOST_kFailure;
        }
-
-       GHOST_TabletData& ct = window->GetCocoaTabletData();
        
-       ct.Pressure = [event pressure];
-       NSPoint tilt = [event tilt];
-       ct.Xtilt = tilt.x;
-       ct.Ytilt = tilt.y;
-
-       switch ([event type])
-               {
-               case NSLeftMouseDown:
-                       if (m_input_fidelity_hint == HI_FI)
-                               {
-                               printf("hi-fi on\n");
-                               [NSEvent setMouseCoalescingEnabled:NO];
-                               }
-                       pushEvent(new GHOST_EventButton([event timestamp]*1000, GHOST_kEventButtonDown, window, convertButton([event buttonNumber])));
+       GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
+       
+       switch (eventType) {
+               case NSTabletPoint:
+                       ct.Pressure = [event pressure];
+                       ct.Xtilt = [event tilt].x;
+                       ct.Ytilt = [event tilt].y;
                        break;
-               case NSLeftMouseUp:
-                       if (m_input_fidelity_hint == HI_FI)
-                               {
-                               printf("hi-fi off\n");
-                               [NSEvent setMouseCoalescingEnabled:YES];
+               
+               case NSTabletProximity:
+                       ct.Pressure = 0;
+                       ct.Xtilt = 0;
+                       ct.Ytilt = 0;
+                       if ([event isEnteringProximity])
+                       {
+                               //pointer is entering tablet area proximity
+                               switch ([event pointingDeviceType]) {
+                                       case NSPenPointingDevice:
+                                               ct.Active = GHOST_kTabletModeStylus;
+                                               break;
+                                       case NSEraserPointingDevice:
+                                               ct.Active = GHOST_kTabletModeEraser;
+                                               break;
+                                       case NSCursorPointingDevice:
+                                       case NSUnknownPointingDevice:
+                                       default:
+                                               ct.Active = GHOST_kTabletModeNone;
+                                               break;
                                }
-                       pushEvent(new GHOST_EventButton([event timestamp]*1000, GHOST_kEventButtonUp, window, convertButton([event buttonNumber])));
+                       } else {
+                               // pointer is leaving - return to mouse
+                               ct.Active = GHOST_kTabletModeNone;
+                       }
                        break;
+               
                default:
-                       {
-                       NSPoint pos = [event locationInWindow];
-                       pushEvent(new GHOST_EventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, pos.x, pos.y));
+                       GHOST_ASSERT(FALSE,"GHOST_SystemCocoa::handleTabletEvent : unknown event received");
+                       return GHOST_kFailure;
                        break;
-                       }
-               }
-
+       }
        return GHOST_kSuccess;
 }
 
 
 GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 {
-       printf("mouse ");
        NSEvent *event = (NSEvent *)eventPtr;
-       GHOST_Window* window =
-               (GHOST_Window*)m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
-
+    GHOST_WindowCocoa* window;
+       
+       window = (GHOST_WindowCocoa*)m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
        if (!window) {
-               printf("\nW failure for event 0x%x",[event type]);
+               //printf("\nW failure for event 0x%x",[event type]);
                return GHOST_kFailure;
        }
-
-       static float warp_dx = 0, warp_dy = 0; // need to reset these. e.g. each grab operation should get its own.
-               // ^^ not currently useful, try m_cursorDelta_* instead.
-
+       
        switch ([event type])
     {
                case NSLeftMouseDown:
                case NSRightMouseDown:
                case NSOtherMouseDown:
-                       printf("button down\n");
-                       if (m_input_fidelity_hint == HI_FI)
-                               {
-                               printf("hi-fi on\n");
-                               [NSEvent setMouseCoalescingEnabled:NO];
-                               }
                        pushEvent(new GHOST_EventButton([event timestamp]*1000, GHOST_kEventButtonDown, window, convertButton([event buttonNumber])));
+                       //Handle tablet events combined with mouse events
+                       switch ([event subtype]) {
+                               case NX_SUBTYPE_TABLET_POINT:
+                                       handleTabletEvent(eventPtr, NSTabletPoint);
+                                       break;
+                               case NX_SUBTYPE_TABLET_PROXIMITY:
+                                       handleTabletEvent(eventPtr, NSTabletProximity);
+                                       break;
+                               default:
+                                       //No tablet event included : do nothing
+                                       break;
+                       }
                        break;
                                                
                case NSLeftMouseUp:
                case NSRightMouseUp:
                case NSOtherMouseUp:
-                       printf("button up\n");
-                       if (m_input_fidelity_hint == HI_FI)
-                               {
-                               printf("hi-fi off\n");
-                               [NSEvent setMouseCoalescingEnabled:YES];
-                               }
                        pushEvent(new GHOST_EventButton([event timestamp]*1000, GHOST_kEventButtonUp, window, convertButton([event buttonNumber])));
-                       // cheap hack, should reset when grab ends.
-                       warp_dx = warp_dy = 0;
+                       //Handle tablet events combined with mouse events
+                       switch ([event subtype]) {
+                               case NX_SUBTYPE_TABLET_POINT:
+                                       handleTabletEvent(eventPtr, NSTabletPoint);
+                                       break;
+                               case NX_SUBTYPE_TABLET_PROXIMITY:
+                                       handleTabletEvent(eventPtr, NSTabletProximity);
+                                       break;
+                               default:
+                                       //No tablet event included : do nothing
+                                       break;
+                       }
                        break;
                        
                case NSLeftMouseDragged:
                case NSRightMouseDragged:
-               case NSOtherMouseDragged:
+               case NSOtherMouseDragged:                               
+                       //Handle tablet events combined with mouse events
+                       switch ([event subtype]) {
+                               case NX_SUBTYPE_TABLET_POINT:
+                                       handleTabletEvent(eventPtr, NSTabletPoint);
+                                       break;
+                               case NX_SUBTYPE_TABLET_PROXIMITY:
+                                       handleTabletEvent(eventPtr, NSTabletProximity);
+                                       break;
+                               default:
+                                       //No tablet event included : do nothing
+                                       break;
+                       }
+                       
                case NSMouseMoved:
-                       {
-                       NSPoint mousePos = [event locationInWindow];
-                       float event_dx = [event deltaX];
-                       float event_dy = [event deltaY];
-
-                       bool coalesced = [NSEvent isMouseCoalescingEnabled];
-                       if (not coalesced)
-                               printf("[hi-fi] ");
-                       printf("move <%.2f,%.2f> to (%.2f,%.2f)\n", event_dx, event_dy, mousePos.x, mousePos.y);
-
-                       event_dy = -event_dy; //Strange Apple implementation (inverted coordinates for the deltaY) ...
-
-
                                switch (window->getCursorGrabMode()) {
                                        case GHOST_kGrabHide: //Cursor hidden grab operation : no cursor move
                                        {
-                                               printf(" - grab hide\n");
-                                               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);
                                                
                                                window->getCursorGrabAccum(x_accum, y_accum);
-                                               x_accum += event_dx;
-                                               y_accum += event_dy;
+                                               x_accum += [event deltaX];
+                                               y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ...
                                                window->setCursorGrabAccum(x_accum, y_accum);
                                                
-                                               pushEvent(new GHOST_EventCursor([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
@@ -1571,7 +1507,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                                NSPoint mousePos = [event locationInWindow];
                                                GHOST_TInt32 x_mouse= mousePos.x;
                                                GHOST_TInt32 y_mouse= mousePos.y;
-                                               GHOST_TInt32 x_accum, y_accum, x_cur, y_cur;
+                                               GHOST_TInt32 x_accum, y_accum, x_cur, y_cur, x, y;
                                                GHOST_Rect bounds, windowBounds, correctedBounds;
                                                
                                                /* fallback to window bounds */
@@ -1580,21 +1516,21 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                                                
                                                //Switch back to Cocoa coordinates orientation (y=0 at botton,the same as blender internal btw!), and to client coordinates
                                                window->getClientBounds(windowBounds);
-                                               window->screenToClient(bounds.m_l,bounds.m_b, correctedBounds.m_l, correctedBounds.m_t);
+                                               window->screenToClient(bounds.m_l, bounds.m_b, correctedBounds.m_l, correctedBounds.m_t);
                                                window->screenToClient(bounds.m_r, bounds.m_t, correctedBounds.m_r, correctedBounds.m_b);
                                                correctedBounds.m_b = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_b;
                                                correctedBounds.m_t = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_t;
                                                
                                                //Update accumulation counts
                                                window->getCursorGrabAccum(x_accum, y_accum);
-                                               x_accum += event_dx - m_cursorDelta_x;
-                                               y_accum += event_dy - m_cursorDelta_y;
+                                               x_accum += [event deltaX]-m_cursorDelta_x;
+                                               y_accum += -[event deltaY]-m_cursorDelta_y; //Strange Apple implementation (inverted coordinates for the deltaY) ...
                                                window->setCursorGrabAccum(x_accum, y_accum);
                                                
                                                
                                                //Warp mouse cursor if needed
-                                               x_mouse += event_dx - m_cursorDelta_x;
-                                               y_mouse += event_dy - m_cursorDelta_y;
+                                               x_mouse += [event deltaX]-m_cursorDelta_x;
+                                               y_mouse += -[event deltaY]-m_cursorDelta_y;
                                                correctedBounds.wrapPoint(x_mouse, y_mouse, 2);
                                                
                                                //Compensate for mouse moved event taking cursor position set into account
@@ -1602,34 +1538,48 @@ 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);
-                                               pushEvent(new GHOST_EventCursor([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
-                                               pushEvent(new GHOST_EventCursor([event timestamp]*1000, GHOST_kEventCursorMove, window, mousePos.x, mousePos.y));
-                                               m_cursorDelta_x=0;
-                                               m_cursorDelta_y=0; //Mouse motion occured between two cursor warps, so we can reset the delta counter
+                                               NSPoint mousePos = [event locationInWindow];
+                                               GHOST_TInt32 x, y;
 
-                                               warp_dx = 0;
-                                               warp_dy = 0;
+                                               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
                                        }
                                                break;
                                }
                                break;
-                       }
-
+                       
                case NSScrollWheel:
                        {
                                /* Send trackpad event if inside a trackpad gesture, send wheel event otherwise */
-                               if (m_hasMultiTouchTrackpad and m_isGestureInProgress) {
+                               if (!m_hasMultiTouchTrackpad || !m_isGestureInProgress) {
+                                       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;
+                                       pushEvent(new GHOST_EventWheel([event timestamp]*1000, window, delta));
+                               }
+                               else {
                                        NSPoint mousePos = [event locationInWindow];
+                                       GHOST_TInt32 x, y;
                                        double dx = [event deltaX];
                                        double dy = -[event deltaY];
                                        
@@ -1646,16 +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;
 
-                                       pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventScroll, mousePos.x, mousePos.y, dx, dy));
-                               }
-                               else {
-                                       GHOST_TInt32 delta;
-                                       
-                                       double deltaF = [event deltaY];
-                                       if (deltaF == 0.0) break; //discard trackpad delta=0 events
-                                       
-                                       delta = deltaF > 0.0 ? 1 : -1;
-                                       pushEvent(new GHOST_EventWheel([event timestamp]*1000, window, delta));
+                                       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;
@@ -1663,14 +1607,20 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                case NSEventTypeMagnify:
                        {
                                NSPoint mousePos = [event locationInWindow];
-                               pushEvent(new GHOST_EventTrackpad([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];
-                               pushEvent(new GHOST_EventTrackpad([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;
@@ -1679,8 +1629,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                        m_isGestureInProgress = false;
                        break;
                default:
-                       printf("<!> unknown event type %d\n", [event type]);
                        return GHOST_kFailure;
+                       break;
                }
        
        return GHOST_kSuccess;
@@ -1703,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];
@@ -1716,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;
        
@@ -1754,7 +1710,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
                                pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) );
                        }
                        if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
-                               pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) );
+                               pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) );
                        }
                        
                        m_modifierMask = modifiers;
@@ -1852,60 +1808,3 @@ void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
        [pool drain];
 }
 
-#pragma mark Base directories retrieval
-
-const GHOST_TUns8* GHOST_SystemCocoa::getSystemDir() const
-{
-       static GHOST_TUns8 tempPath[512] = "";
-       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-       NSFileManager *fileManager;
-       NSString *basePath;
-       NSArray *paths;
-       
-       paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSLocalDomainMask, YES);
-       
-       if ([paths count] > 0)
-               basePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Blender"];
-       else { //Fall back to standard unix path in case of issue
-               basePath = @"/usr/share/blender";
-       }
-       
-       /* Ensure path exists, creates it if needed */
-       fileManager = [NSFileManager defaultManager];
-       if (![fileManager fileExistsAtPath:basePath isDirectory:NULL]) {
-               [fileManager createDirectoryAtPath:basePath attributes:nil];
-       }
-       
-       strcpy((char*)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding]);
-       
-       [pool drain];
-       return tempPath;
-}
-
-const GHOST_TUns8* GHOST_SystemCocoa::getUserDir() const
-{
-       static GHOST_TUns8 tempPath[512] = "";
-       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-       NSFileManager *fileManager;
-       NSString *basePath;
-       NSArray *paths;
-
-       paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
-
-       if ([paths count] > 0)
-               basePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Blender"];
-       else { //Fall back to HOME in case of issue
-               basePath = [NSHomeDirectory() stringByAppendingPathComponent:@".blender"];
-       }
-       
-       /* Ensure path exists, creates it if needed */
-       fileManager = [NSFileManager defaultManager];
-       if (![fileManager fileExistsAtPath:basePath isDirectory:NULL]) {
-               [fileManager createDirectoryAtPath:basePath attributes:nil];
-       }
-       
-       strcpy((char*)tempPath, [basePath cStringUsingEncoding:NSASCIIStringEncoding]);
-       
-       [pool drain];
-       return tempPath;
-}