Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / intern / ghost / intern / GHOST_SystemCocoa.mm
index d8bb903dbe75380bc49c66b41cfb5433d3453c6a..ffc858d2fc52717eb00b32cf9097be8f4469b9e9 100644 (file)
@@ -1,5 +1,4 @@
-/**
- * $Id$
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  *
  * 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 *****
  */
 
 #import <Cocoa/Cocoa.h>
 
+/*For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible)*/
+#include <Carbon/Carbon.h>
+
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/sysctl.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"
-#include "GHOST_NDOFManager.h"
+#ifdef WITH_INPUT_NDOF
+#include "GHOST_NDOFManagerCocoa.h"
+#endif
+
 #include "AssertMacros.h"
 
 #pragma mark KeyMap, mouse converters
-
-
-/* Keycodes from Carbon include file */
+#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
+/* Keycodes not defined in Tiger */
 /*  
  *  Summary:
  *    Virtual keycodes
@@ -202,7 +205,7 @@ enum {
        kVK_JIS_Eisu                  = 0x66,
        kVK_JIS_Kana                  = 0x68
 };
-
+#endif
 
 static GHOST_TButtonMask convertButton(int button)
 {
@@ -229,7 +232,7 @@ static GHOST_TButtonMask convertButton(int button)
  * @param recvChar the character ignoring modifiers (except for shift)
  * @return Ghost key code
  */
-static GHOST_TKey convertKey(int rawCode, unichar recvChar) 
+static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction
 {      
        
        //printf("\nrecvchar %c 0x%x",recvChar,recvChar);
@@ -349,26 +352,68 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar)
                        return GHOST_kKeyUnknown;
                        
                default:
-                       /*Then detect on character value for "remappable" keys in int'l keyboards*/
+                       /* alphanumerical or punctuation key that is remappable in int'l keyboards */
                        if ((recvChar >= 'A') && (recvChar <= 'Z')) {
                                return (GHOST_TKey) (recvChar - 'A' + GHOST_kKeyA);
                        } else if ((recvChar >= 'a') && (recvChar <= 'z')) {
                                return (GHOST_TKey) (recvChar - 'a' + GHOST_kKeyA);
-                       } else
-                       switch (recvChar) {
-                               case '-':       return GHOST_kKeyMinus;
-                               case '=':       return GHOST_kKeyEqual;
-                               case ',':       return GHOST_kKeyComma;
-                               case '.':       return GHOST_kKeyPeriod;
-                               case '/':       return GHOST_kKeySlash;
-                               case ';':       return GHOST_kKeySemicolon;
-                               case '\'':      return GHOST_kKeyQuote;
-                               case '\\':      return GHOST_kKeyBackslash;
-                               case '[':       return GHOST_kKeyLeftBracket;
-                               case ']':       return GHOST_kKeyRightBracket;
-                               case '`':       return GHOST_kKeyAccentGrave;
-                               default:
-                                       return GHOST_kKeyUnknown;
+                       } else {
+#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
+                               KeyboardLayoutRef keyLayout;
+                               UCKeyboardLayout *uchrData;
+                               
+                               KLGetCurrentKeyboardLayout(&keyLayout);
+                               KLGetKeyboardLayoutProperty(keyLayout, kKLuchrData, (const void **)
+                                                                                       &uchrData);
+                               /*get actual character value of the "remappable" keys in int'l keyboards,
+                                if keyboard layout is not correctly reported (e.g. some non Apple keyboards in Tiger),
+                                then fallback on using the received charactersIgnoringModifiers */
+                               if (uchrData)
+                               {
+                                       UInt32 deadKeyState=0;
+                                       UniCharCount actualStrLength=0;
+                                       
+                                       UCKeyTranslate(uchrData, rawCode, keyAction, 0,
+                                                                  LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 1, &actualStrLength, &recvChar);
+                                       
+                               }                               
+#else
+                               /* Leopard and Snow Leopard 64bit compatible API*/
+                               CFDataRef uchrHandle; /*the keyboard layout*/
+                               TISInputSourceRef kbdTISHandle;
+                               
+                               kbdTISHandle = TISCopyCurrentKeyboardLayoutInputSource();
+                               uchrHandle = (CFDataRef)TISGetInputSourceProperty(kbdTISHandle,kTISPropertyUnicodeKeyLayoutData);
+                               CFRelease(kbdTISHandle);
+                               
+                               /*get actual character value of the "remappable" keys in int'l keyboards,
+                                if keyboard layout is not correctly reported (e.g. some non Apple keyboards in Tiger),
+                                then fallback on using the received charactersIgnoringModifiers */
+                               if (uchrHandle)
+                               {
+                                       UInt32 deadKeyState=0;
+                                       UniCharCount actualStrLength=0;
+                                       
+                                       UCKeyTranslate((UCKeyboardLayout*)CFDataGetBytePtr(uchrHandle), rawCode, keyAction, 0,
+                                                                  LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &deadKeyState, 1, &actualStrLength, &recvChar);
+                                       
+                               }
+#endif
+                               switch (recvChar) {
+                                       case '-':       return GHOST_kKeyMinus;
+                                       case '=':       return GHOST_kKeyEqual;
+                                       case ',':       return GHOST_kKeyComma;
+                                       case '.':       return GHOST_kKeyPeriod;
+                                       case '/':       return GHOST_kKeySlash;
+                                       case ';':       return GHOST_kKeySemicolon;
+                                       case '\'':      return GHOST_kKeyQuote;
+                                       case '\\':      return GHOST_kKeyBackslash;
+                                       case '[':       return GHOST_kKeyLeftBracket;
+                                       case ']':       return GHOST_kKeyRightBracket;
+                                       case '`':       return GHOST_kKeyAccentGrave;
+                                       default:
+                                               return GHOST_kKeyUnknown;
+                               }
                        }
        }
        return GHOST_kKeyUnknown;
@@ -396,17 +441,6 @@ enum {
 #endif
 @end 
 
-@interface NSEvent(SnowLeopardEvents)
-/* modifier keys currently down.  This returns the state of devices combined
- with synthesized events at the moment, independent of which events
- have been delivered via the event stream. */
-#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
-+ (unsigned int)modifierFlags; //NSUInteger is defined only from 10.5
-#else
-+ (NSUInteger)modifierFlags;
-#endif
-@end
-
 #endif
 
 
@@ -562,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
@@ -707,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()) {
@@ -737,24 +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;
-       
-       return currentWindow->setState(GHOST_kWindowStateFullScreen);
-}
-
-GHOST_TSuccess GHOST_SystemCocoa::endFullScreen(void)
-{      
-       GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow();
-       
-       return currentWindow->setState(GHOST_kWindowStateNormal);
-}
-
-
-       
 /**
  * @note : returns coordinates in Cocoa screen coordinates
  */
@@ -771,10 +794,31 @@ GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt3
 /**
  * @note : expect Cocoa screen coordinates
  */
-GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
+GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
+{
+       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)
+       pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x, y));
+       m_outsideLoopEventProcessed = true;
+       
+       return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
 {
        float xf=(float)x, yf=(float)y;
        GHOST_WindowCocoa* window = (GHOST_WindowCocoa*)m_windowManager->getActiveWindow();
+       if (!window) return GHOST_kFailure;
+
+       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSScreen *windowScreen = window->getScreen();
        NSRect screenRect = [windowScreen frame];
        
@@ -787,13 +831,14 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32
 
        CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue], CGPointMake(xf, yf));
 
+       [pool drain];
     return GHOST_kSuccess;
 }
 
 
 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);
@@ -927,6 +972,8 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
                return true;
        }
        
+       m_ignoreWindowSizedMessages = false;
+       
     return anyProcessed;
 }
 
@@ -944,21 +991,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
        }
        else m_needDelayedApplicationBecomeActiveEventProcessing = false;
 
-#ifdef MAC_OS_X_VERSION_10_6
-       modifiers = [NSEvent modifierFlags];
-#else
-       //If build against an older SDK, check if running on 10.6 to use the correct function
-       if ([NSEvent respondsToSelector:@selector(modifierFlags)]) {
-               modifiers = [NSEvent modifierFlags];
-       }
-       else {
-               //TODO: need to find a better workaround for the missing cocoa "getModifierFlag" function in 10.4/10.5
-               modifiers = 0;
-       }
-#endif
-       
-       /* Discard erroneous 10.6 modifiers values reported when switching back from spaces */
-       if ((modifiers & NSDeviceIndependentModifierFlagsMask) == 0xb00000) modifiers = 0;
+       modifiers = [[[NSApplication sharedApplication] currentEvent] modifierFlags];
        
        if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
                pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) );
@@ -970,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;
@@ -979,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)
 {
@@ -1002,11 +1040,18 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
                        case GHOST_kEventWindowUpdate:
                                pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
                                break;
+                       case GHOST_kEventWindowMove:
+                               pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, window) );
+                               break;
                        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:
@@ -1022,7 +1067,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
 GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType,
                                                                   GHOST_WindowCocoa* window, int mouseX, int mouseY, void* data)
 {
-       if (!validWindow(window) && (eventType != GHOST_kEventDraggingDropOnIcon)) {
+       if (!validWindow(window)) {
                return GHOST_kFailure;
        }
        switch(eventType) 
@@ -1034,7 +1079,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
                        break;
                        
                case GHOST_kEventDraggingDropDone:
-               case GHOST_kEventDraggingDropOnIcon:
                {
                        GHOST_TUns8 * temp_buff;
                        GHOST_TStringArray *strArray;
@@ -1047,10 +1091,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
                        if (!data) return GHOST_kFailure;
                        
                        switch (draggedObjectType) {
-                               case GHOST_kDragnDropTypeBitmap:
-                                       //TODO: implement bitmap conversion to a blender friendly format
-                                       return GHOST_kFailure;
-                                       break;
                                case GHOST_kDragnDropTypeFilenames:
                                        droppedArray = (NSArray*)data;
                                        
@@ -1066,7 +1106,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
                                        {
                                                droppedStr = [droppedArray objectAtIndex:i];
                                                
-                                               pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding];
+                                               pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
                                                temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); 
                                        
                                                if (!temp_buff) {
@@ -1074,7 +1114,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
                                                        break;
                                                }
                                        
-                                               strncpy((char*)temp_buff, [droppedStr cStringUsingEncoding:NSISOLatin1StringEncoding], pastedTextSize);
+                                               strncpy((char*)temp_buff, [droppedStr cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
                                                temp_buff[pastedTextSize] = '\0';
                                                
                                                strArray->strings[i] = temp_buff;
@@ -1085,7 +1125,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
                                        
                                case GHOST_kDragnDropTypeString:
                                        droppedStr = (NSString*)data;
-                                       pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding];
+                                       pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
                                        
                                        temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); 
                                        
@@ -1093,12 +1133,130 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
                                                return GHOST_kFailure;
                                        }
                                        
-                                       strncpy((char*)temp_buff, [droppedStr cStringUsingEncoding:NSISOLatin1StringEncoding], pastedTextSize);
+                                       strncpy((char*)temp_buff, [droppedStr cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
                                        
                                        temp_buff[pastedTextSize] = '\0';
                                        
                                        eventData = (GHOST_TEventDataPtr) temp_buff;
                                        break;
+                               
+                               case GHOST_kDragnDropTypeBitmap:
+                               {
+                                       NSImage *droppedImg = (NSImage*)data;
+                                       NSSize imgSize = [droppedImg size];
+                                       ImBuf *ibuf = NULL;
+                                       GHOST_TUns8 *rasterRGB = NULL;
+                                       GHOST_TUns8 *rasterRGBA = NULL;
+                                       GHOST_TUns8 *toIBuf = NULL;
+                                       int x, y, to_i, from_i;
+                                       NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA,*bitmapImage=nil;
+                                       NSEnumerator *enumerator;
+                                       NSImageRep *representation;
+                                       
+                                       ibuf = IMB_allocImBuf (imgSize.width , imgSize.height, 32, IB_rect);
+                                       if (!ibuf) {
+                                               [droppedImg release];
+                                               return GHOST_kFailure;
+                                       }
+                                       
+                                       /*Get the bitmap of the image*/
+                                       enumerator = [[droppedImg representations] objectEnumerator];
+                                       while ((representation = [enumerator nextObject])) {
+                                               if ([representation isKindOfClass:[NSBitmapImageRep class]]) {
+                                                       bitmapImage = (NSBitmapImageRep *)representation;
+                                                       break;
+                                               }
+                                       }
+                                       if (bitmapImage == nil) return GHOST_kFailure;
+                                       
+                                       if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0)
+                                               && ![bitmapImage isPlanar]) {
+                                               /* Try a fast copy if the image is a meshed RGBA 32bit bitmap*/
+                                               toIBuf = (GHOST_TUns8*)ibuf->rect;
+                                               rasterRGB = (GHOST_TUns8*)[bitmapImage bitmapData];
+                                               for (y = 0; y < imgSize.height; y++) {
+                                                       to_i = (imgSize.height-y-1)*imgSize.width;
+                                                       from_i = y*imgSize.width;
+                                                       memcpy(toIBuf+4*to_i, rasterRGB+4*from_i, 4*imgSize.width);
+                                               }
+                                       }
+                                       else {
+                                               /* Tell cocoa image resolution is same as current system one */
+                                               [bitmapImage setSize:imgSize];
+                                               
+                                               /* Convert the image in a RGBA 32bit format */
+                                               /* As Core Graphics does not support contextes with non premutliplied alpha,
+                                                we need to get alpha key values in a separate batch */
+                                               
+                                               /* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */
+                                               blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
+                                                                                                                                                                                pixelsWide:imgSize.width 
+                                                                                                                                                                                pixelsHigh:imgSize.height
+                                                                                                                                                                         bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:NO
+                                                                                                                                                                        colorSpaceName:NSDeviceRGBColorSpace 
+                                                                                                                                                                          bitmapFormat:(NSBitmapFormat)0
+                                                                                                                                                                               bytesPerRow:4*imgSize.width
+                                                                                                                                                                          bitsPerPixel:32/*RGB format padded to 32bits*/];
+                                               
+                                               [NSGraphicsContext saveGraphicsState];
+                                               [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
+                                               [bitmapImage draw];
+                                               [NSGraphicsContext restoreGraphicsState];
+                                               
+                                               rasterRGB = (GHOST_TUns8*)[blBitmapFormatImageRGB bitmapData];
+                                               if (rasterRGB == NULL) {
+                                                       [bitmapImage release];
+                                                       [blBitmapFormatImageRGB release];
+                                                       [droppedImg release];
+                                                       return GHOST_kFailure;
+                                               }
+                                               
+                                               /* Then get Alpha values by getting the RGBA image (that is premultiplied btw) */
+                                               blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
+                                                                                                                                                                                 pixelsWide:imgSize.width
+                                                                                                                                                                                 pixelsHigh:imgSize.height
+                                                                                                                                                                          bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
+                                                                                                                                                                         colorSpaceName:NSDeviceRGBColorSpace
+                                                                                                                                                                               bitmapFormat:(NSBitmapFormat)0
+                                                                                                                                                                                bytesPerRow:4*imgSize.width
+                                                                                                                                                                               bitsPerPixel:32/* RGBA */];
+                                               
+                                               [NSGraphicsContext saveGraphicsState];
+                                               [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
+                                               [bitmapImage draw];
+                                               [NSGraphicsContext restoreGraphicsState];
+                                               
+                                               rasterRGBA = (GHOST_TUns8*)[blBitmapFormatImageRGBA bitmapData];
+                                               if (rasterRGBA == NULL) {
+                                                       [bitmapImage release];
+                                                       [blBitmapFormatImageRGB release];
+                                                       [blBitmapFormatImageRGBA release];
+                                                       [droppedImg release];
+                                                       return GHOST_kFailure;
+                                               }
+                                               
+                                               /*Copy the image to ibuf, flipping it vertically*/
+                                               toIBuf = (GHOST_TUns8*)ibuf->rect;
+                                               for (y = 0; y < imgSize.height; y++) {
+                                                       for (x = 0; x < imgSize.width; x++) {
+                                                               to_i = (imgSize.height-y-1)*imgSize.width + x;
+                                                               from_i = y*imgSize.width + x;
+                                                               
+                                                               toIBuf[4*to_i] = rasterRGB[4*from_i]; /* R */
+                                                               toIBuf[4*to_i+1] = rasterRGB[4*from_i+1]; /* G */
+                                                               toIBuf[4*to_i+2] = rasterRGB[4*from_i+2]; /* B */
+                                                               toIBuf[4*to_i+3] = rasterRGBA[4*from_i+3]; /* A */
+                                                       }
+                                               }
+                                               
+                                               [blBitmapFormatImageRGB release];
+                                               [blBitmapFormatImageRGBA release];
+                                               [droppedImg release];
+                                       }
+                                       
+                                       eventData = (GHOST_TEventDataPtr) ibuf;
+                               }
+                                       break;
                                        
                                default:
                                        return GHOST_kFailure;
@@ -1137,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();
                        }
                }
 
@@ -1155,7 +1318,18 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
        NSString *filepath = (NSString*)filepathStr;
        int confirmOpen = NSAlertAlternateReturn;
        NSArray *windowsList;
+       char * temp_buff;
+       size_t filenameTextSize;        
+       GHOST_Window* window= (GHOST_Window*)m_windowManager->getActiveWindow();
+       
+       if (!window) {
+               return NO;
+       }       
        
+       //Discard event if we are in cursor grab sequence, it'll lead to "stuck cursor" situation if the alert panel is raised
+       if (window && (window->getCursorGrabMode() != GHOST_kGrabDisable) && (window->getCursorGrabMode() != GHOST_kGrabNormal))
+               return GHOST_kExitCancel;
+
        //Check open windows if some changes are not saved
        if (m_windowManager->getAnyModifiedState())
        {
@@ -1172,7 +1346,20 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
 
        if (confirmOpen == NSAlertAlternateReturn)
        {
-               handleDraggingEvent(GHOST_kEventDraggingDropOnIcon,GHOST_kDragnDropTypeFilenames,NULL,0,0, [NSArray arrayWithObject:filepath]);
+               filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+               
+               temp_buff = (char*) malloc(filenameTextSize+1); 
+               
+               if (temp_buff == NULL) {
+                       return GHOST_kFailure;
+               }
+               
+               strncpy(temp_buff, [filepath cStringUsingEncoding:NSUTF8StringEncoding], filenameTextSize);
+               
+               temp_buff[filenameTextSize] = '\0';
+
+               pushEvent(new GHOST_EventString(getMilliSeconds(),GHOST_kEventOpenMainFile,window,(GHOST_TEventDataPtr) temp_buff));
+
                return YES;
        }
        else return NO;
@@ -1181,9 +1368,13 @@ bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
 GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventType)
 {
        NSEvent *event = (NSEvent *)eventPtr;
-       GHOST_IWindow* window = m_windowManager->getActiveWindow();
+       GHOST_IWindow* window;
        
-       if (!window) return GHOST_kFailure;
+       window = m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
+       if (!window) {
+               //printf("\nW failure for event 0x%x",[event type]);
+               return GHOST_kFailure;
+       }
        
        GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
        
@@ -1232,9 +1423,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
 GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 {
        NSEvent *event = (NSEvent *)eventPtr;
-    GHOST_Window* window = (GHOST_Window*)m_windowManager->getActiveWindow();
+    GHOST_WindowCocoa* window;
        
+       window = (GHOST_WindowCocoa*)m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
        if (!window) {
+               //printf("\nW failure for event 0x%x",[event type]);
                return GHOST_kFailure;
        }
        
@@ -1296,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);
                                                
@@ -1305,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);
                                                
-                                               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
@@ -1313,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 */
@@ -1322,7 +1516,7 @@ 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;
@@ -1344,21 +1538,26 @@ 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);
-                                               setCursorPosition(x_cur, y_cur); /* wrap */
+                                               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
                                                NSPoint mousePos = [event locationInWindow];
-                                               pushEvent(new GHOST_EventCursor([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 occured between two cursor warps, so we can reset the delta counter
+                                               m_cursorDelta_y=0; //Mouse motion occurred between two cursor warps, so we can reset the delta counter
                                        }
                                                break;
                                }
@@ -1371,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;
@@ -1378,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];
                                        
@@ -1394,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;
 
-                                       pushEvent(new GHOST_EventTrackpad([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;
@@ -1402,7 +1607,9 @@ 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,
+                               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;
@@ -1410,7 +1617,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                case NSEventTypeRotate:
                        {
                                NSPoint mousePos = [event locationInWindow];
-                               pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventRotate, mousePos.x, mousePos.y,
+                               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:
@@ -1431,7 +1640,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
 {
        NSEvent *event = (NSEvent *)eventPtr;
-       GHOST_IWindow* window = m_windowManager->getActiveWindow();
+       GHOST_IWindow* window;
        unsigned int modifiers;
        NSString *characters;
        NSData *convertedCharacters;
@@ -1439,50 +1648,58 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
        unsigned char ascii;
        NSString* charsIgnoringModifiers;
 
-       /* Can happen, very rarely - seems to only be when command-H makes
-        * the window go away and we still get an HKey up. 
-        */
+       window = m_windowManager->getWindowAssociatedWithOSWindow((void*)[event window]);
        if (!window) {
-               //printf("\nW failure");
+               //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];
                        if ([charsIgnoringModifiers length]>0)
                                keyCode = convertKey([event keyCode],
-                                                                        [charsIgnoringModifiers characterAtIndex:0]);
+                                                                        [charsIgnoringModifiers characterAtIndex:0],
+                                                                        [event type] == NSKeyDown?kUCKeyActionDown:kUCKeyActionUp);
                        else
-                               keyCode = convertKey([event keyCode],0);
+                               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 pressed keyCode=%u ascii=%i %c",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) );
+                               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;
        
                case NSFlagsChanged: 
                        modifiers = [event modifierFlags];
+                       
                        if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
                                pushEvent( new GHOST_EventKey([event timestamp]*1000, (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) );
                        }
@@ -1493,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;
@@ -1590,3 +1807,4 @@ void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
        
        [pool drain];
 }
+