]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/cocoa/window.mm
Fix horizontal mouse wheel scrolling in wxGTK.
[wxWidgets.git] / src / osx / cocoa / window.mm
index 81569093a84617b8313bb4d6ba6e2388cc579bd1..78cd6f99aa9716875b025ff422d719f15105f812 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Stefan Csomor
 // Modified by:
 // Created:     2008-06-20
-// RCS-ID:      $Id$
 // Copyright:   (c) Stefan Csomor
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -17,6 +16,7 @@
     #include "wx/log.h"
     #include "wx/textctrl.h"
     #include "wx/combobox.h"
+    #include "wx/radiobut.h"
 #endif
 
 #ifdef __WXMAC__
@@ -41,7 +41,7 @@
 
 // Get the window with the focus
 
-NSView* GetViewFromResponder( NSResponder* responder )
+NSView* wxOSXGetViewFromResponder( NSResponder* responder )
 {
     NSView* view = nil;
     if ( [responder isKindOfClass:[NSTextView class]] )
@@ -64,16 +64,29 @@ NSView* GetFocusedViewInWindow( NSWindow* keyWindow )
 {
     NSView* focusedView = nil;
     if ( keyWindow != nil )
-        focusedView = GetViewFromResponder([keyWindow firstResponder]);
+        focusedView = wxOSXGetViewFromResponder([keyWindow firstResponder]);
 
     return focusedView;
 }
 
 WXWidget wxWidgetImpl::FindFocus()
 {
-    return GetFocusedViewInWindow( [NSApp keyWindow] );
+    return GetFocusedViewInWindow( [NSApp keyWindow] );;
 }
 
+wxWidgetImpl* wxWidgetImpl::FindBestFromWXWidget(WXWidget control)
+{
+    wxWidgetImpl* impl = FindFromWXWidget(control);
+    
+    // NSScrollViews can have their subviews like NSClipView
+    // therefore check and use the NSScrollView peer in that case
+    if ( impl == NULL && [[control superview] isKindOfClass:[NSScrollView class]])
+        impl = FindFromWXWidget([control superview]);
+    
+    return impl;
+}
+
+
 NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin )
 {
     int x, y, w, h ;
@@ -96,6 +109,22 @@ NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const
 
 @end // wxNSView
 
+@interface wxNSView(TextInput) <NSTextInputClient>
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange;
+- (void)doCommandBySelector:(SEL)aSelector;
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange;
+- (void)unmarkText;
+- (NSRange)selectedRange;
+- (NSRange)markedRange;
+- (BOOL)hasMarkedText;
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange;
+- (NSArray*)validAttributesForMarkedText;
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange;
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint;
+
+@end
+
 @interface NSView(PossibleMethods)
 - (void)setTitle:(NSString *)aString;
 - (void)setStringValue:(NSString *)aString;
@@ -293,59 +322,70 @@ long wxOSXTranslateCocoaKey( NSEvent* event, int eventType )
         case 48:
             retval = WXK_TAB;
             break;
-
-        case 75: // /
-            retval = WXK_NUMPAD_DIVIDE;
-            break;
-        case 67: // *
-            retval = WXK_NUMPAD_MULTIPLY;
-            break;
-        case 78: // -
-            retval = WXK_NUMPAD_SUBTRACT;
-            break;
-        case 69: // +
-            retval = WXK_NUMPAD_ADD;
-            break;
-        case 76: // Enter
-            retval = WXK_NUMPAD_ENTER;
-            break;
-        case 65: // .
-            retval = WXK_NUMPAD_DECIMAL;
-            break;
-        case 82: // 0
-            retval = WXK_NUMPAD0;
-            break;
-        case 83: // 1
-            retval = WXK_NUMPAD1;
-            break;
-        case 84: // 2
-            retval = WXK_NUMPAD2;
-            break;
-        case 85: // 3
-            retval = WXK_NUMPAD3;
-            break;
-        case 86: // 4
-            retval = WXK_NUMPAD4;
-            break;
-        case 87: // 5
-            retval = WXK_NUMPAD5;
-            break;
-        case 88: // 6
-            retval = WXK_NUMPAD6;
-            break;
-        case 89: // 7
-            retval = WXK_NUMPAD7;
-            break;
-        case 91: // 8
-            retval = WXK_NUMPAD8;
-            break;
-        case 92: // 9
-            retval = WXK_NUMPAD9;
-            break;
         default:
-            //retval = [event keyCode];
             break;
     }
+    
+    // Check for NUMPAD keys.  For KEY_UP/DOWN events we need to use the
+    // WXK_NUMPAD constants, but for the CHAR event we want to use the
+    // standard ascii values
+    if ( eventType != wxEVT_CHAR )
+    {
+        switch( [event keyCode] )
+        {
+            case 75: // /
+                retval = WXK_NUMPAD_DIVIDE;
+                break;
+            case 67: // *
+                retval = WXK_NUMPAD_MULTIPLY;
+                break;
+            case 78: // -
+                retval = WXK_NUMPAD_SUBTRACT;
+                break;
+            case 69: // +
+                retval = WXK_NUMPAD_ADD;
+                break;
+            case 76: // Enter
+                retval = WXK_NUMPAD_ENTER;
+                break;
+            case 65: // .
+                retval = WXK_NUMPAD_DECIMAL;
+                break;
+            case 82: // 0
+                retval = WXK_NUMPAD0;
+                break;
+            case 83: // 1
+                retval = WXK_NUMPAD1;
+                break;
+            case 84: // 2
+                retval = WXK_NUMPAD2;
+                break;
+            case 85: // 3
+                retval = WXK_NUMPAD3;
+                break;
+            case 86: // 4
+                retval = WXK_NUMPAD4;
+                break;
+            case 87: // 5
+                retval = WXK_NUMPAD5;
+                break;
+            case 88: // 6
+                retval = WXK_NUMPAD6;
+                break;
+            case 89: // 7
+                retval = WXK_NUMPAD7;
+                break;
+            case 91: // 8
+                retval = WXK_NUMPAD8;
+                break;
+            case 92: // 9
+                retval = WXK_NUMPAD9;
+                break;
+            default:
+                //retval = [event keyCode];
+                break;
+        }
+    }
     return retval;
 }
 
@@ -455,13 +495,15 @@ bool g_lastButtonWasFakeRight = false ;
 @interface NSEvent (DeviceDelta)
 - (CGFloat)deviceDeltaX;
 - (CGFloat)deviceDeltaY;
+
+// 10.7+
+- (BOOL)hasPreciseScrollingDeltas;
+- (CGFloat)scrollingDeltaX;
+- (CGFloat)scrollingDeltaY;
 @end
 
-void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent )
+void wxWidgetCocoaImpl::SetupCoordinates(wxCoord &x, wxCoord &y, NSEvent* nsEvent)
 {
-    int eventType = [nsEvent type];
-    UInt32 modifiers = [nsEvent modifierFlags] ;
-
     NSPoint locationInWindow = [nsEvent locationInWindow];
     
     // adjust coordinates for the window of the target view
@@ -469,20 +511,30 @@ void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEve
     {
         if ( [nsEvent window] != nil )
             locationInWindow = [[nsEvent window] convertBaseToScreen:locationInWindow];
-
+        
         if ( [m_osxView window] != nil )
             locationInWindow = [[m_osxView window] convertScreenToBase:locationInWindow];
     }
-
+    
     NSPoint locationInView = [m_osxView convertPoint:locationInWindow fromView:nil];
     wxPoint locationInViewWX = wxFromNSPoint( m_osxView, locationInView );
+        
+    x = locationInViewWX.x;
+    y = locationInViewWX.y;
+
+}
+
+void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent )
+{
+    int eventType = [nsEvent type];
+    UInt32 modifiers = [nsEvent modifierFlags] ;
+    
+    SetupCoordinates(wxevent.m_x, wxevent.m_y, nsEvent);
 
     // these parameters are not given for all events
     UInt32 button = [nsEvent buttonNumber];
     UInt32 clickCount = 0;
 
-    wxevent.m_x = locationInViewWX.x;
-    wxevent.m_y = locationInViewWX.y;
     wxevent.m_shiftDown = modifiers & NSShiftKeyMask;
     wxevent.m_rawControlDown = modifiers & NSControlKeyMask;
     wxevent.m_altDown = modifiers & NSAlternateKeyMask;
@@ -609,32 +661,52 @@ void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEve
 
             wxevent.SetEventType( wxEVT_MOUSEWHEEL ) ;
 
-            // see http://developer.apple.com/qa/qa2005/qa1453.html
-            // for more details on why we have to look for the exact type
-            
-            const EventRef cEvent = (EventRef) [nsEvent eventRef];
-            bool isMouseScrollEvent = false;
-            if ( cEvent )
-                isMouseScrollEvent = ::GetEventKind(cEvent) == kEventMouseScroll;
-                
-            if ( isMouseScrollEvent )
+            if ( UMAGetSystemVersion() >= 0x1070 )
             {
-                deltaX = [nsEvent deviceDeltaX];
-                deltaY = [nsEvent deviceDeltaY];
+                if ( [nsEvent hasPreciseScrollingDeltas] )
+                {
+                    deltaX = [nsEvent scrollingDeltaX];
+                    deltaY = [nsEvent scrollingDeltaY];
+                }
+                else
+                {
+                    deltaX = [nsEvent scrollingDeltaX] * 10;
+                    deltaY = [nsEvent scrollingDeltaY] * 10;
+                }
             }
             else
             {
-                deltaX = ([nsEvent deltaX] * 10);
-                deltaY = ([nsEvent deltaY] * 10);
+                const EventRef cEvent = (EventRef) [nsEvent eventRef];
+                // see http://developer.apple.com/qa/qa2005/qa1453.html
+                // for more details on why we have to look for the exact type
+                
+                bool isMouseScrollEvent = false;
+                if ( cEvent )
+                    isMouseScrollEvent = ::GetEventKind(cEvent) == kEventMouseScroll;
+                
+                if ( isMouseScrollEvent )
+                {
+                    deltaX = [nsEvent deviceDeltaX];
+                    deltaY = [nsEvent deviceDeltaY];
+                }
+                else
+                {
+                    deltaX = ([nsEvent deltaX] * 10);
+                    deltaY = ([nsEvent deltaY] * 10);
+                }
             }
             
             wxevent.m_wheelDelta = 10;
             wxevent.m_linesPerAction = 1;
+            wxevent.m_columnsPerAction = 1;
                 
             if ( fabs(deltaX) > fabs(deltaY) )
             {
+                // wx conventions for horizontal are inverted from vertical (originating from native msw behavior)
+                // right and up are positive values, left and down are negative values, while on OSX right and down
+                // are negative and left and up are positive.
                 wxevent.m_wheelAxis = wxMOUSE_WHEEL_HORIZONTAL;
-                wxevent.m_wheelRotation = (int)deltaX;
+                wxevent.m_wheelRotation = -(int)deltaX;
             }
             else
             {
@@ -762,8 +834,89 @@ void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEve
     }
     [super removeTrackingRect:tag];
 }
+
+#if wxOSX_USE_NATIVE_FLIPPED
+- (BOOL)isFlipped
+{
+    return YES;
+}
+#endif
+
+- (BOOL) canBecomeKeyView
+{
+    wxWidgetCocoaImpl* viewimpl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+    if ( viewimpl && viewimpl->IsUserPane() && viewimpl->GetWXPeer() )
+        return viewimpl->GetWXPeer()->AcceptsFocus();
+    return NO;
+}
+
 @end // wxNSView
 
+// We need to adopt NSTextInputClient protocol in order to interpretKeyEvents: to work.
+// Currently, only insertText:(replacementRange:) is
+// implemented here, and the rest of the methods are stubs.
+// It is hoped that someday IME-related functionality is implemented in
+// wxWidgets and the methods of this protocol are fully working.
+
+@implementation wxNSView(TextInput)
+
+void wxOSX_insertText(NSView* self, SEL _cmd, NSString* text);
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
+{
+    wxOSX_insertText(self, @selector(insertText:), aString);
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+    // these are already caught in the keyEvent handler
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+{
+}
+
+- (void)unmarkText
+{
+}
+
+- (NSRange)selectedRange
+{    
+    return NSMakeRange(NSNotFound, 0);
+}
+
+- (NSRange)markedRange
+{
+    return NSMakeRange(NSNotFound, 0);
+}
+
+- (BOOL)hasMarkedText
+{
+    return NO;
+}
+
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+    return nil;
+}
+
+- (NSArray*)validAttributesForMarkedText
+{
+    return nil;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+    return NSMakeRect(0, 0, 0, 0);
+}
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+{
+    return NSNotFound;
+}
+
+@end // wxNSView(TextInput)
+
+
 //
 // event handlers
 //
@@ -890,6 +1043,8 @@ BOOL wxOSX_resignFirstResponder(NSView* self, SEL _cmd)
     return impl->resignFirstResponder(self, _cmd);
 }
 
+#if !wxOSX_USE_NATIVE_FLIPPED
+
 BOOL wxOSX_isFlipped(NSView* self, SEL _cmd)
 {
     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
@@ -899,6 +1054,8 @@ BOOL wxOSX_isFlipped(NSView* self, SEL _cmd)
     return impl->isFlipped(self, _cmd) ? YES:NO;
 }
 
+#endif
+
 typedef void (*wxOSX_DrawRectHandlerPtr)(NSView* self, SEL _cmd, NSRect rect);
 
 void wxOSX_drawRect(NSView* self, SEL _cmd, NSRect rect)
@@ -1112,24 +1269,29 @@ bool wxWidgetCocoaImpl::performDragOperation(void* s, WXWidget WXUNUSED(slf), vo
     return result != wxDragNone;
 }
 
-typedef void (*wxOSX_TextEventHandlerPtr)(NSView* self, SEL _cmd, NSString *event);
-typedef void (*wxOSX_EventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event);
-typedef BOOL (*wxOSX_PerformKeyEventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event);
-typedef BOOL (*wxOSX_FocusHandlerPtr)(NSView* self, SEL _cmd);
-
 void wxWidgetCocoaImpl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
 {
+    // we are getting moved events for all windows in the hierarchy, not something wx expects
+    // therefore we only handle it for the deepest child in the hierarchy
+    if ( [event type] == NSMouseMoved )
+    {
+        NSView* hitview = [[[slf window] contentView] hitTest:[event locationInWindow]];
+        if ( hitview == NULL || hitview != slf)
+            return;
+    }
+    
     if ( !DoHandleMouseEvent(event) )
     {
         // for plain NSView mouse events would propagate to parents otherwise
-        if (!IsUserPane())
+        // scrollwheel events have to be propagated if not handled in all cases
+        if (!IsUserPane() || [event type] == NSScrollWheel )
         {
             wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
             superimpl(slf, (SEL)_cmd, event);
             
             // super of built-ins keeps the mouse up, as wx expects this event, we have to synthesize it
-            
-            if ( [ event type]  == NSLeftMouseDown )
+            // only trigger if at this moment the mouse is already up
+            if ( [ event type]  == NSLeftMouseDown && !wxGetMouseState().LeftIsDown() )
             {
                 wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
                 SetupMouseEvent(wxevent , event) ;
@@ -1143,20 +1305,45 @@ void wxWidgetCocoaImpl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
 
 void wxWidgetCocoaImpl::cursorUpdate(WX_NSEvent event, WXWidget slf, void *_cmd)
 {
-    NSCursor *cursor = (NSCursor*)GetWXPeer()->GetCursor().GetHCURSOR();
-    if (cursor == NULL)
+    if ( !SetupCursor(event) )
     {
         wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
-        superimpl(slf, (SEL)_cmd, event);
+            superimpl(slf, (SEL)_cmd, event);
     }
-    else 
+ }
+
+bool wxWidgetCocoaImpl::SetupCursor(WX_NSEvent event)
+{
+    extern wxCursor gGlobalCursor;
+    
+    if ( gGlobalCursor.IsOk() )
     {
-        [cursor set];
+        gGlobalCursor.MacInstall();
+        return true;
+    }
+    else
+    {
+        wxWindow* cursorTarget = GetWXPeer();
+        wxCoord x,y;
+        SetupCoordinates(x, y, event);
+        wxPoint cursorPoint( x , y ) ;
+        
+        while ( cursorTarget && !cursorTarget->MacSetupCursor( cursorPoint ) )
+        {
+            // at least in GTK cursor events are not propagated either ...
+#if 1
+            cursorTarget = NULL;
+#else
+            cursorTarget = cursorTarget->GetParent() ;
+            if ( cursorTarget )
+                cursorPoint += cursorTarget->GetPosition();
+#endif
+        }
+        
+        return cursorTarget != NULL;
     }
 }
 
-
-
 void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
 {
     if ( [event type] == NSKeyDown )
@@ -1202,14 +1389,14 @@ bool wxWidgetCocoaImpl::performKeyEquivalent(WX_NSEvent event, WXWidget slf, voi
     {
         wxEvtHandler * const handler = m_wxPeer->GetEventHandler();
         
-        wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
+        wxCommandEvent command_event( wxEVT_MENU, command );
         command_event.SetEventObject( wxevent.GetEventObject() );
         handled = handler->ProcessEvent( command_event );
         
         if ( !handled )
         {
             // accelerators can also be used with buttons, try them too
-            command_event.SetEventType(wxEVT_COMMAND_BUTTON_CLICKED);
+            command_event.SetEventType(wxEVT_BUTTON);
             handled = handler->ProcessEvent( command_event );
         }
     }
@@ -1253,20 +1440,17 @@ bool wxWidgetCocoaImpl::resignFirstResponder(WXWidget slf, void *_cmd)
 {
     wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
     BOOL r = superimpl(slf, (SEL)_cmd);
-    // get the current focus after running resignFirstResponder
-    // note that this value isn't reliable, it might return the same view that
-    // is resigning
-    NSView* otherView = FindFocus();
-    wxWidgetImpl* otherWindow = FindFromWXWidget(otherView);
+    NSResponder * responder = wxNonOwnedWindowCocoaImpl::GetNextFirstResponder();
+    NSView* otherView = wxOSXGetViewFromResponder(responder);
 
-    // It doesn't make sense to notify about the loss of focus if we're not
-    // really losing it and the window which has just gained focus is the same
-    // one as this window itself. Of course, this should never happen in the
-    // first place but somehow it does in wxGrid code and without this check we
-    // enter into an infinite recursion, see #12267.
+    wxWidgetImpl* otherWindow = FindBestFromWXWidget(otherView);
+    
+    // It doesn't make sense to notify about the loss of focus if it's the same
+    // control in the end, and just a different subview
     if ( otherWindow == this )
         return r;
-
+    
     // NSTextViews have an editor as true responder, therefore the might get the
     // resign notification if their editor takes over, don't trigger any event then
     if ( r && !m_hasEditor)
@@ -1276,11 +1460,14 @@ bool wxWidgetCocoaImpl::resignFirstResponder(WXWidget slf, void *_cmd)
     return r;
 }
 
-bool wxWidgetCocoaImpl::isFlipped(WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd))
+#if !wxOSX_USE_NATIVE_FLIPPED
+
+bool wxWidgetCocoaImpl::isFlipped(WXWidget slf, void *WXUNUSED(_cmd))
 {
     return m_isFlipped;
 }
 
+#endif
 
 #define OSX_DEBUG_DRAWING 0
 
@@ -1289,15 +1476,20 @@ void wxWidgetCocoaImpl::drawRect(void* rect, WXWidget slf, void *WXUNUSED(_cmd))
     // preparing the update region
     
     wxRegion updateRgn;
+
+    // since adding many rects to a region is a costly process, by default use the bounding rect
+#if 0
     const NSRect *rects;
     NSInteger count;
-
     [slf getRectsBeingDrawn:&rects count:&count];
     for ( int i = 0 ; i < count ; ++i )
     {
         updateRgn.Union(wxFromNSRect(slf, rects[i]));
     }
-
+#else
+    updateRgn.Union(wxFromNSRect(slf,*(NSRect*)rect));
+#endif
+    
     wxWindow* wxpeer = GetWXPeer();
 
     if ( wxpeer->MacGetLeftBorderSize() != 0 || wxpeer->MacGetTopBorderSize() != 0 )
@@ -1352,7 +1544,7 @@ void wxWidgetCocoaImpl::drawRect(void* rect, WXWidget slf, void *WXUNUSED(_cmd))
     CGContextStrokePath(context);
 #endif
     
-    if ( !m_isFlipped )
+    if ( ![slf isFlipped] )
     {
         CGContextTranslateCTM( context, 0,  [m_osxView bounds].size.height );
         CGContextScaleCTM( context, 1, -1 );
@@ -1374,7 +1566,7 @@ void wxWidgetCocoaImpl::drawRect(void* rect, WXWidget slf, void *WXUNUSED(_cmd))
         CGContextSaveGState( context );
     }
     // as we called restore above, we have to flip again if necessary
-    if ( !m_isFlipped )
+    if ( ![slf isFlipped] )
     {
         CGContextTranslateCTM( context, 0,  [m_osxView bounds].size.height );
         CGContextScaleCTM( context, 1, -1 );
@@ -1417,7 +1609,10 @@ void wxWidgetCocoaImpl::controlAction( WXWidget WXUNUSED(slf), void *WXUNUSED(_c
 {
     wxWindow* wxpeer = (wxWindow*) GetWXPeer();
     if ( wxpeer )
+    {
+        wxpeer->OSXSimulateFocusEvents();
         wxpeer->OSXHandleClicked(0);
+    }
 }
 
 void wxWidgetCocoaImpl::controlDoubleAction( WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd), void *WXUNUSED(sender))
@@ -1499,7 +1694,9 @@ void wxOSXCocoaClassAddWXMethods(Class c)
     wxOSX_CLASS_ADD_METHOD(c, @selector(becomeFirstResponder), (IMP) wxOSX_becomeFirstResponder, "c@:" )
     wxOSX_CLASS_ADD_METHOD(c, @selector(resignFirstResponder), (IMP) wxOSX_resignFirstResponder, "c@:" )
 
+#if !wxOSX_USE_NATIVE_FLIPPED
     wxOSX_CLASS_ADD_METHOD(c, @selector(isFlipped), (IMP) wxOSX_isFlipped, "c@:" )
+#endif
     wxOSX_CLASS_ADD_METHOD(c, @selector(drawRect:), (IMP) wxOSX_drawRect, "v@:{_NSRect={_NSPoint=ff}{_NSSize=ff}}" )
 
     wxOSX_CLASS_ADD_METHOD(c, @selector(controlAction:), (IMP) wxOSX_controlAction, "v@:@" )
@@ -1557,7 +1754,9 @@ wxWidgetCocoaImpl::wxWidgetCocoaImpl()
 void wxWidgetCocoaImpl::Init()
 {
     m_osxView = NULL;
+#if !wxOSX_USE_NATIVE_FLIPPED
     m_isFlipped = true;
+#endif
     m_lastKeyDownEvent = NULL;
     m_hasEditor = false;
 }
@@ -1587,6 +1786,17 @@ void wxWidgetCocoaImpl::SetVisibility( bool visible )
     [m_osxView setHidden:(visible ? NO:YES)];
 }
 
+double wxWidgetCocoaImpl::GetContentScaleFactor() const
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+    NSWindow* tlw = [m_osxView window];
+    if ( [ tlw respondsToSelector:@selector(backingScaleFactor) ] )
+        return [tlw backingScaleFactor];
+    else
+#endif
+        return 1.0;
+}
+
 // ----------------------------------------------------------------------------
 // window animation stuff
 // ----------------------------------------------------------------------------
@@ -1632,7 +1842,6 @@ void wxWidgetCocoaImpl::SetVisibility( bool visible )
     wxUnusedVar(progress);
 
     m_win->SendSizeEvent();
-    m_win->MacOnInternalSize();
 }
 
 - (void)animationDidEnd:(NSAnimation*)animation
@@ -1809,7 +2018,6 @@ wxWidgetCocoaImpl::ShowViewOrWindowWithEffect(wxWindow *win,
         // refresh it once again after the end to ensure that everything is in
         // place
         win->SendSizeEvent();
-        win->MacOnInternalSize();
     }
 
     [anim setDelegate:nil];
@@ -2072,6 +2280,27 @@ bool wxWidgetCocoaImpl::SetFocus()
     return true;
 }
 
+void wxWidgetCocoaImpl::SetDropTarget(wxDropTarget* target)
+{
+    [m_osxView unregisterDraggedTypes];
+    
+    if ( target == NULL )
+        return;
+    
+    wxDataObject* dobj = target->GetDataObject();
+    
+    if( dobj )
+    {
+        CFMutableArrayRef typesarray = CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
+        dobj->AddSupportedTypes(typesarray);
+        NSView* targetView = m_osxView;
+        if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
+            targetView = [(NSScrollView*) m_osxView documentView];
+
+        [targetView registerForDraggedTypes:(NSArray*)typesarray];
+        CFRelease(typesarray);
+    }
+}
 
 void wxWidgetCocoaImpl::RemoveFromParent()
 {
@@ -2083,6 +2312,9 @@ void wxWidgetCocoaImpl::Embed( wxWidgetImpl *parent )
     NSView* container = parent->GetWXWidget() ;
     wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
     [container addSubview:m_osxView];
+    
+    if( m_wxPeer->IsFrozen() )
+        [[m_osxView window] disableFlushWindow];
 }
 
 void wxWidgetCocoaImpl::SetBackgroundColour( const wxColour &col )
@@ -2330,14 +2562,33 @@ void wxWidgetCocoaImpl::SetControlSize( wxWindowVariant variant )
         if ([cell respondsToSelector:@selector(setControlSize:)])
             [cell setControlSize:size];
     }
+
+    // we need to propagate this to inner views as well
+    if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
+    {
+        NSView* targetView = [(NSScrollView*) m_osxView documentView];
+    
+        if ( [targetView respondsToSelector:@selector(setControlSize:)] )
+            [targetView setControlSize:size];
+        else if ([targetView respondsToSelector:@selector(cell)])
+        {
+            id cell = [(id)targetView cell];
+            if ([cell respondsToSelector:@selector(setControlSize:)])
+                [cell setControlSize:size];
+        }
+    }
 }
 
 void wxWidgetCocoaImpl::SetFont(wxFont const& font, wxColour const&col, long, bool)
 {
-    if ([m_osxView respondsToSelector:@selector(setFont:)])
-        [m_osxView setFont: font.OSXGetNSFont()];
-    if ([m_osxView respondsToSelector:@selector(setTextColor:)])
-        [m_osxView setTextColor:[NSColor colorWithCalibratedRed:(CGFloat) (col.Red() / 255.0)
+    NSView* targetView = m_osxView;
+    if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
+        targetView = [(NSScrollView*) m_osxView documentView];
+
+    if ([targetView respondsToSelector:@selector(setFont:)])
+        [targetView setFont: font.OSXGetNSFont()];
+    if ([targetView respondsToSelector:@selector(setTextColor:)])
+        [targetView setTextColor:[NSColor colorWithCalibratedRed:(CGFloat) (col.Red() / 255.0)
                                                                  green:(CGFloat) (col.Green() / 255.0)
                                                                   blue:(CGFloat) (col.Blue() / 255.0)
                                                                  alpha:(CGFloat) (col.Alpha() / 255.0)]];
@@ -2363,7 +2614,13 @@ void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control )
     if ([c respondsToSelector:@selector(setAction:)])
     {
         [c setTarget: c];
-        [c setAction: @selector(controlAction:)];
+        if ( dynamic_cast<wxRadioButton*>(GetWXPeer()) )
+        {
+            // everything already set up
+        }
+        else
+            [c setAction: @selector(controlAction:)];
+        
         if ([c respondsToSelector:@selector(setDoubleAction:)])
         {
             [c setDoubleAction: @selector(controlDoubleAction:)];
@@ -2371,17 +2628,25 @@ void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control )
 
     }
     NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited|NSTrackingCursorUpdate|NSTrackingMouseMoved|NSTrackingActiveAlways|NSTrackingInVisibleRect;
-        NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil];
+    NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil];
     [m_osxView addTrackingArea: area];
     [area release];
  }
 
 bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text)
 {
-    wxKeyEvent wxevent(wxEVT_CHAR);
-    SetupKeyEvent( wxevent, event, text );
+    bool result = false;
+    
+    for (NSUInteger i = 0; i < [text length]; ++i)
+    {
+        wxKeyEvent wxevent(wxEVT_CHAR);
+        unichar c = [text characterAtIndex:i];
+        SetupKeyEvent( wxevent, event, [NSString stringWithCharacters:&c length:1]);
 
-    return GetWXPeer()->OSXHandleKeyEvent(wxevent);
+        result = GetWXPeer()->OSXHandleKeyEvent(wxevent) || result;
+    }
+    
+    return result;
 }
 
 bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event)
@@ -2448,7 +2713,11 @@ bool wxWidgetCocoaImpl::DoHandleMouseEvent(NSEvent *event)
 {
     wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
     SetupMouseEvent(wxevent , event) ;
-    return GetWXPeer()->HandleWindowEvent(wxevent);
+    bool result = GetWXPeer()->HandleWindowEvent(wxevent);
+    
+    (void)SetupCursor(event);
+
+    return result;
 }
 
 void wxWidgetCocoaImpl::DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* otherWindow)
@@ -2476,7 +2745,7 @@ void wxWidgetCocoaImpl::DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* oth
             event.SetWindow(otherWindow->GetWXPeer());
         thisWindow->HandleWindowEvent(event) ;
     }
-    else // !receivedFocuss
+    else // !receivedFocus
     {
 #if wxUSE_CARET
         if ( thisWindow->GetCaret() )
@@ -2510,19 +2779,37 @@ void wxWidgetCocoaImpl::SetCursor(const wxCursor& cursor)
 
 void wxWidgetCocoaImpl::CaptureMouse()
 {
-    [[m_osxView window] disableCursorRects];
+    // TODO remove if we don't get into problems with cursor settings
+    //    [[m_osxView window] disableCursorRects];
 }
 
 void wxWidgetCocoaImpl::ReleaseMouse()
 {
-    [[m_osxView window] enableCursorRects];
+    // TODO remove if we don't get into problems with cursor settings
+    //    [[m_osxView window] enableCursorRects];
 }
 
+#if !wxOSX_USE_NATIVE_FLIPPED
+
 void wxWidgetCocoaImpl::SetFlipped(bool flipped)
 {
     m_isFlipped = flipped;
 }
 
+#endif
+
+void wxWidgetCocoaImpl::SetDrawingEnabled(bool enabled)
+{
+    if ( enabled )
+    {
+        [[m_osxView window] enableFlushWindow];
+        [m_osxView setNeedsDisplay:YES];
+    }
+    else
+    {
+        [[m_osxView window] disableFlushWindow];
+    }
+}
 //
 // Factory methods
 //
@@ -2534,10 +2821,6 @@ wxWidgetImpl* wxWidgetImpl::CreateUserPane( wxWindowMac* wxpeer, wxWindowMac* WX
     NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
     wxNSView* v = [[wxNSView alloc] initWithFrame:r];
 
-    // temporary hook for dnd
-    [v registerForDraggedTypes:[NSArray arrayWithObjects:
-        NSStringPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPICTPboardType, NSPDFPboardType, nil]];
-
     wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( wxpeer, v, false, true );
     return c;
 }
@@ -2551,11 +2834,13 @@ wxWidgetImpl* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
     {
         NSView* cv = [tlw contentView];
         c = new wxWidgetCocoaImpl( now, cv, true );
-        // increase ref count, because the impl destructor will decrement it again
-        CFRetain(cv);
-        if ( !now->IsShown() )
-            [cv setHidden:NO];
-        
+        if ( cv != nil )
+        {
+            // increase ref count, because the impl destructor will decrement it again
+            CFRetain(cv);
+            if ( !now->IsShown() )
+                [cv setHidden:NO];
+        }
     }
     else
     {