patch applied with thanks, fixes #13865
[wxWidgets.git] / src / osx / cocoa / window.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/cocoa/window.mm
3 // Purpose:     widgets (non tlw) for cocoa
4 // Author:      Stefan Csomor
5 // Modified by:
6 // Created:     2008-06-20
7 // RCS-ID:      $Id$
8 // Copyright:   (c) Stefan Csomor
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifndef WX_PRECOMP
15     #include "wx/dcclient.h"
16     #include "wx/frame.h"
17     #include "wx/log.h"
18     #include "wx/textctrl.h"
19     #include "wx/combobox.h"
20 #endif
21
22 #ifdef __WXMAC__
23     #include "wx/osx/private.h"
24 #endif
25
26 #include "wx/evtloop.h"
27
28 #if wxUSE_CARET
29     #include "wx/caret.h"
30 #endif
31
32 #if wxUSE_DRAG_AND_DROP
33     #include "wx/dnd.h"
34 #endif
35
36 #if wxUSE_TOOLTIPS
37     #include "wx/tooltip.h"
38 #endif
39
40 #include <objc/objc-runtime.h>
41
42 // Get the window with the focus
43
44 NSView* GetViewFromResponder( NSResponder* responder )
45 {
46     NSView* view = nil;
47     if ( [responder isKindOfClass:[NSTextView class]] )
48     {
49         NSView* delegate = (NSView*) [(NSTextView*)responder delegate];
50         if ( [delegate isKindOfClass:[NSTextField class] ] )
51             view = delegate;
52         else
53             view =  (NSView*) responder;
54     }
55     else
56     {
57         if ( [responder isKindOfClass:[NSView class]] )
58             view = (NSView*) responder;
59     }
60     return view;
61 }
62
63 NSView* GetFocusedViewInWindow( NSWindow* keyWindow )
64 {
65     NSView* focusedView = nil;
66     if ( keyWindow != nil )
67         focusedView = GetViewFromResponder([keyWindow firstResponder]);
68
69     return focusedView;
70 }
71
72 WXWidget wxWidgetImpl::FindFocus()
73 {
74     return GetFocusedViewInWindow( [NSApp keyWindow] );
75 }
76
77 NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin )
78 {
79     int x, y, w, h ;
80
81     window->MacGetBoundsForControl( pos , size , x , y, w, h , adjustForOrigin ) ;
82     wxRect bounds(x,y,w,h);
83     NSView* sv = (window->GetParent()->GetHandle() );
84
85     return wxToNSRect( sv, bounds );
86 }
87
88 @interface wxNSView : NSView
89 {
90     NSTrackingRectTag rectTag;
91 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
92     NSTrackingArea* _trackingArea;
93 #endif
94 }
95
96 // the tracking tag is needed to track mouse enter / exit events
97 - (void) setTrackingTag: (NSTrackingRectTag)tag;
98 - (NSTrackingRectTag) trackingTag;
99 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
100 // under 10.5 we can also track mouse moved events on non-focused windows if
101 // we use the new NSTrackingArea APIs. 
102 - (void) updateTrackingArea;
103 - (NSTrackingArea*) trackingArea;
104 #endif
105 @end // wxNSView
106
107 @interface NSView(PossibleMethods)
108 - (void)setTitle:(NSString *)aString;
109 - (void)setStringValue:(NSString *)aString;
110 - (void)setIntValue:(int)anInt;
111 - (void)setFloatValue:(float)aFloat;
112 - (void)setDoubleValue:(double)aDouble;
113
114 - (double)minValue;
115 - (double)maxValue;
116 - (void)setMinValue:(double)aDouble;
117 - (void)setMaxValue:(double)aDouble;
118
119 - (void)sizeToFit;
120
121 - (BOOL)isEnabled;
122 - (void)setEnabled:(BOOL)flag;
123
124 - (void)setImage:(NSImage *)image;
125 - (void)setControlSize:(NSControlSize)size;
126
127 - (void)setFont:(NSFont *)fontObject;
128
129 - (id)contentView;
130
131 - (void)setTarget:(id)anObject;
132 - (void)setAction:(SEL)aSelector;
133 - (void)setDoubleAction:(SEL)aSelector;
134 - (void)setBackgroundColor:(NSColor*)aColor;
135 - (void)setOpaque:(BOOL)opaque;
136 - (void)setTextColor:(NSColor *)color;
137 - (void)setImagePosition:(NSCellImagePosition)aPosition;
138 @end
139
140 long wxOSXTranslateCocoaKey( NSEvent* event, int eventType )
141 {
142     long retval = 0;
143
144     if ([event type] != NSFlagsChanged)
145     {
146         NSString* s = [event charactersIgnoringModifiers];
147         // backspace char reports as delete w/modifiers for some reason
148         if ([s length] == 1)
149         {
150             if ( eventType == wxEVT_CHAR && ([event modifierFlags] & NSControlKeyMask) && ( [s characterAtIndex:0] >= 'a' && [s characterAtIndex:0] <= 'z' ) )
151             {
152                 retval = WXK_CONTROL_A + ([s characterAtIndex:0] - 'a');
153             }
154             else
155             {
156                 switch ( [s characterAtIndex:0] )
157                 {
158                     // backspace key
159                     case 0x7F :
160                     case 8 :
161                         retval = WXK_BACK;
162                         break;
163                     case NSUpArrowFunctionKey :
164                         retval = WXK_UP;
165                         break;
166                     case NSDownArrowFunctionKey :
167                         retval = WXK_DOWN;
168                         break;
169                     case NSLeftArrowFunctionKey :
170                         retval = WXK_LEFT;
171                         break;
172                     case NSRightArrowFunctionKey :
173                         retval = WXK_RIGHT;
174                         break;
175                     case NSInsertFunctionKey  :
176                         retval = WXK_INSERT;
177                         break;
178                     case NSDeleteFunctionKey  :
179                         retval = WXK_DELETE;
180                         break;
181                     case NSHomeFunctionKey  :
182                         retval = WXK_HOME;
183                         break;
184             //        case NSBeginFunctionKey  :
185             //            retval = WXK_BEGIN;
186             //            break;
187                     case NSEndFunctionKey  :
188                         retval = WXK_END;
189                         break;
190                     case NSPageUpFunctionKey  :
191                         retval = WXK_PAGEUP;
192                         break;
193                    case NSPageDownFunctionKey  :
194                         retval = WXK_PAGEDOWN;
195                         break;
196                    case NSHelpFunctionKey  :
197                         retval = WXK_HELP;
198                         break;
199                     default:
200                         int intchar = [s characterAtIndex: 0];
201                         if ( intchar >= NSF1FunctionKey && intchar <= NSF24FunctionKey )
202                             retval = WXK_F1 + (intchar - NSF1FunctionKey );
203                         else if ( intchar > 0 && intchar < 32 )
204                             retval = intchar;
205                         break;
206                 }
207             }
208         }
209     }
210
211     // Some keys don't seem to have constants. The code mimics the approach
212     // taken by WebKit. See:
213     // http://trac.webkit.org/browser/trunk/WebCore/platform/mac/KeyEventMac.mm
214     switch( [event keyCode] )
215     {
216         // command key
217         case 54:
218         case 55:
219             retval = WXK_CONTROL;
220             break;
221         // caps locks key
222         case 57: // Capslock
223             retval = WXK_CAPITAL;
224             break;
225         // shift key
226         case 56: // Left Shift
227         case 60: // Right Shift
228             retval = WXK_SHIFT;
229             break;
230         // alt key
231         case 58: // Left Alt
232         case 61: // Right Alt
233             retval = WXK_ALT;
234             break;
235         // ctrl key
236         case 59: // Left Ctrl
237         case 62: // Right Ctrl
238             retval = WXK_RAW_CONTROL;
239             break;
240         // clear key
241         case 71:
242             retval = WXK_CLEAR;
243             break;
244         // tab key
245         case 48:
246             retval = WXK_TAB;
247             break;
248
249         case 75: // /
250             retval = WXK_NUMPAD_DIVIDE;
251             break;
252         case 67: // *
253             retval = WXK_NUMPAD_MULTIPLY;
254             break;
255         case 78: // -
256             retval = WXK_NUMPAD_SUBTRACT;
257             break;
258         case 69: // +
259             retval = WXK_NUMPAD_ADD;
260             break;
261         case 76: // Enter
262             retval = WXK_NUMPAD_ENTER;
263             break;
264         case 65: // .
265             retval = WXK_NUMPAD_DECIMAL;
266             break;
267         case 82: // 0
268             retval = WXK_NUMPAD0;
269             break;
270         case 83: // 1
271             retval = WXK_NUMPAD1;
272             break;
273         case 84: // 2
274             retval = WXK_NUMPAD2;
275             break;
276         case 85: // 3
277             retval = WXK_NUMPAD3;
278             break;
279         case 86: // 4
280             retval = WXK_NUMPAD4;
281             break;
282         case 87: // 5
283             retval = WXK_NUMPAD5;
284             break;
285         case 88: // 6
286             retval = WXK_NUMPAD6;
287             break;
288         case 89: // 7
289             retval = WXK_NUMPAD7;
290             break;
291         case 91: // 8
292             retval = WXK_NUMPAD8;
293             break;
294         case 92: // 9
295             retval = WXK_NUMPAD9;
296             break;
297         default:
298             //retval = [event keyCode];
299             break;
300     }
301     return retval;
302 }
303
304 void wxWidgetCocoaImpl::SetupKeyEvent(wxKeyEvent &wxevent , NSEvent * nsEvent, NSString* charString)
305 {
306     UInt32 modifiers = [nsEvent modifierFlags] ;
307     int eventType = [nsEvent type];
308
309     wxevent.m_shiftDown = modifiers & NSShiftKeyMask;
310     wxevent.m_rawControlDown = modifiers & NSControlKeyMask;
311     wxevent.m_altDown = modifiers & NSAlternateKeyMask;
312     wxevent.m_controlDown = modifiers & NSCommandKeyMask;
313
314     wxevent.m_rawCode = [nsEvent keyCode];
315     wxevent.m_rawFlags = modifiers;
316
317     wxevent.SetTimestamp( (int)([nsEvent timestamp] * 1000) ) ;
318
319     wxString chars;
320     if ( eventType != NSFlagsChanged )
321     {
322         NSString* nschars = [[nsEvent charactersIgnoringModifiers] uppercaseString];
323         if ( charString )
324         {
325             // if charString is set, it did not come from key up / key down
326             wxevent.SetEventType( wxEVT_CHAR );
327             chars = wxCFStringRef::AsString(charString);
328         }
329         else if ( nschars )
330         {
331             chars = wxCFStringRef::AsString(nschars);
332         }
333     }
334
335     int aunichar = chars.Length() > 0 ? chars[0] : 0;
336     long keyval = 0;
337
338     if (wxevent.GetEventType() != wxEVT_CHAR)
339     {
340         keyval = wxOSXTranslateCocoaKey(nsEvent, wxevent.GetEventType()) ;
341         switch (eventType)
342         {
343             case NSKeyDown :
344                 wxevent.SetEventType( wxEVT_KEY_DOWN )  ;
345                 break;
346             case NSKeyUp :
347                 wxevent.SetEventType( wxEVT_KEY_UP )  ;
348                 break;
349             case NSFlagsChanged :
350                 switch (keyval)
351                 {
352                     case WXK_CONTROL:
353                         wxevent.SetEventType( wxevent.m_controlDown ? wxEVT_KEY_DOWN : wxEVT_KEY_UP);
354                         break;
355                     case WXK_SHIFT:
356                         wxevent.SetEventType( wxevent.m_shiftDown ? wxEVT_KEY_DOWN : wxEVT_KEY_UP);
357                         break;
358                     case WXK_ALT:
359                         wxevent.SetEventType( wxevent.m_altDown ? wxEVT_KEY_DOWN : wxEVT_KEY_UP);
360                         break;
361                     case WXK_RAW_CONTROL:
362                         wxevent.SetEventType( wxevent.m_rawControlDown ? wxEVT_KEY_DOWN : wxEVT_KEY_UP);
363                         break;
364                 }
365                 break;
366             default :
367                 break ;
368         }
369     }
370
371     if ( !keyval )
372     {
373         if ( wxevent.GetEventType() == wxEVT_KEY_UP || wxevent.GetEventType() == wxEVT_KEY_DOWN )
374             keyval = wxToupper( aunichar ) ;
375         else
376             keyval = aunichar;
377     }
378
379 #if wxUSE_UNICODE
380     // OS X generates events with key codes in Unicode private use area for
381     // unprintable symbols such as cursor arrows (WXK_UP is mapped to U+F700)
382     // and function keys (WXK_F2 is U+F705). We don't want to use them as the
383     // result of wxKeyEvent::GetUnicodeKey() however as it's supposed to return
384     // WXK_NONE for "non characters" so explicitly exclude them.
385     //
386     // We only exclude the private use area inside the Basic Multilingual Plane
387     // as key codes beyond it don't seem to be currently used.
388     if ( !(aunichar >= 0xe000 && aunichar < 0xf900) )
389         wxevent.m_uniChar = aunichar;
390 #endif
391     wxevent.m_keyCode = keyval;
392
393     wxWindowMac* peer = GetWXPeer();
394     if ( peer )
395     {
396         wxevent.SetEventObject(peer);
397         wxevent.SetId(peer->GetId()) ;
398     }
399 }
400
401 UInt32 g_lastButton = 0 ;
402 bool g_lastButtonWasFakeRight = false ;
403
404 // better scroll wheel support 
405 // see http://lists.apple.com/archives/cocoa-dev/2007/Feb/msg00050.html
406
407 @interface NSEvent (DeviceDelta)
408 - (CGFloat)deviceDeltaX;
409 - (CGFloat)deviceDeltaY;
410 @end
411
412 void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent )
413 {
414     int eventType = [nsEvent type];
415     UInt32 modifiers = [nsEvent modifierFlags] ;
416
417     NSPoint locationInWindow = [nsEvent locationInWindow];
418     
419     // adjust coordinates for the window of the target view
420     if ( [nsEvent window] != [m_osxView window] )
421     {
422         if ( [nsEvent window] != nil )
423             locationInWindow = [[nsEvent window] convertBaseToScreen:locationInWindow];
424
425         if ( [m_osxView window] != nil )
426             locationInWindow = [[m_osxView window] convertScreenToBase:locationInWindow];
427     }
428
429     NSPoint locationInView = [m_osxView convertPoint:locationInWindow fromView:nil];
430     wxPoint locationInViewWX = wxFromNSPoint( m_osxView, locationInView );
431
432     // these parameters are not given for all events
433     UInt32 button = [nsEvent buttonNumber];
434     UInt32 clickCount = 0;
435
436     wxevent.m_x = locationInViewWX.x;
437     wxevent.m_y = locationInViewWX.y;
438     wxevent.m_shiftDown = modifiers & NSShiftKeyMask;
439     wxevent.m_rawControlDown = modifiers & NSControlKeyMask;
440     wxevent.m_altDown = modifiers & NSAlternateKeyMask;
441     wxevent.m_controlDown = modifiers & NSCommandKeyMask;
442     wxevent.SetTimestamp( (int)([nsEvent timestamp] * 1000) ) ;
443
444     UInt32 mouseChord = 0;
445
446     switch (eventType)
447     {
448         case NSLeftMouseDown :
449         case NSLeftMouseDragged :
450             mouseChord = 1U;
451             break;
452         case NSRightMouseDown :
453         case NSRightMouseDragged :
454             mouseChord = 2U;
455             break;
456         case NSOtherMouseDown :
457         case NSOtherMouseDragged :
458             mouseChord = 4U;
459             break;
460     }
461
462     // a control click is interpreted as a right click
463     bool thisButtonIsFakeRight = false ;
464     if ( button == 0 && (modifiers & NSControlKeyMask) )
465     {
466         button = 1 ;
467         thisButtonIsFakeRight = true ;
468     }
469
470     // otherwise we report double clicks by connecting a left click with a ctrl-left click
471     if ( clickCount > 1 && button != g_lastButton )
472         clickCount = 1 ;
473
474     // we must make sure that our synthetic 'right' button corresponds in
475     // mouse down, moved and mouse up, and does not deliver a right down and left up
476     switch (eventType)
477     {
478         case NSLeftMouseDown :
479         case NSRightMouseDown :
480         case NSOtherMouseDown :
481             g_lastButton = button ;
482             g_lastButtonWasFakeRight = thisButtonIsFakeRight ;
483             break;
484      }
485
486     if ( button == 0 )
487     {
488         g_lastButton = 0 ;
489         g_lastButtonWasFakeRight = false ;
490     }
491     else if ( g_lastButton == 1 && g_lastButtonWasFakeRight )
492         button = g_lastButton ;
493
494     // Adjust the chord mask to remove the primary button and add the
495     // secondary button.  It is possible that the secondary button is
496     // already pressed, e.g. on a mouse connected to a laptop, but this
497     // possibility is ignored here:
498     if( thisButtonIsFakeRight && ( mouseChord & 1U ) )
499         mouseChord = ((mouseChord & ~1U) | 2U);
500
501     if(mouseChord & 1U)
502                 wxevent.m_leftDown = true ;
503     if(mouseChord & 2U)
504                 wxevent.m_rightDown = true ;
505     if(mouseChord & 4U)
506                 wxevent.m_middleDown = true ;
507
508     // translate into wx types
509     switch (eventType)
510     {
511         case NSLeftMouseDown :
512         case NSRightMouseDown :
513         case NSOtherMouseDown :
514             clickCount = [nsEvent clickCount];
515             switch ( button )
516             {
517                 case 0 :
518                     wxevent.SetEventType( clickCount > 1 ? wxEVT_LEFT_DCLICK : wxEVT_LEFT_DOWN )  ;
519                     break ;
520
521                 case 1 :
522                     wxevent.SetEventType( clickCount > 1 ? wxEVT_RIGHT_DCLICK : wxEVT_RIGHT_DOWN ) ;
523                     break ;
524
525                 case 2 :
526                     wxevent.SetEventType( clickCount > 1 ? wxEVT_MIDDLE_DCLICK : wxEVT_MIDDLE_DOWN ) ;
527                     break ;
528
529                 default:
530                     break ;
531             }
532             break ;
533
534         case NSLeftMouseUp :
535         case NSRightMouseUp :
536         case NSOtherMouseUp :
537             clickCount = [nsEvent clickCount];
538             switch ( button )
539             {
540                 case 0 :
541                     wxevent.SetEventType( wxEVT_LEFT_UP )  ;
542                     break ;
543
544                 case 1 :
545                     wxevent.SetEventType( wxEVT_RIGHT_UP ) ;
546                     break ;
547
548                 case 2 :
549                     wxevent.SetEventType( wxEVT_MIDDLE_UP ) ;
550                     break ;
551
552                 default:
553                     break ;
554             }
555             break ;
556
557      case NSScrollWheel :
558         {
559             float deltaX = 0.0;
560             float deltaY = 0.0;
561
562             wxevent.SetEventType( wxEVT_MOUSEWHEEL ) ;
563
564             // see http://developer.apple.com/qa/qa2005/qa1453.html
565             // for more details on why we have to look for the exact type
566             
567             const EventRef cEvent = (EventRef) [nsEvent eventRef];
568             bool isMouseScrollEvent = false;
569             if ( cEvent )
570                 isMouseScrollEvent = ::GetEventKind(cEvent) == kEventMouseScroll;
571                 
572             if ( isMouseScrollEvent )
573             {
574                 deltaX = [nsEvent deviceDeltaX];
575                 deltaY = [nsEvent deviceDeltaY];
576             }
577             else
578             {
579                 deltaX = ([nsEvent deltaX] * 10);
580                 deltaY = ([nsEvent deltaY] * 10);
581             }
582             
583             wxevent.m_wheelDelta = 10;
584             wxevent.m_linesPerAction = 1;
585                 
586             if ( fabs(deltaX) > fabs(deltaY) )
587             {
588                 wxevent.m_wheelAxis = 1;
589                 wxevent.m_wheelRotation = (int)deltaX;
590             }
591             else
592             {
593                 wxevent.m_wheelRotation = (int)deltaY;
594             }
595
596         }
597         break ;
598
599         case NSMouseEntered :
600             wxevent.SetEventType( wxEVT_ENTER_WINDOW ) ;
601             break;
602         case NSMouseExited :
603             wxevent.SetEventType( wxEVT_LEAVE_WINDOW ) ;
604             break;
605         case NSLeftMouseDragged :
606         case NSRightMouseDragged :
607         case NSOtherMouseDragged :
608         case NSMouseMoved :
609             wxevent.SetEventType( wxEVT_MOTION ) ;
610             break;
611         default :
612             break ;
613     }
614
615     wxevent.m_clickCount = clickCount;
616     wxWindowMac* peer = GetWXPeer();
617     if ( peer )
618     {
619         wxevent.SetEventObject(peer);
620         wxevent.SetId(peer->GetId()) ;
621     }
622 }
623
624 @implementation wxNSView
625
626 + (void)initialize
627 {
628     static BOOL initialized = NO;
629     if (!initialized)
630     {
631         initialized = YES;
632         wxOSXCocoaClassAddWXMethods( self );
633     }
634 }
635
636 - (void) setTrackingTag: (NSTrackingRectTag)tag
637 {
638     rectTag = tag;
639 }
640
641 - (NSTrackingRectTag) trackingTag
642 {
643     return rectTag;
644 }
645
646 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
647 - (void) updateTrackingArea
648 {
649     if (_trackingArea)
650     {
651         [self removeTrackingArea: _trackingArea];
652         [_trackingArea release];
653     }
654     
655     NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited|NSTrackingMouseMoved|NSTrackingActiveAlways;
656         
657     NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: [self bounds] options: options owner: self userInfo: nil];
658     [self addTrackingArea: area];
659
660     _trackingArea = area;
661 }
662
663 - (NSTrackingArea*) trackingArea
664 {
665     return _trackingArea;
666 }
667 #endif
668 @end // wxNSView
669
670 //
671 // event handlers
672 //
673
674 #if wxUSE_DRAG_AND_DROP
675
676 // see http://lists.apple.com/archives/Cocoa-dev/2005/Jul/msg01244.html
677 // for details on the NSPasteboard -> PasteboardRef conversion
678
679 NSDragOperation wxOSX_draggingEntered( id self, SEL _cmd, id <NSDraggingInfo>sender )
680 {
681     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
682     if (impl == NULL)
683         return NSDragOperationNone;
684
685     return impl->draggingEntered(sender, self, _cmd);
686 }
687
688 void wxOSX_draggingExited( id self, SEL _cmd, id <NSDraggingInfo> sender )
689 {
690     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
691     if (impl == NULL)
692         return ;
693
694     return impl->draggingExited(sender, self, _cmd);
695 }
696
697 NSDragOperation wxOSX_draggingUpdated( id self, SEL _cmd, id <NSDraggingInfo>sender )
698 {
699     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
700     if (impl == NULL)
701         return NSDragOperationNone;
702
703     return impl->draggingUpdated(sender, self, _cmd);
704 }
705
706 BOOL wxOSX_performDragOperation( id self, SEL _cmd, id <NSDraggingInfo> sender )
707 {
708     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
709     if (impl == NULL)
710         return NSDragOperationNone;
711
712     return impl->performDragOperation(sender, self, _cmd) ? YES:NO ;
713 }
714
715 #endif
716
717 void wxOSX_mouseEvent(NSView* self, SEL _cmd, NSEvent *event)
718 {
719     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
720     if (impl == NULL)
721         return;
722
723     impl->mouseEvent(event, self, _cmd);
724 }
725
726 BOOL wxOSX_acceptsFirstMouse(NSView* WXUNUSED(self), SEL WXUNUSED(_cmd), NSEvent *WXUNUSED(event))
727 {
728     // This is needed to support click through, otherwise the first click on a window
729     // will not do anything unless it is the active window already.
730     return YES;
731 }
732
733 void wxOSX_keyEvent(NSView* self, SEL _cmd, NSEvent *event)
734 {
735     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
736     if (impl == NULL)
737         return;
738
739     impl->keyEvent(event, self, _cmd);
740 }
741
742 void wxOSX_insertText(NSView* self, SEL _cmd, NSString* text)
743 {
744     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
745     if (impl == NULL)
746         return;
747
748     impl->insertText(text, self, _cmd);
749 }
750
751 BOOL wxOSX_performKeyEquivalent(NSView* self, SEL _cmd, NSEvent *event)
752 {
753     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
754     if (impl == NULL)
755         return NO;
756
757     return impl->performKeyEquivalent(event, self, _cmd);
758 }
759
760 BOOL wxOSX_acceptsFirstResponder(NSView* self, SEL _cmd)
761 {
762     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
763     if (impl == NULL)
764         return NO;
765
766     return impl->acceptsFirstResponder(self, _cmd);
767 }
768
769 BOOL wxOSX_becomeFirstResponder(NSView* self, SEL _cmd)
770 {
771     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
772     if (impl == NULL)
773         return NO;
774
775     return impl->becomeFirstResponder(self, _cmd);
776 }
777
778 BOOL wxOSX_resignFirstResponder(NSView* self, SEL _cmd)
779 {
780     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
781     if (impl == NULL)
782         return NO;
783
784     return impl->resignFirstResponder(self, _cmd);
785 }
786
787 void wxOSX_resetCursorRects(NSView* self, SEL _cmd)
788 {
789     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
790     if (impl == NULL)
791         return;
792
793     impl->resetCursorRects(self, _cmd);
794 }
795
796 BOOL wxOSX_isFlipped(NSView* self, SEL _cmd)
797 {
798     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
799     if (impl == NULL)
800         return NO;
801
802     return impl->isFlipped(self, _cmd) ? YES:NO;
803 }
804
805 typedef void (*wxOSX_DrawRectHandlerPtr)(NSView* self, SEL _cmd, NSRect rect);
806
807 void wxOSX_drawRect(NSView* self, SEL _cmd, NSRect rect)
808 {
809     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
810     if (impl == NULL)
811         return;
812
813 #ifdef wxUSE_THREADS
814     // OS X starts a NSUIHeartBeatThread for animating the default button in a
815     // dialog. This causes a drawRect of the active dialog from outside the
816     // main UI thread. This causes an occasional crash since the wx drawing
817     // objects (like wxPen) are not thread safe.
818     //
819     // Notice that NSUIHeartBeatThread seems to be undocumented and doing
820     // [NSWindow setAllowsConcurrentViewDrawing:NO] does not affect it.
821     if ( !wxThread::IsMain() )
822     {
823         if ( impl->IsUserPane() )
824         {
825             wxWindow* win = impl->GetWXPeer();
826             if ( win->UseBgCol() )
827             {
828                 
829                 CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
830                 CGContextSaveGState( context );
831
832                 CGContextSetFillColorWithColor( context, win->GetBackgroundColour().GetCGColor());
833                 CGRect r = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
834                 CGContextFillRect( context, r );
835
836                 CGContextRestoreGState( context );
837             }
838         }
839         else 
840         {
841             // just call the superclass handler, we don't need any custom wx drawing
842             // here and it seems to work fine:
843             wxOSX_DrawRectHandlerPtr
844             superimpl = (wxOSX_DrawRectHandlerPtr)
845             [[self superclass] instanceMethodForSelector:_cmd];
846             superimpl(self, _cmd, rect);
847         }
848
849       return;
850     }
851 #endif // wxUSE_THREADS
852
853     return impl->drawRect(&rect, self, _cmd);
854 }
855
856 void wxOSX_controlAction(NSView* self, SEL _cmd, id sender)
857 {
858     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
859     if (impl == NULL)
860         return;
861
862     impl->controlAction(self, _cmd, sender);
863 }
864
865 void wxOSX_controlDoubleAction(NSView* self, SEL _cmd, id sender)
866 {
867     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
868     if (impl == NULL)
869         return;
870
871     impl->controlDoubleAction(self, _cmd, sender);
872 }
873
874 unsigned int wxWidgetCocoaImpl::draggingEntered(void* s, WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd))
875 {
876     id <NSDraggingInfo>sender = (id <NSDraggingInfo>) s;
877     NSPasteboard *pboard = [sender draggingPasteboard];
878     NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
879
880     wxWindow* wxpeer = GetWXPeer();
881     if ( wxpeer == NULL )
882         return NSDragOperationNone;
883
884     wxDropTarget* target = wxpeer->GetDropTarget();
885     if ( target == NULL )
886         return NSDragOperationNone;
887
888     wxDragResult result = wxDragNone;
889     NSPoint nspoint = [m_osxView convertPoint:[sender draggingLocation] fromView:nil];
890     wxPoint pt = wxFromNSPoint( m_osxView, nspoint );
891
892     if ( sourceDragMask & NSDragOperationLink )
893         result = wxDragLink;
894     else if ( sourceDragMask & NSDragOperationCopy )
895         result = wxDragCopy;
896     else if ( sourceDragMask & NSDragOperationMove )
897         result = wxDragMove;
898
899     PasteboardRef pboardRef;
900     PasteboardCreate((CFStringRef)[pboard name], &pboardRef);
901     target->SetCurrentDragPasteboard(pboardRef);
902     result = target->OnEnter(pt.x, pt.y, result);
903     CFRelease(pboardRef);
904
905     NSDragOperation nsresult = NSDragOperationNone;
906     switch (result )
907     {
908         case wxDragLink:
909             nsresult = NSDragOperationLink;
910         case wxDragMove:
911             nsresult = NSDragOperationMove;
912         case wxDragCopy:
913             nsresult = NSDragOperationCopy;
914         default :
915             break;
916     }
917     return nsresult;
918 }
919
920 void wxWidgetCocoaImpl::draggingExited(void* s, WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd))
921 {
922     id <NSDraggingInfo>sender = (id <NSDraggingInfo>) s;
923     NSPasteboard *pboard = [sender draggingPasteboard];
924
925     wxWindow* wxpeer = GetWXPeer();
926     if ( wxpeer == NULL )
927         return;
928
929     wxDropTarget* target = wxpeer->GetDropTarget();
930     if ( target == NULL )
931         return;
932
933     PasteboardRef pboardRef;
934     PasteboardCreate((CFStringRef)[pboard name], &pboardRef);
935     target->SetCurrentDragPasteboard(pboardRef);
936     target->OnLeave();
937     CFRelease(pboardRef);
938  }
939
940 unsigned int wxWidgetCocoaImpl::draggingUpdated(void* s, WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd))
941 {
942     id <NSDraggingInfo>sender = (id <NSDraggingInfo>) s;
943     NSPasteboard *pboard = [sender draggingPasteboard];
944     NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
945
946     wxWindow* wxpeer = GetWXPeer();
947     if ( wxpeer == NULL )
948         return NSDragOperationNone;
949
950     wxDropTarget* target = wxpeer->GetDropTarget();
951     if ( target == NULL )
952         return NSDragOperationNone;
953
954     wxDragResult result = wxDragNone;
955     NSPoint nspoint = [m_osxView convertPoint:[sender draggingLocation] fromView:nil];
956     wxPoint pt = wxFromNSPoint( m_osxView, nspoint );
957
958     if ( sourceDragMask & NSDragOperationLink )
959         result = wxDragLink;
960     else if ( sourceDragMask & NSDragOperationCopy )
961         result = wxDragCopy;
962     else if ( sourceDragMask & NSDragOperationMove )
963         result = wxDragMove;
964     
965     PasteboardRef pboardRef;
966     PasteboardCreate((CFStringRef)[pboard name], &pboardRef);
967     target->SetCurrentDragPasteboard(pboardRef);
968     result = target->OnDragOver(pt.x, pt.y, result);
969     CFRelease(pboardRef);
970
971     NSDragOperation nsresult = NSDragOperationNone;
972     switch (result )
973     {
974         case wxDragLink:
975             nsresult = NSDragOperationLink;
976         case wxDragMove:
977             nsresult = NSDragOperationMove;
978         case wxDragCopy:
979             nsresult = NSDragOperationCopy;
980         default :
981             break;
982     }
983     return nsresult;
984 }
985
986 bool wxWidgetCocoaImpl::performDragOperation(void* s, WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd))
987 {
988     id <NSDraggingInfo>sender = (id <NSDraggingInfo>) s;
989
990     NSPasteboard *pboard = [sender draggingPasteboard];
991     NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
992
993     wxWindow* wxpeer = GetWXPeer();
994     wxDropTarget* target = wxpeer->GetDropTarget();
995     wxDragResult result = wxDragNone;
996     NSPoint nspoint = [m_osxView convertPoint:[sender draggingLocation] fromView:nil];
997     wxPoint pt = wxFromNSPoint( m_osxView, nspoint );
998
999     if ( sourceDragMask & NSDragOperationLink )
1000         result = wxDragLink;
1001     else if ( sourceDragMask & NSDragOperationCopy )
1002         result = wxDragCopy;
1003     else if ( sourceDragMask & NSDragOperationMove )
1004         result = wxDragMove;
1005
1006     PasteboardRef pboardRef;
1007     PasteboardCreate((CFStringRef)[pboard name], &pboardRef);
1008     target->SetCurrentDragPasteboard(pboardRef);
1009
1010     if (target->OnDrop(pt.x, pt.y))
1011         result = target->OnData(pt.x, pt.y, result);
1012
1013     CFRelease(pboardRef);
1014
1015     return result != wxDragNone;
1016 }
1017
1018 typedef void (*wxOSX_TextEventHandlerPtr)(NSView* self, SEL _cmd, NSString *event);
1019 typedef void (*wxOSX_EventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event);
1020 typedef BOOL (*wxOSX_PerformKeyEventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event);
1021 typedef BOOL (*wxOSX_FocusHandlerPtr)(NSView* self, SEL _cmd);
1022 typedef BOOL (*wxOSX_ResetCursorRectsHandlerPtr)(NSView* self, SEL _cmd);
1023
1024 void wxWidgetCocoaImpl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
1025 {
1026     if ( !DoHandleMouseEvent(event) )
1027     {
1028         // for plain NSView mouse events would propagate to parents otherwise
1029         if (!IsUserPane())
1030         {
1031             wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1032             superimpl(slf, (SEL)_cmd, event);
1033             
1034             // super of built-ins keeps the mouse up, as wx expects this event, we have to synthesize it
1035             
1036             if ( [ event type]  == NSLeftMouseDown )
1037             {
1038                 wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
1039                 SetupMouseEvent(wxevent , event) ;
1040                 wxevent.SetEventType(wxEVT_LEFT_UP);
1041                 
1042                 GetWXPeer()->HandleWindowEvent(wxevent);
1043             }
1044         }
1045     }
1046 }
1047
1048 void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
1049 {
1050     if ( [event type] == NSKeyDown )
1051     {
1052         // there are key equivalents that are not command-combos and therefore not handled by cocoa automatically, 
1053         // therefore we call the menubar directly here, exit if the menu is handling the shortcut
1054         if ( [[[NSApplication sharedApplication] mainMenu] performKeyEquivalent:event] )
1055             return;
1056     
1057         m_lastKeyDownEvent = event;
1058     }
1059     
1060     if ( GetFocusedViewInWindow([slf window]) != slf || m_hasEditor || !DoHandleKeyEvent(event) )
1061     {
1062         wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1063         superimpl(slf, (SEL)_cmd, event);
1064     }
1065     m_lastKeyDownEvent = NULL;
1066 }
1067
1068 void wxWidgetCocoaImpl::insertText(NSString* text, WXWidget slf, void *_cmd)
1069 {
1070     if ( m_lastKeyDownEvent==NULL || m_hasEditor || !DoHandleCharEvent(m_lastKeyDownEvent, text) )
1071     {
1072         wxOSX_TextEventHandlerPtr superimpl = (wxOSX_TextEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1073         superimpl(slf, (SEL)_cmd, text);
1074     }
1075 }
1076
1077
1078 bool wxWidgetCocoaImpl::performKeyEquivalent(WX_NSEvent event, WXWidget slf, void *_cmd)
1079 {
1080     bool handled = false;
1081     
1082     wxKeyEvent wxevent(wxEVT_KEY_DOWN);
1083     SetupKeyEvent( wxevent, event );
1084    
1085     // because performKeyEquivalent is going up the entire view hierarchy, we don't have to
1086     // walk up the ancestors ourselves but let cocoa do it
1087     
1088     int command = m_wxPeer->GetAcceleratorTable()->GetCommand( wxevent );
1089     if (command != -1)
1090     {
1091         wxEvtHandler * const handler = m_wxPeer->GetEventHandler();
1092         
1093         wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1094         command_event.SetEventObject( wxevent.GetEventObject() );
1095         handled = handler->ProcessEvent( command_event );
1096         
1097         if ( !handled )
1098         {
1099             // accelerators can also be used with buttons, try them too
1100             command_event.SetEventType(wxEVT_COMMAND_BUTTON_CLICKED);
1101             handled = handler->ProcessEvent( command_event );
1102         }
1103     }
1104     
1105     if ( !handled )
1106     {
1107         wxOSX_PerformKeyEventHandlerPtr superimpl = (wxOSX_PerformKeyEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1108         return superimpl(slf, (SEL)_cmd, event);
1109     }
1110     return YES;
1111 }
1112
1113 bool wxWidgetCocoaImpl::acceptsFirstResponder(WXWidget slf, void *_cmd)
1114 {
1115     if ( IsUserPane() )
1116         return m_wxPeer->AcceptsFocus();
1117     else
1118     {
1119         wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1120         return superimpl(slf, (SEL)_cmd);
1121     }
1122 }
1123
1124 bool wxWidgetCocoaImpl::becomeFirstResponder(WXWidget slf, void *_cmd)
1125 {
1126     wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1127     // get the current focus before running becomeFirstResponder
1128     NSView* otherView = FindFocus();
1129
1130     wxWidgetImpl* otherWindow = FindFromWXWidget(otherView);
1131     BOOL r = superimpl(slf, (SEL)_cmd);
1132     if ( r )
1133     {
1134         DoNotifyFocusEvent( true, otherWindow );
1135     }
1136
1137     return r;
1138 }
1139
1140 bool wxWidgetCocoaImpl::resignFirstResponder(WXWidget slf, void *_cmd)
1141 {
1142     wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1143     BOOL r = superimpl(slf, (SEL)_cmd);
1144     // get the current focus after running resignFirstResponder
1145     // note that this value isn't reliable, it might return the same view that
1146     // is resigning
1147     NSView* otherView = FindFocus();
1148     wxWidgetImpl* otherWindow = FindFromWXWidget(otherView);
1149
1150     // It doesn't make sense to notify about the loss of focus if we're not
1151     // really losing it and the window which has just gained focus is the same
1152     // one as this window itself. Of course, this should never happen in the
1153     // first place but somehow it does in wxGrid code and without this check we
1154     // enter into an infinite recursion, see #12267.
1155     if ( otherWindow == this )
1156         return r;
1157
1158     // NSTextViews have an editor as true responder, therefore the might get the
1159     // resign notification if their editor takes over, don't trigger any event then
1160     if ( r && !m_hasEditor)
1161     {
1162         DoNotifyFocusEvent( false, otherWindow );
1163     }
1164     return r;
1165 }
1166
1167 void wxWidgetCocoaImpl::resetCursorRects(WXWidget slf, void *_cmd)
1168 {
1169     wxWindow* wxpeer = GetWXPeer();
1170     if ( wxpeer )
1171     {
1172         NSCursor *cursor = (NSCursor*)wxpeer->GetCursor().GetHCURSOR();
1173         if (cursor == NULL)
1174         {
1175             wxOSX_ResetCursorRectsHandlerPtr superimpl = (wxOSX_ResetCursorRectsHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1176             superimpl(slf, (SEL)_cmd);
1177         }
1178         else
1179         {
1180             [slf addCursorRect: [slf bounds]
1181                 cursor: cursor];
1182         }
1183     }
1184 }
1185
1186 bool wxWidgetCocoaImpl::isFlipped(WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd))
1187 {
1188     return m_isFlipped;
1189 }
1190
1191
1192 #define OSX_DEBUG_DRAWING 0
1193
1194 void wxWidgetCocoaImpl::drawRect(void* rect, WXWidget slf, void *WXUNUSED(_cmd))
1195 {
1196     // preparing the update region
1197     
1198     wxRegion updateRgn;
1199     const NSRect *rects;
1200     NSInteger count;
1201
1202     [slf getRectsBeingDrawn:&rects count:&count];
1203     for ( int i = 0 ; i < count ; ++i )
1204     {
1205         updateRgn.Union(wxFromNSRect(slf, rects[i]));
1206     }
1207
1208     wxWindow* wxpeer = GetWXPeer();
1209
1210     if ( wxpeer->MacGetLeftBorderSize() != 0 || wxpeer->MacGetTopBorderSize() != 0 )
1211     {
1212         // as this update region is in native window locals we must adapt it to wx window local
1213         updateRgn.Offset( wxpeer->MacGetLeftBorderSize() , wxpeer->MacGetTopBorderSize() );
1214     }
1215     
1216     // Restrict the update region to the shape of the window, if any, and also
1217     // remember the region that we need to clear later.
1218     wxNonOwnedWindow* const tlwParent = wxpeer->MacGetTopLevelWindow();
1219     const bool isTopLevel = tlwParent == wxpeer;
1220     wxRegion clearRgn;
1221     if ( tlwParent->GetWindowStyle() & wxFRAME_SHAPED )
1222     {
1223         if ( isTopLevel )
1224             clearRgn = updateRgn;
1225
1226         int xoffset = 0, yoffset = 0;
1227         wxRegion rgn = tlwParent->GetShape();
1228         wxpeer->MacRootWindowToWindow( &xoffset, &yoffset );
1229         rgn.Offset( xoffset, yoffset );
1230         updateRgn.Intersect(rgn);
1231
1232         if ( isTopLevel )
1233         {
1234             // Exclude the window shape from the region to be cleared below.
1235             rgn.Xor(wxpeer->GetSize());
1236             clearRgn.Intersect(rgn);
1237         }
1238     }
1239     
1240     wxpeer->GetUpdateRegion() = updateRgn;
1241
1242     // setting up the drawing context
1243     
1244     CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
1245     CGContextSaveGState( context );
1246     
1247 #if OSX_DEBUG_DRAWING
1248     CGContextBeginPath( context );
1249     CGContextMoveToPoint(context, 0, 0);
1250     NSRect bounds = [slf bounds];
1251     CGContextAddLineToPoint(context, 10, 0);
1252     CGContextMoveToPoint(context, 0, 0);
1253     CGContextAddLineToPoint(context, 0, 10);
1254     CGContextMoveToPoint(context, bounds.size.width, bounds.size.height);
1255     CGContextAddLineToPoint(context, bounds.size.width, bounds.size.height-10);
1256     CGContextMoveToPoint(context, bounds.size.width, bounds.size.height);
1257     CGContextAddLineToPoint(context, bounds.size.width-10, bounds.size.height);
1258     CGContextClosePath( context );
1259     CGContextStrokePath(context);
1260 #endif
1261     
1262     if ( !m_isFlipped )
1263     {
1264         CGContextTranslateCTM( context, 0,  [m_osxView bounds].size.height );
1265         CGContextScaleCTM( context, 1, -1 );
1266     }
1267     
1268     wxpeer->MacSetCGContextRef( context );
1269
1270     bool handled = wxpeer->MacDoRedraw( 0 );
1271     CGContextRestoreGState( context );
1272
1273     CGContextSaveGState( context );
1274     if ( !handled )
1275     {
1276         // call super
1277         SEL _cmd = @selector(drawRect:);
1278         wxOSX_DrawRectHandlerPtr superimpl = (wxOSX_DrawRectHandlerPtr) [[slf superclass] instanceMethodForSelector:_cmd];
1279         superimpl(slf, _cmd, *(NSRect*)rect);
1280         CGContextRestoreGState( context );
1281         CGContextSaveGState( context );
1282     }
1283     // as we called restore above, we have to flip again if necessary
1284     if ( !m_isFlipped )
1285     {
1286         CGContextTranslateCTM( context, 0,  [m_osxView bounds].size.height );
1287         CGContextScaleCTM( context, 1, -1 );
1288     }
1289
1290     if ( isTopLevel )
1291     {
1292         // We also need to explicitly draw the part of the top level window
1293         // outside of its region with transparent colour to ensure that it is
1294         // really transparent.
1295         if ( clearRgn.IsOk() )
1296         {
1297             wxMacCGContextStateSaver saveState(context);
1298             wxWindowDC dc(wxpeer);
1299             dc.SetBackground(wxBrush(wxTransparentColour));
1300             dc.SetDeviceClippingRegion(clearRgn);
1301             dc.Clear();
1302         }
1303
1304 #if wxUSE_GRAPHICS_CONTEXT
1305         // If the window shape is defined by a path, stroke the path to show
1306         // the window border.
1307         const wxGraphicsPath& path = tlwParent->GetShapePath();
1308         if ( !path.IsNull() )
1309         {
1310             CGContextSetLineWidth(context, 1);
1311             CGContextSetStrokeColorWithColor(context, wxLIGHT_GREY->GetCGColor());
1312             CGContextAddPath(context, (CGPathRef) path.GetNativePath());
1313             CGContextStrokePath(context);
1314         }
1315 #endif // wxUSE_GRAPHICS_CONTEXT
1316     }
1317
1318     wxpeer->MacPaintChildrenBorders();
1319     wxpeer->MacSetCGContextRef( NULL );
1320     CGContextRestoreGState( context );
1321 }
1322
1323 void wxWidgetCocoaImpl::controlAction( WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd), void *WXUNUSED(sender))
1324 {
1325     wxWindow* wxpeer = (wxWindow*) GetWXPeer();
1326     if ( wxpeer )
1327         wxpeer->OSXHandleClicked(0);
1328 }
1329
1330 void wxWidgetCocoaImpl::controlDoubleAction( WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd), void *WXUNUSED(sender))
1331 {
1332 }
1333
1334 void wxWidgetCocoaImpl::controlTextDidChange()
1335 {
1336     wxWindow* wxpeer = (wxWindow*)GetWXPeer();
1337     if ( wxpeer ) 
1338     {
1339         // since native rtti doesn't have to be enabled and wx' rtti is not aware of the mixin wxTextEntry, workaround is needed
1340         wxTextCtrl *tc = wxDynamicCast( wxpeer , wxTextCtrl );
1341         wxComboBox *cb = wxDynamicCast( wxpeer , wxComboBox );
1342         if ( tc )
1343             tc->SendTextUpdatedEventIfAllowed();
1344         else if ( cb )
1345             cb->SendTextUpdatedEventIfAllowed();
1346         else 
1347         {
1348             wxFAIL_MSG("Unexpected class for controlTextDidChange event");
1349         }
1350     }
1351 }
1352
1353 //
1354
1355 #if OBJC_API_VERSION >= 2
1356
1357 #define wxOSX_CLASS_ADD_METHOD( c, s, i, t ) \
1358     class_addMethod(c, s, i, t );
1359
1360 #else
1361
1362 #define wxOSX_CLASS_ADD_METHOD( c, s, i, t ) \
1363     { s, (char*) t, i },
1364
1365 #endif
1366
1367 void wxOSXCocoaClassAddWXMethods(Class c)
1368 {
1369
1370 #if OBJC_API_VERSION < 2
1371     static objc_method wxmethods[] =
1372     {
1373 #endif
1374
1375     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseDown:), (IMP) wxOSX_mouseEvent, "v@:@" )
1376     wxOSX_CLASS_ADD_METHOD(c, @selector(rightMouseDown:), (IMP) wxOSX_mouseEvent, "v@:@" )
1377     wxOSX_CLASS_ADD_METHOD(c, @selector(otherMouseDown:), (IMP) wxOSX_mouseEvent, "v@:@" )
1378
1379     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseUp:), (IMP) wxOSX_mouseEvent, "v@:@" )
1380     wxOSX_CLASS_ADD_METHOD(c, @selector(rightMouseUp:), (IMP) wxOSX_mouseEvent, "v@:@" )
1381     wxOSX_CLASS_ADD_METHOD(c, @selector(otherMouseUp:), (IMP) wxOSX_mouseEvent, "v@:@" )
1382
1383     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseMoved:), (IMP) wxOSX_mouseEvent, "v@:@" )
1384
1385     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseDragged:), (IMP) wxOSX_mouseEvent, "v@:@" )
1386     wxOSX_CLASS_ADD_METHOD(c, @selector(rightMouseDragged:), (IMP) wxOSX_mouseEvent, "v@:@" )
1387     wxOSX_CLASS_ADD_METHOD(c, @selector(otherMouseDragged:), (IMP) wxOSX_mouseEvent, "v@:@" )
1388     
1389     wxOSX_CLASS_ADD_METHOD(c, @selector(acceptsFirstMouse:), (IMP) wxOSX_acceptsFirstMouse, "v@:@" )
1390
1391     wxOSX_CLASS_ADD_METHOD(c, @selector(scrollWheel:), (IMP) wxOSX_mouseEvent, "v@:@" )
1392     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseEntered:), (IMP) wxOSX_mouseEvent, "v@:@" )
1393     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseExited:), (IMP) wxOSX_mouseEvent, "v@:@" )
1394
1395     wxOSX_CLASS_ADD_METHOD(c, @selector(keyDown:), (IMP) wxOSX_keyEvent, "v@:@" )
1396     wxOSX_CLASS_ADD_METHOD(c, @selector(keyUp:), (IMP) wxOSX_keyEvent, "v@:@" )
1397     wxOSX_CLASS_ADD_METHOD(c, @selector(flagsChanged:), (IMP) wxOSX_keyEvent, "v@:@" )
1398
1399     wxOSX_CLASS_ADD_METHOD(c, @selector(insertText:), (IMP) wxOSX_insertText, "v@:@" )
1400
1401     wxOSX_CLASS_ADD_METHOD(c, @selector(performKeyEquivalent:), (IMP) wxOSX_performKeyEquivalent, "c@:@" )
1402
1403     wxOSX_CLASS_ADD_METHOD(c, @selector(acceptsFirstResponder), (IMP) wxOSX_acceptsFirstResponder, "c@:" )
1404     wxOSX_CLASS_ADD_METHOD(c, @selector(becomeFirstResponder), (IMP) wxOSX_becomeFirstResponder, "c@:" )
1405     wxOSX_CLASS_ADD_METHOD(c, @selector(resignFirstResponder), (IMP) wxOSX_resignFirstResponder, "c@:" )
1406     wxOSX_CLASS_ADD_METHOD(c, @selector(resetCursorRects), (IMP) wxOSX_resetCursorRects, "v@:" )
1407
1408     wxOSX_CLASS_ADD_METHOD(c, @selector(isFlipped), (IMP) wxOSX_isFlipped, "c@:" )
1409     wxOSX_CLASS_ADD_METHOD(c, @selector(drawRect:), (IMP) wxOSX_drawRect, "v@:{_NSRect={_NSPoint=ff}{_NSSize=ff}}" )
1410
1411     wxOSX_CLASS_ADD_METHOD(c, @selector(controlAction:), (IMP) wxOSX_controlAction, "v@:@" )
1412     wxOSX_CLASS_ADD_METHOD(c, @selector(controlDoubleAction:), (IMP) wxOSX_controlDoubleAction, "v@:@" )
1413
1414 #if wxUSE_DRAG_AND_DROP
1415     wxOSX_CLASS_ADD_METHOD(c, @selector(draggingEntered:), (IMP) wxOSX_draggingEntered, "I@:@" )
1416     wxOSX_CLASS_ADD_METHOD(c, @selector(draggingUpdated:), (IMP) wxOSX_draggingUpdated, "I@:@" )
1417     wxOSX_CLASS_ADD_METHOD(c, @selector(draggingExited:), (IMP) wxOSX_draggingExited, "v@:@" )
1418     wxOSX_CLASS_ADD_METHOD(c, @selector(performDragOperation:), (IMP) wxOSX_performDragOperation, "c@:@" )
1419 #endif
1420
1421 #if OBJC_API_VERSION < 2
1422     } ;
1423     static int method_count = WXSIZEOF( wxmethods );
1424     static objc_method_list *wxmethodlist = NULL;
1425     if ( wxmethodlist == NULL )
1426     {
1427         wxmethodlist = (objc_method_list*) malloc(sizeof(objc_method_list) + sizeof(wxmethods) );
1428         memcpy( &wxmethodlist->method_list[0], &wxmethods[0], sizeof(wxmethods) );
1429         wxmethodlist->method_count = method_count;
1430         wxmethodlist->obsolete = 0;
1431     }
1432     class_addMethods( c, wxmethodlist );
1433 #endif
1434 }
1435
1436 //
1437 // C++ implementation class
1438 //
1439
1440 IMPLEMENT_DYNAMIC_CLASS( wxWidgetCocoaImpl , wxWidgetImpl )
1441
1442 wxWidgetCocoaImpl::wxWidgetCocoaImpl( wxWindowMac* peer , WXWidget w, bool isRootControl, bool isUserPane ) :
1443     wxWidgetImpl( peer, isRootControl, isUserPane )
1444 {
1445     Init();
1446     m_osxView = w;
1447
1448     // check if the user wants to create the control initially hidden
1449     if ( !peer->IsShown() )
1450         SetVisibility(false);
1451
1452     // gc aware handling
1453     if ( m_osxView )
1454         CFRetain(m_osxView);
1455     [m_osxView release];
1456 }
1457
1458 wxWidgetCocoaImpl::wxWidgetCocoaImpl()
1459 {
1460     Init();
1461 }
1462
1463 void wxWidgetCocoaImpl::Init()
1464 {
1465     m_osxView = NULL;
1466     m_isFlipped = true;
1467     m_lastKeyDownEvent = NULL;
1468     m_hasEditor = false;
1469 }
1470
1471 wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
1472 {
1473     RemoveAssociations( this );
1474
1475     if ( !IsRootControl() )
1476     {
1477         NSView *sv = [m_osxView superview];
1478         if ( sv != nil )
1479             [m_osxView removeFromSuperview];
1480     }
1481     // gc aware handling
1482     if ( m_osxView )
1483         CFRelease(m_osxView);
1484 }
1485
1486 bool wxWidgetCocoaImpl::IsVisible() const
1487 {
1488     return [m_osxView isHiddenOrHasHiddenAncestor] == NO;
1489 }
1490
1491 void wxWidgetCocoaImpl::SetVisibility( bool visible )
1492 {
1493     [m_osxView setHidden:(visible ? NO:YES)];
1494 }
1495
1496 // ----------------------------------------------------------------------------
1497 // window animation stuff
1498 // ----------------------------------------------------------------------------
1499
1500 // define a delegate used to refresh the window during animation
1501 @interface wxNSAnimationDelegate : NSObject wxOSX_10_6_AND_LATER(<NSAnimationDelegate>)
1502 {
1503     wxWindow *m_win;
1504     bool m_isDone;
1505 }
1506
1507 - (id)init:(wxWindow *)win;
1508
1509 - (bool)isDone;
1510
1511 // NSAnimationDelegate methods
1512 - (void)animationDidEnd:(NSAnimation*)animation;
1513 - (void)animation:(NSAnimation*)animation
1514         didReachProgressMark:(NSAnimationProgress)progress;
1515 @end
1516
1517 @implementation wxNSAnimationDelegate
1518
1519 - (id)init:(wxWindow *)win
1520 {
1521     self = [super init];
1522
1523     m_win = win;
1524     m_isDone = false;
1525
1526     return self;
1527 }
1528
1529 - (bool)isDone
1530 {
1531     return m_isDone;
1532 }
1533
1534 - (void)animation:(NSAnimation*)animation
1535         didReachProgressMark:(NSAnimationProgress)progress
1536 {
1537     wxUnusedVar(animation);
1538     wxUnusedVar(progress);
1539
1540     m_win->SendSizeEvent();
1541 }
1542
1543 - (void)animationDidEnd:(NSAnimation*)animation
1544 {
1545     wxUnusedVar(animation);
1546     m_isDone = true;
1547 }
1548
1549 @end
1550
1551 /* static */
1552 bool
1553 wxWidgetCocoaImpl::ShowViewOrWindowWithEffect(wxWindow *win,
1554                                               bool show,
1555                                               wxShowEffect effect,
1556                                               unsigned timeout)
1557 {
1558     // create the dictionary describing the animation to perform on this view
1559     NSObject * const
1560         viewOrWin = static_cast<NSObject *>(win->OSXGetViewOrWindow());
1561     NSMutableDictionary * const
1562         dict = [NSMutableDictionary dictionaryWithCapacity:4];
1563     [dict setObject:viewOrWin forKey:NSViewAnimationTargetKey];
1564
1565     // determine the start and end rectangles assuming we're hiding the window
1566     const wxRect rectOrig = win->GetRect();
1567     wxRect rectStart,
1568            rectEnd;
1569     rectStart =
1570     rectEnd = rectOrig;
1571
1572     if ( show )
1573     {
1574         if ( effect == wxSHOW_EFFECT_ROLL_TO_LEFT ||
1575                 effect == wxSHOW_EFFECT_SLIDE_TO_LEFT )
1576             effect = wxSHOW_EFFECT_ROLL_TO_RIGHT;
1577         else if ( effect == wxSHOW_EFFECT_ROLL_TO_RIGHT ||
1578                     effect == wxSHOW_EFFECT_SLIDE_TO_RIGHT )
1579             effect = wxSHOW_EFFECT_ROLL_TO_LEFT;
1580         else if ( effect == wxSHOW_EFFECT_ROLL_TO_TOP ||
1581                     effect == wxSHOW_EFFECT_SLIDE_TO_TOP )
1582             effect = wxSHOW_EFFECT_ROLL_TO_BOTTOM;
1583         else if ( effect == wxSHOW_EFFECT_ROLL_TO_BOTTOM ||
1584                     effect == wxSHOW_EFFECT_SLIDE_TO_BOTTOM )
1585             effect = wxSHOW_EFFECT_ROLL_TO_TOP;
1586     }
1587
1588     switch ( effect )
1589     {
1590         case wxSHOW_EFFECT_ROLL_TO_LEFT:
1591         case wxSHOW_EFFECT_SLIDE_TO_LEFT:
1592             rectEnd.width = 0;
1593             break;
1594
1595         case wxSHOW_EFFECT_ROLL_TO_RIGHT:
1596         case wxSHOW_EFFECT_SLIDE_TO_RIGHT:
1597             rectEnd.x = rectStart.GetRight();
1598             rectEnd.width = 0;
1599             break;
1600
1601         case wxSHOW_EFFECT_ROLL_TO_TOP:
1602         case wxSHOW_EFFECT_SLIDE_TO_TOP:
1603             rectEnd.height = 0;
1604             break;
1605
1606         case wxSHOW_EFFECT_ROLL_TO_BOTTOM:
1607         case wxSHOW_EFFECT_SLIDE_TO_BOTTOM:
1608             rectEnd.y = rectStart.GetBottom();
1609             rectEnd.height = 0;
1610             break;
1611
1612         case wxSHOW_EFFECT_EXPAND:
1613             rectEnd.x = rectStart.x + rectStart.width / 2;
1614             rectEnd.y = rectStart.y + rectStart.height / 2;
1615             rectEnd.width =
1616             rectEnd.height = 0;
1617             break;
1618
1619         case wxSHOW_EFFECT_BLEND:
1620             [dict setObject:(show ? NSViewAnimationFadeInEffect
1621                                   : NSViewAnimationFadeOutEffect)
1622                   forKey:NSViewAnimationEffectKey];
1623             break;
1624
1625         case wxSHOW_EFFECT_NONE:
1626         case wxSHOW_EFFECT_MAX:
1627             wxFAIL_MSG( "unexpected animation effect" );
1628             return false;
1629
1630         default:
1631             wxFAIL_MSG( "unknown animation effect" );
1632             return false;
1633     };
1634
1635     if ( show )
1636     {
1637         // we need to restore it to the original rectangle instead of making it
1638         // disappear
1639         wxSwap(rectStart, rectEnd);
1640
1641         // and as the window is currently hidden, we need to show it for the
1642         // animation to be visible at all (but don't restore it at its full
1643         // rectangle as it shouldn't appear immediately)
1644         win->SetSize(rectStart);
1645         win->Show();
1646     }
1647
1648     NSView * const parentView = [viewOrWin isKindOfClass:[NSView class]]
1649                                     ? [(NSView *)viewOrWin superview]
1650                                     : nil;
1651     const NSRect rStart = wxToNSRect(parentView, rectStart);
1652     const NSRect rEnd = wxToNSRect(parentView, rectEnd);
1653
1654     [dict setObject:[NSValue valueWithRect:rStart]
1655           forKey:NSViewAnimationStartFrameKey];
1656     [dict setObject:[NSValue valueWithRect:rEnd]
1657           forKey:NSViewAnimationEndFrameKey];
1658
1659     // create an animation using the values in the above dictionary
1660     NSViewAnimation * const
1661         anim = [[NSViewAnimation alloc]
1662                 initWithViewAnimations:[NSArray arrayWithObject:dict]];
1663
1664     if ( !timeout )
1665     {
1666         // what is a good default duration? Windows uses 200ms, Web frameworks
1667         // use anything from 250ms to 1s... choose something in the middle
1668         timeout = 500;
1669     }
1670
1671     [anim setDuration:timeout/1000.];   // duration is in seconds here
1672
1673     // if the window being animated changes its layout depending on its size
1674     // (which is almost always the case) we need to redo it during animation
1675     //
1676     // the number of layouts here is arbitrary, but 10 seems like too few (e.g.
1677     // controls in wxInfoBar visibly jump around)
1678     const int NUM_LAYOUTS = 20;
1679     for ( float f = 1./NUM_LAYOUTS; f < 1.; f += 1./NUM_LAYOUTS )
1680         [anim addProgressMark:f];
1681
1682     wxNSAnimationDelegate * const
1683         animDelegate = [[wxNSAnimationDelegate alloc] init:win];
1684     [anim setDelegate:animDelegate];
1685     [anim startAnimation];
1686
1687     // Cocoa is capable of doing animation asynchronously or even from separate
1688     // thread but wx API doesn't provide any way to be notified about the
1689     // animation end and without this we really must ensure that the window has
1690     // the expected (i.e. the same as if a simple Show() had been used) size
1691     // when we return, so block here until the animation finishes
1692     //
1693     // notice that because the default animation mode is NSAnimationBlocking,
1694     // no user input events ought to be processed from here
1695     {
1696         wxEventLoopGuarantor ensureEventLoopExistence;
1697         wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
1698         while ( ![animDelegate isDone] )
1699             loop->Dispatch();
1700     }
1701
1702     if ( !show )
1703     {
1704         // NSViewAnimation is smart enough to hide the NSView being animated at
1705         // the end but we also must ensure that it's hidden for wx too
1706         win->Hide();
1707
1708         // and we must also restore its size because it isn't expected to
1709         // change just because the window was hidden
1710         win->SetSize(rectOrig);
1711     }
1712     else
1713     {
1714         // refresh it once again after the end to ensure that everything is in
1715         // place
1716         win->SendSizeEvent();
1717     }
1718
1719     [anim setDelegate:nil];
1720     [animDelegate release];
1721     [anim release];
1722
1723     return true;
1724 }
1725
1726 bool wxWidgetCocoaImpl::ShowWithEffect(bool show,
1727                                        wxShowEffect effect,
1728                                        unsigned timeout)
1729 {
1730     return ShowViewOrWindowWithEffect(m_wxPeer, show, effect, timeout);
1731 }
1732
1733 /* note that the drawing order between siblings is not defined under 10.4 */
1734 /* only starting from 10.5 the subview order is respected */
1735
1736 /* NSComparisonResult is typedef'd as an enum pre-Leopard but typedef'd as
1737  * NSInteger post-Leopard.  Pre-Leopard the Cocoa toolkit expects a function
1738  * returning int and not NSComparisonResult.  Post-Leopard the Cocoa toolkit
1739  * expects a function returning the new non-enum NSComparsionResult.
1740  * Hence we create a typedef named CocoaWindowCompareFunctionResult.
1741  */
1742 #if defined(NSINTEGER_DEFINED)
1743 typedef NSComparisonResult CocoaWindowCompareFunctionResult;
1744 #else
1745 typedef int CocoaWindowCompareFunctionResult;
1746 #endif
1747
1748 class CocoaWindowCompareContext
1749 {
1750     wxDECLARE_NO_COPY_CLASS(CocoaWindowCompareContext);
1751 public:
1752     CocoaWindowCompareContext(); // Not implemented
1753     CocoaWindowCompareContext(NSView *target, NSArray *subviews)
1754     {
1755         m_target = target;
1756         // Cocoa sorts subviews in-place.. make a copy
1757         m_subviews = [subviews copy];
1758     }
1759     
1760     ~CocoaWindowCompareContext()
1761     {   // release the copy
1762         [m_subviews release];
1763     }
1764     NSView* target()
1765     {   return m_target; }
1766     
1767     NSArray* subviews()
1768     {   return m_subviews; }
1769     
1770     /* Helper function that returns the comparison based off of the original ordering */
1771     CocoaWindowCompareFunctionResult CompareUsingOriginalOrdering(id first, id second)
1772     {
1773         NSUInteger firstI = [m_subviews indexOfObjectIdenticalTo:first];
1774         NSUInteger secondI = [m_subviews indexOfObjectIdenticalTo:second];
1775         // NOTE: If either firstI or secondI is NSNotFound then it will be NSIntegerMax and thus will
1776         // likely compare higher than the other view which is reasonable considering the only way that
1777         // can happen is if the subview was added after our call to subviews but before the call to
1778         // sortSubviewsUsingFunction:context:.  Thus we don't bother checking.  Particularly because
1779         // that case should never occur anyway because that would imply a multi-threaded GUI call
1780         // which is a big no-no with Cocoa.
1781                 
1782         // Subviews are ordered from back to front meaning one that is already lower will have an lower index.
1783         NSComparisonResult result = (firstI < secondI)
1784                 ?   NSOrderedAscending /* -1 */
1785                 :   (firstI > secondI)
1786                 ?   NSOrderedDescending /* 1 */
1787                 :   NSOrderedSame /* 0 */;
1788                 
1789         return result;
1790     }
1791 private:
1792     /* The subview we are trying to Raise or Lower */
1793     NSView *m_target;
1794     /* A copy of the original array of subviews */
1795     NSArray *m_subviews;
1796 };
1797
1798 /* Causes Cocoa to raise the target view to the top of the Z-Order by telling the sort function that
1799  * the target view is always higher than every other view.  When comparing two views neither of
1800  * which is the target, it returns the correct response based on the original ordering
1801  */
1802 static CocoaWindowCompareFunctionResult CocoaRaiseWindowCompareFunction(id first, id second, void *ctx)
1803 {
1804     CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
1805     // first should be ordered higher
1806     if(first==compareContext->target())
1807         return NSOrderedDescending;
1808     // second should be ordered higher
1809     if(second==compareContext->target())
1810         return NSOrderedAscending;
1811     return compareContext->CompareUsingOriginalOrdering(first,second);
1812 }
1813
1814 void wxWidgetCocoaImpl::Raise()
1815 {
1816         NSView* nsview = m_osxView;
1817         
1818     NSView *superview = [nsview superview];
1819     CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1820         
1821     [superview sortSubviewsUsingFunction:
1822          CocoaRaiseWindowCompareFunction
1823                                                                  context: &compareContext];
1824         
1825 }
1826
1827 /* Causes Cocoa to lower the target view to the bottom of the Z-Order by telling the sort function that
1828  * the target view is always lower than every other view.  When comparing two views neither of
1829  * which is the target, it returns the correct response based on the original ordering
1830  */
1831 static CocoaWindowCompareFunctionResult CocoaLowerWindowCompareFunction(id first, id second, void *ctx)
1832 {
1833     CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
1834     // first should be ordered lower
1835     if(first==compareContext->target())
1836         return NSOrderedAscending;
1837     // second should be ordered lower
1838     if(second==compareContext->target())
1839         return NSOrderedDescending;
1840     return compareContext->CompareUsingOriginalOrdering(first,second);
1841 }
1842
1843 void wxWidgetCocoaImpl::Lower()
1844 {
1845         NSView* nsview = m_osxView;
1846         
1847     NSView *superview = [nsview superview];
1848     CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1849         
1850     [superview sortSubviewsUsingFunction:
1851          CocoaLowerWindowCompareFunction
1852                                                                  context: &compareContext];
1853 }
1854
1855 void wxWidgetCocoaImpl::ScrollRect( const wxRect *WXUNUSED(rect), int WXUNUSED(dx), int WXUNUSED(dy) )
1856 {
1857 #if 1
1858     SetNeedsDisplay() ;
1859 #else
1860     // We should do something like this, but it wasn't working in 10.4.
1861     if (GetNeedsDisplay() )
1862     {
1863         SetNeedsDisplay() ;
1864     }
1865     NSRect r = wxToNSRect( [m_osxView superview], *rect );
1866     NSSize offset = NSMakeSize((float)dx, (float)dy);
1867     [m_osxView scrollRect:r by:offset];
1868 #endif
1869 }
1870
1871 void wxWidgetCocoaImpl::Move(int x, int y, int width, int height)
1872 {
1873     wxWindowMac* parent = GetWXPeer()->GetParent();
1874     // under Cocoa we might have a contentView in the wxParent to which we have to
1875     // adjust the coordinates
1876     if (parent && [m_osxView superview] != parent->GetHandle() )
1877     {
1878         int cx = 0,cy = 0,cw = 0,ch = 0;
1879         if ( parent->GetPeer() )
1880         {
1881             parent->GetPeer()->GetContentArea(cx, cy, cw, ch);
1882             x -= cx;
1883             y -= cy;
1884         }
1885     }
1886     [[m_osxView superview] setNeedsDisplayInRect:[m_osxView frame]];
1887     NSRect r = wxToNSRect( [m_osxView superview], wxRect(x,y,width, height) );
1888     [m_osxView setFrame:r];
1889     [[m_osxView superview] setNeedsDisplayInRect:r];
1890
1891     wxNSView* wxview = (wxNSView*)m_osxView;
1892 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1893     if ([wxview respondsToSelector:@selector(updateTrackingArea)] )
1894         [wxview updateTrackingArea]; 
1895 #else
1896     if ([m_osxView respondsToSelector:@selector(trackingTag)] )
1897     {
1898         if ( [wxview trackingTag] )
1899             [wxview removeTrackingRect: [wxview trackingTag]];
1900
1901         [wxview setTrackingTag: [wxview addTrackingRect: [m_osxView bounds] owner: wxview userData: nil assumeInside: NO]];
1902     }
1903 #endif
1904 }
1905
1906 void wxWidgetCocoaImpl::GetPosition( int &x, int &y ) const
1907 {
1908     wxRect r = wxFromNSRect( [m_osxView superview], [m_osxView frame] );
1909     x = r.GetLeft();
1910     y = r.GetTop();
1911     
1912     // under Cocoa we might have a contentView in the wxParent to which we have to
1913     // adjust the coordinates
1914     wxWindowMac* parent = GetWXPeer()->GetParent();
1915     if (parent && [m_osxView superview] != parent->GetHandle() )
1916     {
1917         int cx = 0,cy = 0,cw = 0,ch = 0;
1918         if ( parent->GetPeer() )
1919         {
1920             parent->GetPeer()->GetContentArea(cx, cy, cw, ch);
1921             x += cx;
1922             y += cy;
1923         }
1924     }
1925 }
1926
1927 void wxWidgetCocoaImpl::GetSize( int &width, int &height ) const
1928 {
1929     NSRect rect = [m_osxView frame];
1930     width = (int)rect.size.width;
1931     height = (int)rect.size.height;
1932 }
1933
1934 void wxWidgetCocoaImpl::GetContentArea( int&left, int &top, int &width, int &height ) const
1935 {
1936     if ( [m_osxView respondsToSelector:@selector(contentView) ] )
1937     {
1938         NSView* cv = [m_osxView contentView];
1939
1940         NSRect bounds = [m_osxView bounds];
1941         NSRect rect = [cv frame];
1942
1943         int y = (int)rect.origin.y;
1944         int x = (int)rect.origin.x;
1945         if ( ![ m_osxView isFlipped ] )
1946             y = (int)(bounds.size.height - (rect.origin.y + rect.size.height));
1947         left = x;
1948         top = y;
1949         width = (int)rect.size.width;
1950         height = (int)rect.size.height;
1951     }
1952     else
1953     {
1954         left = top = 0;
1955         GetSize( width, height );
1956     }
1957 }
1958
1959 void wxWidgetCocoaImpl::SetNeedsDisplay( const wxRect* where )
1960 {
1961     if ( where )
1962         [m_osxView setNeedsDisplayInRect:wxToNSRect(m_osxView, *where )];
1963     else
1964         [m_osxView setNeedsDisplay:YES];
1965 }
1966
1967 bool wxWidgetCocoaImpl::GetNeedsDisplay() const
1968 {
1969     return [m_osxView needsDisplay];
1970 }
1971
1972 bool wxWidgetCocoaImpl::CanFocus() const
1973 {
1974     return [m_osxView canBecomeKeyView] == YES;
1975 }
1976
1977 bool wxWidgetCocoaImpl::HasFocus() const
1978 {
1979     return ( FindFocus() == m_osxView );
1980 }
1981
1982 bool wxWidgetCocoaImpl::SetFocus()
1983 {
1984     if ( !CanFocus() )
1985         return false;
1986
1987     [[m_osxView window] makeKeyAndOrderFront:nil] ;
1988     [[m_osxView window] makeFirstResponder: m_osxView] ;
1989     return true;
1990 }
1991
1992
1993 void wxWidgetCocoaImpl::RemoveFromParent()
1994 {
1995     [m_osxView removeFromSuperview];
1996 }
1997
1998 void wxWidgetCocoaImpl::Embed( wxWidgetImpl *parent )
1999 {
2000     NSView* container = parent->GetWXWidget() ;
2001     wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
2002     [container addSubview:m_osxView];
2003 }
2004
2005 void wxWidgetCocoaImpl::SetBackgroundColour( const wxColour &col )
2006 {
2007     NSView* targetView = m_osxView;
2008     if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
2009         targetView = [(NSScrollView*) m_osxView documentView];
2010
2011     if ( [targetView respondsToSelector:@selector(setBackgroundColor:) ] )
2012     {
2013         [targetView setBackgroundColor:[NSColor colorWithCalibratedRed:(CGFloat) (col.Red() / 255.0)
2014                                                                 green:(CGFloat) (col.Green() / 255.0)
2015                                                                  blue:(CGFloat) (col.Blue() / 255.0)
2016                                                                 alpha:(CGFloat) (col.Alpha() / 255.0)]];
2017     }
2018 }
2019
2020 bool wxWidgetCocoaImpl::SetBackgroundStyle( wxBackgroundStyle style )
2021 {
2022     BOOL opaque = ( style == wxBG_STYLE_PAINT );
2023     
2024     if ( [m_osxView respondsToSelector:@selector(setOpaque:) ] )
2025     {
2026         [m_osxView setOpaque: opaque];
2027     }
2028     
2029     return true ;
2030 }
2031
2032 void wxWidgetCocoaImpl::SetLabel( const wxString& title, wxFontEncoding encoding )
2033 {
2034     if ( [m_osxView respondsToSelector:@selector(setTitle:) ] )
2035     {
2036         wxCFStringRef cf( title , encoding );
2037         [m_osxView setTitle:cf.AsNSString()];
2038     }
2039     else if ( [m_osxView respondsToSelector:@selector(setStringValue:) ] )
2040     {
2041         wxCFStringRef cf( title , encoding );
2042         [m_osxView setStringValue:cf.AsNSString()];
2043     }
2044 }
2045
2046
2047 void  wxWidgetImpl::Convert( wxPoint *pt , wxWidgetImpl *from , wxWidgetImpl *to )
2048 {
2049     NSPoint p = wxToNSPoint( from->GetWXWidget(), *pt );
2050     p = [from->GetWXWidget() convertPoint:p toView:to->GetWXWidget() ];
2051     *pt = wxFromNSPoint( to->GetWXWidget(), p );
2052 }
2053
2054 wxInt32 wxWidgetCocoaImpl::GetValue() const
2055 {
2056     return [(NSControl*)m_osxView intValue];
2057 }
2058
2059 void wxWidgetCocoaImpl::SetValue( wxInt32 v )
2060 {
2061     if (  [m_osxView respondsToSelector:@selector(setIntValue:)] )
2062     {
2063         [m_osxView setIntValue:v];
2064     }
2065     else if (  [m_osxView respondsToSelector:@selector(setFloatValue:)] )
2066     {
2067         [m_osxView setFloatValue:(double)v];
2068     }
2069     else if (  [m_osxView respondsToSelector:@selector(setDoubleValue:)] )
2070     {
2071         [m_osxView setDoubleValue:(double)v];
2072     }
2073 }
2074
2075 void wxWidgetCocoaImpl::SetMinimum( wxInt32 v )
2076 {
2077     if (  [m_osxView respondsToSelector:@selector(setMinValue:)] )
2078     {
2079         [m_osxView setMinValue:(double)v];
2080     }
2081 }
2082
2083 void wxWidgetCocoaImpl::SetMaximum( wxInt32 v )
2084 {
2085     if (  [m_osxView respondsToSelector:@selector(setMaxValue:)] )
2086     {
2087         [m_osxView setMaxValue:(double)v];
2088     }
2089 }
2090
2091 wxInt32 wxWidgetCocoaImpl::GetMinimum() const
2092 {
2093     if (  [m_osxView respondsToSelector:@selector(minValue)] )
2094     {
2095         return (int)[m_osxView minValue];
2096     }
2097     return 0;
2098 }
2099
2100 wxInt32 wxWidgetCocoaImpl::GetMaximum() const
2101 {
2102     if (  [m_osxView respondsToSelector:@selector(maxValue)] )
2103     {
2104         return (int)[m_osxView maxValue];
2105     }
2106     return 0;
2107 }
2108
2109 wxBitmap wxWidgetCocoaImpl::GetBitmap() const
2110 {
2111     wxBitmap bmp;
2112
2113     // TODO: how to create a wxBitmap from NSImage?
2114 #if 0
2115     if ( [m_osxView respondsToSelector:@selector(image:)] )
2116         bmp = [m_osxView image];
2117 #endif
2118
2119     return bmp;
2120 }
2121
2122 void wxWidgetCocoaImpl::SetBitmap( const wxBitmap& bitmap )
2123 {
2124     if (  [m_osxView respondsToSelector:@selector(setImage:)] )
2125     {
2126         if (bitmap.IsOk())
2127             [m_osxView setImage:bitmap.GetNSImage()];
2128         else
2129             [m_osxView setImage:nil];
2130
2131         [m_osxView setNeedsDisplay:YES];
2132     }
2133 }
2134
2135 void wxWidgetCocoaImpl::SetBitmapPosition( wxDirection dir )
2136 {
2137     if ( [m_osxView respondsToSelector:@selector(setImagePosition:)] )
2138     {
2139         NSCellImagePosition pos;
2140         switch ( dir )
2141         {
2142             case wxLEFT:
2143                 pos = NSImageLeft;
2144                 break;
2145
2146             case wxRIGHT:
2147                 pos = NSImageRight;
2148                 break;
2149
2150             case wxTOP:
2151                 pos = NSImageAbove;
2152                 break;
2153
2154             case wxBOTTOM:
2155                 pos = NSImageBelow;
2156                 break;
2157
2158             default:
2159                 wxFAIL_MSG( "invalid image position" );
2160                 pos = NSNoImage;
2161         }
2162
2163         [m_osxView setImagePosition:pos];
2164     }
2165 }
2166
2167 void wxWidgetCocoaImpl::SetupTabs( const wxNotebook& WXUNUSED(notebook))
2168 {
2169     // implementation in subclass
2170 }
2171
2172 void wxWidgetCocoaImpl::GetBestRect( wxRect *r ) const
2173 {
2174     r->x = r->y = r->width = r->height = 0;
2175
2176     if (  [m_osxView respondsToSelector:@selector(sizeToFit)] )
2177     {
2178         NSRect former = [m_osxView frame];
2179         [m_osxView sizeToFit];
2180         NSRect best = [m_osxView frame];
2181         [m_osxView setFrame:former];
2182         r->width = (int)best.size.width;
2183         r->height = (int)best.size.height;
2184     }
2185 }
2186
2187 bool wxWidgetCocoaImpl::IsEnabled() const
2188 {
2189     NSView* targetView = m_osxView;
2190     if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
2191         targetView = [(NSScrollView*) m_osxView documentView];
2192
2193     if ( [targetView respondsToSelector:@selector(isEnabled) ] )
2194         return [targetView isEnabled];
2195     return true;
2196 }
2197
2198 void wxWidgetCocoaImpl::Enable( bool enable )
2199 {
2200     NSView* targetView = m_osxView;
2201     if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
2202         targetView = [(NSScrollView*) m_osxView documentView];
2203
2204     if ( [targetView respondsToSelector:@selector(setEnabled:) ] )
2205         [targetView setEnabled:enable];
2206 }
2207
2208 void wxWidgetCocoaImpl::PulseGauge()
2209 {
2210 }
2211
2212 void wxWidgetCocoaImpl::SetScrollThumb( wxInt32 WXUNUSED(val), wxInt32 WXUNUSED(view) )
2213 {
2214 }
2215
2216 void wxWidgetCocoaImpl::SetControlSize( wxWindowVariant variant )
2217 {
2218     NSControlSize size = NSRegularControlSize;
2219
2220     switch ( variant )
2221     {
2222         case wxWINDOW_VARIANT_NORMAL :
2223             size = NSRegularControlSize;
2224             break ;
2225
2226         case wxWINDOW_VARIANT_SMALL :
2227             size = NSSmallControlSize;
2228             break ;
2229
2230         case wxWINDOW_VARIANT_MINI :
2231             size = NSMiniControlSize;
2232             break ;
2233
2234         case wxWINDOW_VARIANT_LARGE :
2235             size = NSRegularControlSize;
2236             break ;
2237
2238         default:
2239             wxFAIL_MSG(wxT("unexpected window variant"));
2240             break ;
2241     }
2242     if ( [m_osxView respondsToSelector:@selector(setControlSize:)] )
2243         [m_osxView setControlSize:size];
2244     else if ([m_osxView respondsToSelector:@selector(cell)])
2245     {
2246         id cell = [(id)m_osxView cell];
2247         if ([cell respondsToSelector:@selector(setControlSize:)])
2248             [cell setControlSize:size];
2249     }
2250 }
2251
2252 void wxWidgetCocoaImpl::SetFont(wxFont const& font, wxColour const&col, long, bool)
2253 {
2254     if ([m_osxView respondsToSelector:@selector(setFont:)])
2255         [m_osxView setFont: font.OSXGetNSFont()];
2256     if ([m_osxView respondsToSelector:@selector(setTextColor:)])
2257         [m_osxView setTextColor:[NSColor colorWithCalibratedRed:(CGFloat) (col.Red() / 255.0)
2258                                                                  green:(CGFloat) (col.Green() / 255.0)
2259                                                                   blue:(CGFloat) (col.Blue() / 255.0)
2260                                                                  alpha:(CGFloat) (col.Alpha() / 255.0)]];
2261 }
2262
2263 void wxWidgetCocoaImpl::SetToolTip(wxToolTip* tooltip)
2264 {
2265     if (tooltip)
2266     {
2267         wxCFStringRef cf( tooltip->GetTip() , m_wxPeer->GetFont().GetEncoding() );
2268         [m_osxView setToolTip: cf.AsNSString()];
2269     }
2270     else 
2271         [m_osxView setToolTip: nil];
2272
2273 }
2274
2275 void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control )
2276 {
2277     WXWidget c =  control ? control : (WXWidget) m_osxView;
2278     wxWidgetImpl::Associate( c, this ) ;
2279     if ([c respondsToSelector:@selector(setAction:)])
2280     {
2281         [c setTarget: c];
2282         [c setAction: @selector(controlAction:)];
2283         if ([c respondsToSelector:@selector(setDoubleAction:)])
2284         {
2285             [c setDoubleAction: @selector(controlDoubleAction:)];
2286         }
2287
2288     }
2289 }
2290
2291 bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text)
2292 {
2293     wxKeyEvent wxevent(wxEVT_CHAR);
2294     SetupKeyEvent( wxevent, event, text );
2295
2296     return GetWXPeer()->OSXHandleKeyEvent(wxevent);
2297 }
2298
2299 bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event)
2300 {
2301     wxKeyEvent wxevent(wxEVT_KEY_DOWN);
2302     SetupKeyEvent( wxevent, event );
2303
2304     // Generate wxEVT_CHAR_HOOK before sending any other events but only when
2305     // the key is pressed, not when it's released (the type of wxevent is
2306     // changed by SetupKeyEvent() so it can be wxEVT_KEY_UP too by now).
2307     if ( wxevent.GetEventType() == wxEVT_KEY_DOWN )
2308     {
2309         wxKeyEvent eventHook(wxEVT_CHAR_HOOK, wxevent);
2310         if ( GetWXPeer()->OSXHandleKeyEvent(eventHook)
2311                 && !eventHook.IsNextEventAllowed() )
2312             return true;
2313     }
2314
2315     bool result = GetWXPeer()->OSXHandleKeyEvent(wxevent);
2316
2317     // this will fire higher level events, like insertText, to help
2318     // us handle EVT_CHAR, etc.
2319
2320     if ( !result )
2321     {
2322         if ( IsUserPane() && [event type] == NSKeyDown)
2323         {
2324             long keycode = wxOSXTranslateCocoaKey( event, wxEVT_CHAR );
2325             
2326             if ( (keycode > 0 && keycode < WXK_SPACE) || keycode == WXK_DELETE || keycode >= WXK_START )
2327             {
2328                 // eventually we could setup a doCommandBySelector catcher and retransform this into the wx key chars
2329                 wxKeyEvent wxevent2(wxevent) ;
2330                 wxevent2.SetEventType(wxEVT_CHAR);
2331                 wxevent2.m_keyCode = keycode;
2332                 result = GetWXPeer()->OSXHandleKeyEvent(wxevent2);
2333             }
2334             else
2335             {
2336                 if ( !wxevent.CmdDown() )
2337                 {
2338                     if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
2339                         [[(NSScrollView*)m_osxView documentView] interpretKeyEvents:[NSArray arrayWithObject:event]];
2340                     else
2341                         [m_osxView interpretKeyEvents:[NSArray arrayWithObject:event]];
2342                     result = true;
2343                 }
2344             }
2345         }
2346     }
2347
2348     return result;
2349 }
2350
2351 bool wxWidgetCocoaImpl::DoHandleMouseEvent(NSEvent *event)
2352 {
2353     wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
2354     SetupMouseEvent(wxevent , event) ;
2355
2356     return GetWXPeer()->HandleWindowEvent(wxevent);
2357 }
2358
2359 void wxWidgetCocoaImpl::DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* otherWindow)
2360 {
2361     wxWindow* thisWindow = GetWXPeer();
2362     if ( thisWindow->MacGetTopLevelWindow() && NeedsFocusRect() )
2363     {
2364         thisWindow->MacInvalidateBorders();
2365     }
2366
2367     if ( receivedFocus )
2368     {
2369         wxLogTrace(wxT("Focus"), wxT("focus set(%p)"), static_cast<void*>(thisWindow));
2370         wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
2371         thisWindow->HandleWindowEvent(eventFocus);
2372
2373 #if wxUSE_CARET
2374         if ( thisWindow->GetCaret() )
2375             thisWindow->GetCaret()->OnSetFocus();
2376 #endif
2377
2378         wxFocusEvent event(wxEVT_SET_FOCUS, thisWindow->GetId());
2379         event.SetEventObject(thisWindow);
2380         if (otherWindow)
2381             event.SetWindow(otherWindow->GetWXPeer());
2382         thisWindow->HandleWindowEvent(event) ;
2383     }
2384     else // !receivedFocuss
2385     {
2386 #if wxUSE_CARET
2387         if ( thisWindow->GetCaret() )
2388             thisWindow->GetCaret()->OnKillFocus();
2389 #endif
2390
2391         wxLogTrace(wxT("Focus"), wxT("focus lost(%p)"), static_cast<void*>(thisWindow));
2392
2393         wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
2394         event.SetEventObject(thisWindow);
2395         if (otherWindow)
2396             event.SetWindow(otherWindow->GetWXPeer());
2397         thisWindow->HandleWindowEvent(event) ;
2398     }
2399 }
2400
2401 void wxWidgetCocoaImpl::SetCursor(const wxCursor& cursor)
2402 {
2403     if ( !wxIsBusy() )
2404     {
2405         NSPoint location = [NSEvent mouseLocation];
2406         location = [[m_osxView window] convertScreenToBase:location];
2407         NSPoint locationInView = [m_osxView convertPoint:location fromView:nil];
2408
2409         if( NSMouseInRect(locationInView, [m_osxView bounds], YES) )
2410         {
2411             [(NSCursor*)cursor.GetHCURSOR() set];
2412         }
2413     }
2414     [[m_osxView window] invalidateCursorRectsForView:m_osxView];
2415 }
2416
2417 void wxWidgetCocoaImpl::CaptureMouse()
2418 {
2419     [[m_osxView window] disableCursorRects];
2420 }
2421
2422 void wxWidgetCocoaImpl::ReleaseMouse()
2423 {
2424     [[m_osxView window] enableCursorRects];
2425 }
2426
2427 void wxWidgetCocoaImpl::SetFlipped(bool flipped)
2428 {
2429     m_isFlipped = flipped;
2430 }
2431
2432 //
2433 // Factory methods
2434 //
2435
2436 wxWidgetImpl* wxWidgetImpl::CreateUserPane( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent),
2437     wxWindowID WXUNUSED(id), const wxPoint& pos, const wxSize& size,
2438     long WXUNUSED(style), long WXUNUSED(extraStyle))
2439 {
2440     NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
2441     wxNSView* v = [[wxNSView alloc] initWithFrame:r];
2442
2443     // temporary hook for dnd
2444     [v registerForDraggedTypes:[NSArray arrayWithObjects:
2445         NSStringPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPICTPboardType, NSPDFPboardType, nil]];
2446
2447     wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( wxpeer, v, false, true );
2448     return c;
2449 }
2450
2451 wxWidgetImpl* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
2452 {
2453     NSWindow* tlw = now->GetWXWindow();
2454     
2455     wxWidgetCocoaImpl* c = NULL;
2456     if ( now->IsNativeWindowWrapper() )
2457     {
2458         NSView* cv = [tlw contentView];
2459         c = new wxWidgetCocoaImpl( now, cv, true );
2460         // increase ref count, because the impl destructor will decrement it again
2461         CFRetain(cv);
2462         if ( !now->IsShown() )
2463             [cv setHidden:NO];
2464         
2465     }
2466     else
2467     {
2468         wxNSView* v = [[wxNSView alloc] initWithFrame:[[tlw contentView] frame]];
2469         c = new wxWidgetCocoaImpl( now, v, true );
2470         c->InstallEventHandler();
2471         [tlw setContentView:v];
2472     }
2473     return c;
2474 }