routing keys like ESC etc, fixes #13429
[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     }
1035 }
1036
1037 void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
1038 {
1039     if ( [event type] == NSKeyDown )
1040     {
1041         // there are key equivalents that are not command-combos and therefore not handled by cocoa automatically, 
1042         // therefore we call the menubar directly here, exit if the menu is handling the shortcut
1043         if ( [[[NSApplication sharedApplication] mainMenu] performKeyEquivalent:event] )
1044             return;
1045     
1046         m_lastKeyDownEvent = event;
1047     }
1048     
1049     if ( GetFocusedViewInWindow([slf window]) != slf || m_hasEditor || !DoHandleKeyEvent(event) )
1050     {
1051         wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1052         superimpl(slf, (SEL)_cmd, event);
1053     }
1054     m_lastKeyDownEvent = NULL;
1055 }
1056
1057 void wxWidgetCocoaImpl::insertText(NSString* text, WXWidget slf, void *_cmd)
1058 {
1059     if ( m_lastKeyDownEvent==NULL || m_hasEditor || !DoHandleCharEvent(m_lastKeyDownEvent, text) )
1060     {
1061         wxOSX_TextEventHandlerPtr superimpl = (wxOSX_TextEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1062         superimpl(slf, (SEL)_cmd, text);
1063     }
1064 }
1065
1066
1067 bool wxWidgetCocoaImpl::performKeyEquivalent(WX_NSEvent event, WXWidget slf, void *_cmd)
1068 {
1069     bool handled = false;
1070     
1071     wxKeyEvent wxevent(wxEVT_KEY_DOWN);
1072     SetupKeyEvent( wxevent, event );
1073    
1074     // because performKeyEquivalent is going up the entire view hierarchy, we don't have to
1075     // walk up the ancestors ourselves but let cocoa do it
1076     
1077     int command = m_wxPeer->GetAcceleratorTable()->GetCommand( wxevent );
1078     if (command != -1)
1079     {
1080         wxEvtHandler * const handler = m_wxPeer->GetEventHandler();
1081         
1082         wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1083         handled = handler->ProcessEvent( command_event );
1084         
1085         if ( !handled )
1086         {
1087             // accelerators can also be used with buttons, try them too
1088             command_event.SetEventType(wxEVT_COMMAND_BUTTON_CLICKED);
1089             handled = handler->ProcessEvent( command_event );
1090         }
1091     }
1092     
1093     if ( !handled )
1094     {
1095         wxOSX_PerformKeyEventHandlerPtr superimpl = (wxOSX_PerformKeyEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1096         return superimpl(slf, (SEL)_cmd, event);
1097     }
1098     return YES;
1099 }
1100
1101 bool wxWidgetCocoaImpl::acceptsFirstResponder(WXWidget slf, void *_cmd)
1102 {
1103     if ( IsUserPane() )
1104         return m_wxPeer->AcceptsFocus();
1105     else
1106     {
1107         wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1108         return superimpl(slf, (SEL)_cmd);
1109     }
1110 }
1111
1112 bool wxWidgetCocoaImpl::becomeFirstResponder(WXWidget slf, void *_cmd)
1113 {
1114     wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1115     // get the current focus before running becomeFirstResponder
1116     NSView* otherView = FindFocus();
1117
1118     wxWidgetImpl* otherWindow = FindFromWXWidget(otherView);
1119     BOOL r = superimpl(slf, (SEL)_cmd);
1120     if ( r )
1121     {
1122         DoNotifyFocusEvent( true, otherWindow );
1123     }
1124
1125     return r;
1126 }
1127
1128 bool wxWidgetCocoaImpl::resignFirstResponder(WXWidget slf, void *_cmd)
1129 {
1130     wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1131     BOOL r = superimpl(slf, (SEL)_cmd);
1132     // get the current focus after running resignFirstResponder
1133     // note that this value isn't reliable, it might return the same view that
1134     // is resigning
1135     NSView* otherView = FindFocus();
1136     wxWidgetImpl* otherWindow = FindFromWXWidget(otherView);
1137
1138     // It doesn't make sense to notify about the loss of focus if we're not
1139     // really losing it and the window which has just gained focus is the same
1140     // one as this window itself. Of course, this should never happen in the
1141     // first place but somehow it does in wxGrid code and without this check we
1142     // enter into an infinite recursion, see #12267.
1143     if ( otherWindow == this )
1144         return r;
1145
1146     // NSTextViews have an editor as true responder, therefore the might get the
1147     // resign notification if their editor takes over, don't trigger any event then
1148     if ( r && !m_hasEditor)
1149     {
1150         DoNotifyFocusEvent( false, otherWindow );
1151     }
1152     return r;
1153 }
1154
1155 void wxWidgetCocoaImpl::resetCursorRects(WXWidget slf, void *_cmd)
1156 {
1157     wxWindow* wxpeer = GetWXPeer();
1158     if ( wxpeer )
1159     {
1160         NSCursor *cursor = (NSCursor*)wxpeer->GetCursor().GetHCURSOR();
1161         if (cursor == NULL)
1162         {
1163             wxOSX_ResetCursorRectsHandlerPtr superimpl = (wxOSX_ResetCursorRectsHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
1164             superimpl(slf, (SEL)_cmd);
1165         }
1166         else
1167         {
1168             [slf addCursorRect: [slf bounds]
1169                 cursor: cursor];
1170         }
1171     }
1172 }
1173
1174 bool wxWidgetCocoaImpl::isFlipped(WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd))
1175 {
1176     return m_isFlipped;
1177 }
1178
1179
1180 #define OSX_DEBUG_DRAWING 0
1181
1182 void wxWidgetCocoaImpl::drawRect(void* rect, WXWidget slf, void *WXUNUSED(_cmd))
1183 {
1184     // preparing the update region
1185     
1186     wxRegion updateRgn;
1187     const NSRect *rects;
1188     NSInteger count;
1189
1190     [slf getRectsBeingDrawn:&rects count:&count];
1191     for ( int i = 0 ; i < count ; ++i )
1192     {
1193         updateRgn.Union(wxFromNSRect(slf, rects[i]));
1194     }
1195
1196     wxWindow* wxpeer = GetWXPeer();
1197
1198     if ( wxpeer->MacGetLeftBorderSize() != 0 || wxpeer->MacGetTopBorderSize() != 0 )
1199     {
1200         // as this update region is in native window locals we must adapt it to wx window local
1201         updateRgn.Offset( wxpeer->MacGetLeftBorderSize() , wxpeer->MacGetTopBorderSize() );
1202     }
1203     
1204     if ( wxpeer->MacGetTopLevelWindow()->GetWindowStyle() & wxFRAME_SHAPED )
1205     {
1206         int xoffset = 0, yoffset = 0;
1207         wxRegion rgn = wxpeer->MacGetTopLevelWindow()->GetShape();
1208         wxpeer->MacRootWindowToWindow( &xoffset, &yoffset );
1209         rgn.Offset( xoffset, yoffset );
1210         updateRgn.Intersect(rgn);
1211     }
1212     
1213     wxpeer->GetUpdateRegion() = updateRgn;
1214
1215     // setting up the drawing context
1216     
1217     CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
1218     CGContextSaveGState( context );
1219     
1220 #if OSX_DEBUG_DRAWING
1221     CGContextBeginPath( context );
1222     CGContextMoveToPoint(context, 0, 0);
1223     NSRect bounds = [slf bounds];
1224     CGContextAddLineToPoint(context, 10, 0);
1225     CGContextMoveToPoint(context, 0, 0);
1226     CGContextAddLineToPoint(context, 0, 10);
1227     CGContextMoveToPoint(context, bounds.size.width, bounds.size.height);
1228     CGContextAddLineToPoint(context, bounds.size.width, bounds.size.height-10);
1229     CGContextMoveToPoint(context, bounds.size.width, bounds.size.height);
1230     CGContextAddLineToPoint(context, bounds.size.width-10, bounds.size.height);
1231     CGContextClosePath( context );
1232     CGContextStrokePath(context);
1233 #endif
1234     
1235     if ( !m_isFlipped )
1236     {
1237         CGContextTranslateCTM( context, 0,  [m_osxView bounds].size.height );
1238         CGContextScaleCTM( context, 1, -1 );
1239     }
1240     
1241     wxpeer->MacSetCGContextRef( context );
1242
1243     bool handled = wxpeer->MacDoRedraw( 0 );
1244     CGContextRestoreGState( context );
1245
1246     CGContextSaveGState( context );
1247     if ( !handled )
1248     {
1249         // call super
1250         SEL _cmd = @selector(drawRect:);
1251         wxOSX_DrawRectHandlerPtr superimpl = (wxOSX_DrawRectHandlerPtr) [[slf superclass] instanceMethodForSelector:_cmd];
1252         superimpl(slf, _cmd, *(NSRect*)rect);
1253         CGContextRestoreGState( context );
1254         CGContextSaveGState( context );
1255     }
1256     // as we called restore above, we have to flip again if necessary
1257     if ( !m_isFlipped )
1258     {
1259         CGContextTranslateCTM( context, 0,  [m_osxView bounds].size.height );
1260         CGContextScaleCTM( context, 1, -1 );
1261     }
1262     wxpeer->MacPaintChildrenBorders();
1263     wxpeer->MacSetCGContextRef( NULL );
1264     CGContextRestoreGState( context );
1265 }
1266
1267 void wxWidgetCocoaImpl::controlAction( WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd), void *WXUNUSED(sender))
1268 {
1269     wxWindow* wxpeer = (wxWindow*) GetWXPeer();
1270     if ( wxpeer )
1271         wxpeer->OSXHandleClicked(0);
1272 }
1273
1274 void wxWidgetCocoaImpl::controlDoubleAction( WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd), void *WXUNUSED(sender))
1275 {
1276 }
1277
1278 void wxWidgetCocoaImpl::controlTextDidChange()
1279 {
1280     wxWindow* wxpeer = (wxWindow*)GetWXPeer();
1281     if ( wxpeer ) 
1282     {
1283         // since native rtti doesn't have to be enabled and wx' rtti is not aware of the mixin wxTextEntry, workaround is needed
1284         wxTextCtrl *tc = wxDynamicCast( wxpeer , wxTextCtrl );
1285         wxComboBox *cb = wxDynamicCast( wxpeer , wxComboBox );
1286         if ( tc )
1287             tc->SendTextUpdatedEventIfAllowed();
1288         else if ( cb )
1289             cb->SendTextUpdatedEventIfAllowed();
1290         else 
1291         {
1292             wxFAIL_MSG("Unexpected class for controlTextDidChange event");
1293         }
1294     }
1295 }
1296
1297 //
1298
1299 #if OBJC_API_VERSION >= 2
1300
1301 #define wxOSX_CLASS_ADD_METHOD( c, s, i, t ) \
1302     class_addMethod(c, s, i, t );
1303
1304 #else
1305
1306 #define wxOSX_CLASS_ADD_METHOD( c, s, i, t ) \
1307     { s, (char*) t, i },
1308
1309 #endif
1310
1311 void wxOSXCocoaClassAddWXMethods(Class c)
1312 {
1313
1314 #if OBJC_API_VERSION < 2
1315     static objc_method wxmethods[] =
1316     {
1317 #endif
1318
1319     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseDown:), (IMP) wxOSX_mouseEvent, "v@:@" )
1320     wxOSX_CLASS_ADD_METHOD(c, @selector(rightMouseDown:), (IMP) wxOSX_mouseEvent, "v@:@" )
1321     wxOSX_CLASS_ADD_METHOD(c, @selector(otherMouseDown:), (IMP) wxOSX_mouseEvent, "v@:@" )
1322
1323     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseUp:), (IMP) wxOSX_mouseEvent, "v@:@" )
1324     wxOSX_CLASS_ADD_METHOD(c, @selector(rightMouseUp:), (IMP) wxOSX_mouseEvent, "v@:@" )
1325     wxOSX_CLASS_ADD_METHOD(c, @selector(otherMouseUp:), (IMP) wxOSX_mouseEvent, "v@:@" )
1326
1327     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseMoved:), (IMP) wxOSX_mouseEvent, "v@:@" )
1328
1329     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseDragged:), (IMP) wxOSX_mouseEvent, "v@:@" )
1330     wxOSX_CLASS_ADD_METHOD(c, @selector(rightMouseDragged:), (IMP) wxOSX_mouseEvent, "v@:@" )
1331     wxOSX_CLASS_ADD_METHOD(c, @selector(otherMouseDragged:), (IMP) wxOSX_mouseEvent, "v@:@" )
1332     
1333     wxOSX_CLASS_ADD_METHOD(c, @selector(acceptsFirstMouse:), (IMP) wxOSX_acceptsFirstMouse, "v@:@" )
1334
1335     wxOSX_CLASS_ADD_METHOD(c, @selector(scrollWheel:), (IMP) wxOSX_mouseEvent, "v@:@" )
1336     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseEntered:), (IMP) wxOSX_mouseEvent, "v@:@" )
1337     wxOSX_CLASS_ADD_METHOD(c, @selector(mouseExited:), (IMP) wxOSX_mouseEvent, "v@:@" )
1338
1339     wxOSX_CLASS_ADD_METHOD(c, @selector(keyDown:), (IMP) wxOSX_keyEvent, "v@:@" )
1340     wxOSX_CLASS_ADD_METHOD(c, @selector(keyUp:), (IMP) wxOSX_keyEvent, "v@:@" )
1341     wxOSX_CLASS_ADD_METHOD(c, @selector(flagsChanged:), (IMP) wxOSX_keyEvent, "v@:@" )
1342
1343     wxOSX_CLASS_ADD_METHOD(c, @selector(insertText:), (IMP) wxOSX_insertText, "v@:@" )
1344
1345     wxOSX_CLASS_ADD_METHOD(c, @selector(performKeyEquivalent:), (IMP) wxOSX_performKeyEquivalent, "c@:@" )
1346
1347     wxOSX_CLASS_ADD_METHOD(c, @selector(acceptsFirstResponder), (IMP) wxOSX_acceptsFirstResponder, "c@:" )
1348     wxOSX_CLASS_ADD_METHOD(c, @selector(becomeFirstResponder), (IMP) wxOSX_becomeFirstResponder, "c@:" )
1349     wxOSX_CLASS_ADD_METHOD(c, @selector(resignFirstResponder), (IMP) wxOSX_resignFirstResponder, "c@:" )
1350     wxOSX_CLASS_ADD_METHOD(c, @selector(resetCursorRects), (IMP) wxOSX_resetCursorRects, "v@:" )
1351
1352     wxOSX_CLASS_ADD_METHOD(c, @selector(isFlipped), (IMP) wxOSX_isFlipped, "c@:" )
1353     wxOSX_CLASS_ADD_METHOD(c, @selector(drawRect:), (IMP) wxOSX_drawRect, "v@:{_NSRect={_NSPoint=ff}{_NSSize=ff}}" )
1354
1355     wxOSX_CLASS_ADD_METHOD(c, @selector(controlAction:), (IMP) wxOSX_controlAction, "v@:@" )
1356     wxOSX_CLASS_ADD_METHOD(c, @selector(controlDoubleAction:), (IMP) wxOSX_controlDoubleAction, "v@:@" )
1357
1358 #if wxUSE_DRAG_AND_DROP
1359     wxOSX_CLASS_ADD_METHOD(c, @selector(draggingEntered:), (IMP) wxOSX_draggingEntered, "I@:@" )
1360     wxOSX_CLASS_ADD_METHOD(c, @selector(draggingUpdated:), (IMP) wxOSX_draggingUpdated, "I@:@" )
1361     wxOSX_CLASS_ADD_METHOD(c, @selector(draggingExited:), (IMP) wxOSX_draggingExited, "v@:@" )
1362     wxOSX_CLASS_ADD_METHOD(c, @selector(performDragOperation:), (IMP) wxOSX_performDragOperation, "c@:@" )
1363 #endif
1364
1365 #if OBJC_API_VERSION < 2
1366     } ;
1367     static int method_count = WXSIZEOF( wxmethods );
1368     static objc_method_list *wxmethodlist = NULL;
1369     if ( wxmethodlist == NULL )
1370     {
1371         wxmethodlist = (objc_method_list*) malloc(sizeof(objc_method_list) + sizeof(wxmethods) );
1372         memcpy( &wxmethodlist->method_list[0], &wxmethods[0], sizeof(wxmethods) );
1373         wxmethodlist->method_count = method_count;
1374         wxmethodlist->obsolete = 0;
1375     }
1376     class_addMethods( c, wxmethodlist );
1377 #endif
1378 }
1379
1380 //
1381 // C++ implementation class
1382 //
1383
1384 IMPLEMENT_DYNAMIC_CLASS( wxWidgetCocoaImpl , wxWidgetImpl )
1385
1386 wxWidgetCocoaImpl::wxWidgetCocoaImpl( wxWindowMac* peer , WXWidget w, bool isRootControl, bool isUserPane ) :
1387     wxWidgetImpl( peer, isRootControl, isUserPane )
1388 {
1389     Init();
1390     m_osxView = w;
1391
1392     // check if the user wants to create the control initially hidden
1393     if ( !peer->IsShown() )
1394         SetVisibility(false);
1395
1396     // gc aware handling
1397     if ( m_osxView )
1398         CFRetain(m_osxView);
1399     [m_osxView release];
1400 }
1401
1402 wxWidgetCocoaImpl::wxWidgetCocoaImpl()
1403 {
1404     Init();
1405 }
1406
1407 void wxWidgetCocoaImpl::Init()
1408 {
1409     m_osxView = NULL;
1410     m_isFlipped = true;
1411     m_lastKeyDownEvent = NULL;
1412     m_hasEditor = false;
1413 }
1414
1415 wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
1416 {
1417     RemoveAssociations( this );
1418
1419     if ( !IsRootControl() )
1420     {
1421         NSView *sv = [m_osxView superview];
1422         if ( sv != nil )
1423             [m_osxView removeFromSuperview];
1424     }
1425     // gc aware handling
1426     if ( m_osxView )
1427         CFRelease(m_osxView);
1428 }
1429
1430 bool wxWidgetCocoaImpl::IsVisible() const
1431 {
1432     return [m_osxView isHiddenOrHasHiddenAncestor] == NO;
1433 }
1434
1435 void wxWidgetCocoaImpl::SetVisibility( bool visible )
1436 {
1437     [m_osxView setHidden:(visible ? NO:YES)];
1438 }
1439
1440 // ----------------------------------------------------------------------------
1441 // window animation stuff
1442 // ----------------------------------------------------------------------------
1443
1444 // define a delegate used to refresh the window during animation
1445 @interface wxNSAnimationDelegate : NSObject wxOSX_10_6_AND_LATER(<NSAnimationDelegate>)
1446 {
1447     wxWindow *m_win;
1448     bool m_isDone;
1449 }
1450
1451 - (id)init:(wxWindow *)win;
1452
1453 - (bool)isDone;
1454
1455 // NSAnimationDelegate methods
1456 - (void)animationDidEnd:(NSAnimation*)animation;
1457 - (void)animation:(NSAnimation*)animation
1458         didReachProgressMark:(NSAnimationProgress)progress;
1459 @end
1460
1461 @implementation wxNSAnimationDelegate
1462
1463 - (id)init:(wxWindow *)win
1464 {
1465     self = [super init];
1466
1467     m_win = win;
1468     m_isDone = false;
1469
1470     return self;
1471 }
1472
1473 - (bool)isDone
1474 {
1475     return m_isDone;
1476 }
1477
1478 - (void)animation:(NSAnimation*)animation
1479         didReachProgressMark:(NSAnimationProgress)progress
1480 {
1481     wxUnusedVar(animation);
1482     wxUnusedVar(progress);
1483
1484     m_win->SendSizeEvent();
1485 }
1486
1487 - (void)animationDidEnd:(NSAnimation*)animation
1488 {
1489     wxUnusedVar(animation);
1490     m_isDone = true;
1491 }
1492
1493 @end
1494
1495 /* static */
1496 bool
1497 wxWidgetCocoaImpl::ShowViewOrWindowWithEffect(wxWindow *win,
1498                                               bool show,
1499                                               wxShowEffect effect,
1500                                               unsigned timeout)
1501 {
1502     // create the dictionary describing the animation to perform on this view
1503     NSObject * const
1504         viewOrWin = static_cast<NSObject *>(win->OSXGetViewOrWindow());
1505     NSMutableDictionary * const
1506         dict = [NSMutableDictionary dictionaryWithCapacity:4];
1507     [dict setObject:viewOrWin forKey:NSViewAnimationTargetKey];
1508
1509     // determine the start and end rectangles assuming we're hiding the window
1510     const wxRect rectOrig = win->GetRect();
1511     wxRect rectStart,
1512            rectEnd;
1513     rectStart =
1514     rectEnd = rectOrig;
1515
1516     if ( show )
1517     {
1518         if ( effect == wxSHOW_EFFECT_ROLL_TO_LEFT ||
1519                 effect == wxSHOW_EFFECT_SLIDE_TO_LEFT )
1520             effect = wxSHOW_EFFECT_ROLL_TO_RIGHT;
1521         else if ( effect == wxSHOW_EFFECT_ROLL_TO_RIGHT ||
1522                     effect == wxSHOW_EFFECT_SLIDE_TO_RIGHT )
1523             effect = wxSHOW_EFFECT_ROLL_TO_LEFT;
1524         else if ( effect == wxSHOW_EFFECT_ROLL_TO_TOP ||
1525                     effect == wxSHOW_EFFECT_SLIDE_TO_TOP )
1526             effect = wxSHOW_EFFECT_ROLL_TO_BOTTOM;
1527         else if ( effect == wxSHOW_EFFECT_ROLL_TO_BOTTOM ||
1528                     effect == wxSHOW_EFFECT_SLIDE_TO_BOTTOM )
1529             effect = wxSHOW_EFFECT_ROLL_TO_TOP;
1530     }
1531
1532     switch ( effect )
1533     {
1534         case wxSHOW_EFFECT_ROLL_TO_LEFT:
1535         case wxSHOW_EFFECT_SLIDE_TO_LEFT:
1536             rectEnd.width = 0;
1537             break;
1538
1539         case wxSHOW_EFFECT_ROLL_TO_RIGHT:
1540         case wxSHOW_EFFECT_SLIDE_TO_RIGHT:
1541             rectEnd.x = rectStart.GetRight();
1542             rectEnd.width = 0;
1543             break;
1544
1545         case wxSHOW_EFFECT_ROLL_TO_TOP:
1546         case wxSHOW_EFFECT_SLIDE_TO_TOP:
1547             rectEnd.height = 0;
1548             break;
1549
1550         case wxSHOW_EFFECT_ROLL_TO_BOTTOM:
1551         case wxSHOW_EFFECT_SLIDE_TO_BOTTOM:
1552             rectEnd.y = rectStart.GetBottom();
1553             rectEnd.height = 0;
1554             break;
1555
1556         case wxSHOW_EFFECT_EXPAND:
1557             rectEnd.x = rectStart.x + rectStart.width / 2;
1558             rectEnd.y = rectStart.y + rectStart.height / 2;
1559             rectEnd.width =
1560             rectEnd.height = 0;
1561             break;
1562
1563         case wxSHOW_EFFECT_BLEND:
1564             [dict setObject:(show ? NSViewAnimationFadeInEffect
1565                                   : NSViewAnimationFadeOutEffect)
1566                   forKey:NSViewAnimationEffectKey];
1567             break;
1568
1569         case wxSHOW_EFFECT_NONE:
1570         case wxSHOW_EFFECT_MAX:
1571             wxFAIL_MSG( "unexpected animation effect" );
1572             return false;
1573
1574         default:
1575             wxFAIL_MSG( "unknown animation effect" );
1576             return false;
1577     };
1578
1579     if ( show )
1580     {
1581         // we need to restore it to the original rectangle instead of making it
1582         // disappear
1583         wxSwap(rectStart, rectEnd);
1584
1585         // and as the window is currently hidden, we need to show it for the
1586         // animation to be visible at all (but don't restore it at its full
1587         // rectangle as it shouldn't appear immediately)
1588         win->SetSize(rectStart);
1589         win->Show();
1590     }
1591
1592     NSView * const parentView = [viewOrWin isKindOfClass:[NSView class]]
1593                                     ? [(NSView *)viewOrWin superview]
1594                                     : nil;
1595     const NSRect rStart = wxToNSRect(parentView, rectStart);
1596     const NSRect rEnd = wxToNSRect(parentView, rectEnd);
1597
1598     [dict setObject:[NSValue valueWithRect:rStart]
1599           forKey:NSViewAnimationStartFrameKey];
1600     [dict setObject:[NSValue valueWithRect:rEnd]
1601           forKey:NSViewAnimationEndFrameKey];
1602
1603     // create an animation using the values in the above dictionary
1604     NSViewAnimation * const
1605         anim = [[NSViewAnimation alloc]
1606                 initWithViewAnimations:[NSArray arrayWithObject:dict]];
1607
1608     if ( !timeout )
1609     {
1610         // what is a good default duration? Windows uses 200ms, Web frameworks
1611         // use anything from 250ms to 1s... choose something in the middle
1612         timeout = 500;
1613     }
1614
1615     [anim setDuration:timeout/1000.];   // duration is in seconds here
1616
1617     // if the window being animated changes its layout depending on its size
1618     // (which is almost always the case) we need to redo it during animation
1619     //
1620     // the number of layouts here is arbitrary, but 10 seems like too few (e.g.
1621     // controls in wxInfoBar visibly jump around)
1622     const int NUM_LAYOUTS = 20;
1623     for ( float f = 1./NUM_LAYOUTS; f < 1.; f += 1./NUM_LAYOUTS )
1624         [anim addProgressMark:f];
1625
1626     wxNSAnimationDelegate * const
1627         animDelegate = [[wxNSAnimationDelegate alloc] init:win];
1628     [anim setDelegate:animDelegate];
1629     [anim startAnimation];
1630
1631     // Cocoa is capable of doing animation asynchronously or even from separate
1632     // thread but wx API doesn't provide any way to be notified about the
1633     // animation end and without this we really must ensure that the window has
1634     // the expected (i.e. the same as if a simple Show() had been used) size
1635     // when we return, so block here until the animation finishes
1636     //
1637     // notice that because the default animation mode is NSAnimationBlocking,
1638     // no user input events ought to be processed from here
1639     {
1640         wxEventLoopGuarantor ensureEventLoopExistence;
1641         wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
1642         while ( ![animDelegate isDone] )
1643             loop->Dispatch();
1644     }
1645
1646     if ( !show )
1647     {
1648         // NSViewAnimation is smart enough to hide the NSView being animated at
1649         // the end but we also must ensure that it's hidden for wx too
1650         win->Hide();
1651
1652         // and we must also restore its size because it isn't expected to
1653         // change just because the window was hidden
1654         win->SetSize(rectOrig);
1655     }
1656     else
1657     {
1658         // refresh it once again after the end to ensure that everything is in
1659         // place
1660         win->SendSizeEvent();
1661     }
1662
1663     [anim setDelegate:nil];
1664     [animDelegate release];
1665     [anim release];
1666
1667     return true;
1668 }
1669
1670 bool wxWidgetCocoaImpl::ShowWithEffect(bool show,
1671                                        wxShowEffect effect,
1672                                        unsigned timeout)
1673 {
1674     return ShowViewOrWindowWithEffect(m_wxPeer, show, effect, timeout);
1675 }
1676
1677 void wxWidgetCocoaImpl::Raise()
1678 {
1679     // Not implemented
1680 }
1681
1682 void wxWidgetCocoaImpl::Lower()
1683 {
1684     // Not implemented
1685 }
1686
1687 void wxWidgetCocoaImpl::ScrollRect( const wxRect *WXUNUSED(rect), int WXUNUSED(dx), int WXUNUSED(dy) )
1688 {
1689 #if 1
1690     SetNeedsDisplay() ;
1691 #else
1692     // We should do something like this, but it wasn't working in 10.4.
1693     if (GetNeedsDisplay() )
1694     {
1695         SetNeedsDisplay() ;
1696     }
1697     NSRect r = wxToNSRect( [m_osxView superview], *rect );
1698     NSSize offset = NSMakeSize((float)dx, (float)dy);
1699     [m_osxView scrollRect:r by:offset];
1700 #endif
1701 }
1702
1703 void wxWidgetCocoaImpl::Move(int x, int y, int width, int height)
1704 {
1705     wxWindowMac* parent = GetWXPeer()->GetParent();
1706     // under Cocoa we might have a contentView in the wxParent to which we have to
1707     // adjust the coordinates
1708     if (parent && [m_osxView superview] != parent->GetHandle() )
1709     {
1710         int cx = 0,cy = 0,cw = 0,ch = 0;
1711         if ( parent->GetPeer() )
1712         {
1713             parent->GetPeer()->GetContentArea(cx, cy, cw, ch);
1714             x -= cx;
1715             y -= cy;
1716         }
1717     }
1718     [[m_osxView superview] setNeedsDisplayInRect:[m_osxView frame]];
1719     NSRect r = wxToNSRect( [m_osxView superview], wxRect(x,y,width, height) );
1720     [m_osxView setFrame:r];
1721     [[m_osxView superview] setNeedsDisplayInRect:r];
1722
1723     wxNSView* wxview = (wxNSView*)m_osxView;
1724 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1725     if ([wxview respondsToSelector:@selector(updateTrackingArea)] )
1726         [wxview updateTrackingArea]; 
1727 #else
1728     if ([m_osxView respondsToSelector:@selector(trackingTag)] )
1729     {
1730         if ( [wxview trackingTag] )
1731             [wxview removeTrackingRect: [wxview trackingTag]];
1732
1733         [wxview setTrackingTag: [wxview addTrackingRect: [m_osxView bounds] owner: wxview userData: nil assumeInside: NO]];
1734     }
1735 #endif
1736 }
1737
1738 void wxWidgetCocoaImpl::GetPosition( int &x, int &y ) const
1739 {
1740     wxRect r = wxFromNSRect( [m_osxView superview], [m_osxView frame] );
1741     x = r.GetLeft();
1742     y = r.GetTop();
1743     
1744     // under Cocoa we might have a contentView in the wxParent to which we have to
1745     // adjust the coordinates
1746     wxWindowMac* parent = GetWXPeer()->GetParent();
1747     if (parent && [m_osxView superview] != parent->GetHandle() )
1748     {
1749         int cx = 0,cy = 0,cw = 0,ch = 0;
1750         if ( parent->GetPeer() )
1751         {
1752             parent->GetPeer()->GetContentArea(cx, cy, cw, ch);
1753             x += cx;
1754             y += cy;
1755         }
1756     }
1757 }
1758
1759 void wxWidgetCocoaImpl::GetSize( int &width, int &height ) const
1760 {
1761     NSRect rect = [m_osxView frame];
1762     width = (int)rect.size.width;
1763     height = (int)rect.size.height;
1764 }
1765
1766 void wxWidgetCocoaImpl::GetContentArea( int&left, int &top, int &width, int &height ) const
1767 {
1768     if ( [m_osxView respondsToSelector:@selector(contentView) ] )
1769     {
1770         NSView* cv = [m_osxView contentView];
1771
1772         NSRect bounds = [m_osxView bounds];
1773         NSRect rect = [cv frame];
1774
1775         int y = (int)rect.origin.y;
1776         int x = (int)rect.origin.x;
1777         if ( ![ m_osxView isFlipped ] )
1778             y = (int)(bounds.size.height - (rect.origin.y + rect.size.height));
1779         left = x;
1780         top = y;
1781         width = (int)rect.size.width;
1782         height = (int)rect.size.height;
1783     }
1784     else
1785     {
1786         left = top = 0;
1787         GetSize( width, height );
1788     }
1789 }
1790
1791 void wxWidgetCocoaImpl::SetNeedsDisplay( const wxRect* where )
1792 {
1793     if ( where )
1794         [m_osxView setNeedsDisplayInRect:wxToNSRect(m_osxView, *where )];
1795     else
1796         [m_osxView setNeedsDisplay:YES];
1797 }
1798
1799 bool wxWidgetCocoaImpl::GetNeedsDisplay() const
1800 {
1801     return [m_osxView needsDisplay];
1802 }
1803
1804 bool wxWidgetCocoaImpl::CanFocus() const
1805 {
1806     return [m_osxView canBecomeKeyView] == YES;
1807 }
1808
1809 bool wxWidgetCocoaImpl::HasFocus() const
1810 {
1811     return ( FindFocus() == m_osxView );
1812 }
1813
1814 bool wxWidgetCocoaImpl::SetFocus()
1815 {
1816     if ( !CanFocus() )
1817         return false;
1818
1819     [[m_osxView window] makeKeyAndOrderFront:nil] ;
1820     [[m_osxView window] makeFirstResponder: m_osxView] ;
1821     return true;
1822 }
1823
1824
1825 void wxWidgetCocoaImpl::RemoveFromParent()
1826 {
1827     [m_osxView removeFromSuperview];
1828 }
1829
1830 void wxWidgetCocoaImpl::Embed( wxWidgetImpl *parent )
1831 {
1832     NSView* container = parent->GetWXWidget() ;
1833     wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
1834     [container addSubview:m_osxView];
1835 }
1836
1837 void wxWidgetCocoaImpl::SetBackgroundColour( const wxColour &col )
1838 {
1839     NSView* targetView = m_osxView;
1840     if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
1841         targetView = [(NSScrollView*) m_osxView documentView];
1842
1843     if ( [targetView respondsToSelector:@selector(setBackgroundColor:) ] )
1844     {
1845         [targetView setBackgroundColor:[NSColor colorWithCalibratedRed:(CGFloat) (col.Red() / 255.0)
1846                                                                 green:(CGFloat) (col.Green() / 255.0)
1847                                                                  blue:(CGFloat) (col.Blue() / 255.0)
1848                                                                 alpha:(CGFloat) (col.Alpha() / 255.0)]];
1849     }
1850 }
1851
1852 bool wxWidgetCocoaImpl::SetBackgroundStyle( wxBackgroundStyle style )
1853 {
1854     BOOL opaque = ( style == wxBG_STYLE_PAINT );
1855     
1856     if ( [m_osxView respondsToSelector:@selector(setOpaque:) ] )
1857     {
1858         [m_osxView setOpaque: opaque];
1859     }
1860     
1861     return true ;
1862 }
1863
1864 void wxWidgetCocoaImpl::SetLabel( const wxString& title, wxFontEncoding encoding )
1865 {
1866     if ( [m_osxView respondsToSelector:@selector(setTitle:) ] )
1867     {
1868         wxCFStringRef cf( title , encoding );
1869         [m_osxView setTitle:cf.AsNSString()];
1870     }
1871     else if ( [m_osxView respondsToSelector:@selector(setStringValue:) ] )
1872     {
1873         wxCFStringRef cf( title , encoding );
1874         [m_osxView setStringValue:cf.AsNSString()];
1875     }
1876 }
1877
1878
1879 void  wxWidgetImpl::Convert( wxPoint *pt , wxWidgetImpl *from , wxWidgetImpl *to )
1880 {
1881     NSPoint p = wxToNSPoint( from->GetWXWidget(), *pt );
1882     p = [from->GetWXWidget() convertPoint:p toView:to->GetWXWidget() ];
1883     *pt = wxFromNSPoint( to->GetWXWidget(), p );
1884 }
1885
1886 wxInt32 wxWidgetCocoaImpl::GetValue() const
1887 {
1888     return [(NSControl*)m_osxView intValue];
1889 }
1890
1891 void wxWidgetCocoaImpl::SetValue( wxInt32 v )
1892 {
1893     if (  [m_osxView respondsToSelector:@selector(setIntValue:)] )
1894     {
1895         [m_osxView setIntValue:v];
1896     }
1897     else if (  [m_osxView respondsToSelector:@selector(setFloatValue:)] )
1898     {
1899         [m_osxView setFloatValue:(double)v];
1900     }
1901     else if (  [m_osxView respondsToSelector:@selector(setDoubleValue:)] )
1902     {
1903         [m_osxView setDoubleValue:(double)v];
1904     }
1905 }
1906
1907 void wxWidgetCocoaImpl::SetMinimum( wxInt32 v )
1908 {
1909     if (  [m_osxView respondsToSelector:@selector(setMinValue:)] )
1910     {
1911         [m_osxView setMinValue:(double)v];
1912     }
1913 }
1914
1915 void wxWidgetCocoaImpl::SetMaximum( wxInt32 v )
1916 {
1917     if (  [m_osxView respondsToSelector:@selector(setMaxValue:)] )
1918     {
1919         [m_osxView setMaxValue:(double)v];
1920     }
1921 }
1922
1923 wxInt32 wxWidgetCocoaImpl::GetMinimum() const
1924 {
1925     if (  [m_osxView respondsToSelector:@selector(minValue)] )
1926     {
1927         return (int)[m_osxView minValue];
1928     }
1929     return 0;
1930 }
1931
1932 wxInt32 wxWidgetCocoaImpl::GetMaximum() const
1933 {
1934     if (  [m_osxView respondsToSelector:@selector(maxValue)] )
1935     {
1936         return (int)[m_osxView maxValue];
1937     }
1938     return 0;
1939 }
1940
1941 wxBitmap wxWidgetCocoaImpl::GetBitmap() const
1942 {
1943     wxBitmap bmp;
1944
1945     // TODO: how to create a wxBitmap from NSImage?
1946 #if 0
1947     if ( [m_osxView respondsToSelector:@selector(image:)] )
1948         bmp = [m_osxView image];
1949 #endif
1950
1951     return bmp;
1952 }
1953
1954 void wxWidgetCocoaImpl::SetBitmap( const wxBitmap& bitmap )
1955 {
1956     if (  [m_osxView respondsToSelector:@selector(setImage:)] )
1957     {
1958         [m_osxView setImage:bitmap.GetNSImage()];
1959         [m_osxView setNeedsDisplay:YES];
1960     }
1961 }
1962
1963 void wxWidgetCocoaImpl::SetBitmapPosition( wxDirection dir )
1964 {
1965     if ( [m_osxView respondsToSelector:@selector(setImagePosition:)] )
1966     {
1967         NSCellImagePosition pos;
1968         switch ( dir )
1969         {
1970             case wxLEFT:
1971                 pos = NSImageLeft;
1972                 break;
1973
1974             case wxRIGHT:
1975                 pos = NSImageRight;
1976                 break;
1977
1978             case wxTOP:
1979                 pos = NSImageAbove;
1980                 break;
1981
1982             case wxBOTTOM:
1983                 pos = NSImageBelow;
1984                 break;
1985
1986             default:
1987                 wxFAIL_MSG( "invalid image position" );
1988                 pos = NSNoImage;
1989         }
1990
1991         [m_osxView setImagePosition:pos];
1992     }
1993 }
1994
1995 void wxWidgetCocoaImpl::SetupTabs( const wxNotebook& WXUNUSED(notebook))
1996 {
1997     // implementation in subclass
1998 }
1999
2000 void wxWidgetCocoaImpl::GetBestRect( wxRect *r ) const
2001 {
2002     r->x = r->y = r->width = r->height = 0;
2003
2004     if (  [m_osxView respondsToSelector:@selector(sizeToFit)] )
2005     {
2006         NSRect former = [m_osxView frame];
2007         [m_osxView sizeToFit];
2008         NSRect best = [m_osxView frame];
2009         [m_osxView setFrame:former];
2010         r->width = (int)best.size.width;
2011         r->height = (int)best.size.height;
2012     }
2013 }
2014
2015 bool wxWidgetCocoaImpl::IsEnabled() const
2016 {
2017     NSView* targetView = m_osxView;
2018     if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
2019         targetView = [(NSScrollView*) m_osxView documentView];
2020
2021     if ( [targetView respondsToSelector:@selector(isEnabled) ] )
2022         return [targetView isEnabled];
2023     return true;
2024 }
2025
2026 void wxWidgetCocoaImpl::Enable( bool enable )
2027 {
2028     NSView* targetView = m_osxView;
2029     if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
2030         targetView = [(NSScrollView*) m_osxView documentView];
2031
2032     if ( [targetView respondsToSelector:@selector(setEnabled:) ] )
2033         [targetView setEnabled:enable];
2034 }
2035
2036 void wxWidgetCocoaImpl::PulseGauge()
2037 {
2038 }
2039
2040 void wxWidgetCocoaImpl::SetScrollThumb( wxInt32 WXUNUSED(val), wxInt32 WXUNUSED(view) )
2041 {
2042 }
2043
2044 void wxWidgetCocoaImpl::SetControlSize( wxWindowVariant variant )
2045 {
2046     NSControlSize size = NSRegularControlSize;
2047
2048     switch ( variant )
2049     {
2050         case wxWINDOW_VARIANT_NORMAL :
2051             size = NSRegularControlSize;
2052             break ;
2053
2054         case wxWINDOW_VARIANT_SMALL :
2055             size = NSSmallControlSize;
2056             break ;
2057
2058         case wxWINDOW_VARIANT_MINI :
2059             size = NSMiniControlSize;
2060             break ;
2061
2062         case wxWINDOW_VARIANT_LARGE :
2063             size = NSRegularControlSize;
2064             break ;
2065
2066         default:
2067             wxFAIL_MSG(wxT("unexpected window variant"));
2068             break ;
2069     }
2070     if ( [m_osxView respondsToSelector:@selector(setControlSize:)] )
2071         [m_osxView setControlSize:size];
2072     else if ([m_osxView respondsToSelector:@selector(cell)])
2073     {
2074         id cell = [(id)m_osxView cell];
2075         if ([cell respondsToSelector:@selector(setControlSize:)])
2076             [cell setControlSize:size];
2077     }
2078 }
2079
2080 void wxWidgetCocoaImpl::SetFont(wxFont const& font, wxColour const&col, long, bool)
2081 {
2082     if ([m_osxView respondsToSelector:@selector(setFont:)])
2083         [m_osxView setFont: font.OSXGetNSFont()];
2084     if ([m_osxView respondsToSelector:@selector(setTextColor:)])
2085         [m_osxView setTextColor:[NSColor colorWithCalibratedRed:(CGFloat) (col.Red() / 255.0)
2086                                                                  green:(CGFloat) (col.Green() / 255.0)
2087                                                                   blue:(CGFloat) (col.Blue() / 255.0)
2088                                                                  alpha:(CGFloat) (col.Alpha() / 255.0)]];
2089 }
2090
2091 void wxWidgetCocoaImpl::SetToolTip(wxToolTip* tooltip)
2092 {
2093     if (tooltip)
2094     {
2095         wxCFStringRef cf( tooltip->GetTip() , m_wxPeer->GetFont().GetEncoding() );
2096         [m_osxView setToolTip: cf.AsNSString()];
2097     }
2098     else 
2099         [m_osxView setToolTip: nil];
2100
2101 }
2102
2103 void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control )
2104 {
2105     WXWidget c =  control ? control : (WXWidget) m_osxView;
2106     wxWidgetImpl::Associate( c, this ) ;
2107     if ([c respondsToSelector:@selector(setAction:)])
2108     {
2109         [c setTarget: c];
2110         [c setAction: @selector(controlAction:)];
2111         if ([c respondsToSelector:@selector(setDoubleAction:)])
2112         {
2113             [c setDoubleAction: @selector(controlDoubleAction:)];
2114         }
2115
2116     }
2117 }
2118
2119 bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text)
2120 {
2121     wxKeyEvent wxevent(wxEVT_CHAR);
2122     SetupKeyEvent( wxevent, event, text );
2123
2124     return GetWXPeer()->OSXHandleKeyEvent(wxevent);
2125 }
2126
2127 bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event)
2128 {
2129     wxKeyEvent wxevent(wxEVT_KEY_DOWN);
2130     SetupKeyEvent( wxevent, event );
2131     bool result = GetWXPeer()->OSXHandleKeyEvent(wxevent);
2132
2133     // this will fire higher level events, like insertText, to help
2134     // us handle EVT_CHAR, etc.
2135
2136     if ( !result )
2137     {
2138         if ( IsUserPane() && [event type] == NSKeyDown)
2139         {
2140             long keycode = wxOSXTranslateCocoaKey( event, wxEVT_CHAR );
2141             
2142             if ( (keycode > 0 && keycode < WXK_SPACE) || keycode == WXK_DELETE || keycode >= WXK_START )
2143             {
2144                 // eventually we could setup a doCommandBySelector catcher and retransform this into the wx key chars
2145                 wxKeyEvent wxevent2(wxevent) ;
2146                 wxevent2.SetEventType(wxEVT_CHAR);
2147                 wxevent2.m_keyCode = keycode;
2148                 result = GetWXPeer()->OSXHandleKeyEvent(wxevent2);
2149             }
2150             else
2151             {
2152                 if ( !wxevent.CmdDown() )
2153                 {
2154                     if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
2155                         [[(NSScrollView*)m_osxView documentView] interpretKeyEvents:[NSArray arrayWithObject:event]];
2156                     else
2157                         [m_osxView interpretKeyEvents:[NSArray arrayWithObject:event]];
2158                     result = true;
2159                 }
2160             }
2161         }
2162     }
2163
2164     return result;
2165 }
2166
2167 bool wxWidgetCocoaImpl::DoHandleMouseEvent(NSEvent *event)
2168 {
2169     wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
2170     SetupMouseEvent(wxevent , event) ;
2171
2172     return GetWXPeer()->HandleWindowEvent(wxevent);
2173 }
2174
2175 void wxWidgetCocoaImpl::DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* otherWindow)
2176 {
2177     wxWindow* thisWindow = GetWXPeer();
2178     if ( thisWindow->MacGetTopLevelWindow() && NeedsFocusRect() )
2179     {
2180         thisWindow->MacInvalidateBorders();
2181     }
2182
2183     if ( receivedFocus )
2184     {
2185         wxLogTrace(wxT("Focus"), wxT("focus set(%p)"), static_cast<void*>(thisWindow));
2186         wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
2187         thisWindow->HandleWindowEvent(eventFocus);
2188
2189 #if wxUSE_CARET
2190         if ( thisWindow->GetCaret() )
2191             thisWindow->GetCaret()->OnSetFocus();
2192 #endif
2193
2194         wxFocusEvent event(wxEVT_SET_FOCUS, thisWindow->GetId());
2195         event.SetEventObject(thisWindow);
2196         if (otherWindow)
2197             event.SetWindow(otherWindow->GetWXPeer());
2198         thisWindow->HandleWindowEvent(event) ;
2199     }
2200     else // !receivedFocuss
2201     {
2202 #if wxUSE_CARET
2203         if ( thisWindow->GetCaret() )
2204             thisWindow->GetCaret()->OnKillFocus();
2205 #endif
2206
2207         wxLogTrace(wxT("Focus"), wxT("focus lost(%p)"), static_cast<void*>(thisWindow));
2208
2209         wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
2210         event.SetEventObject(thisWindow);
2211         if (otherWindow)
2212             event.SetWindow(otherWindow->GetWXPeer());
2213         thisWindow->HandleWindowEvent(event) ;
2214     }
2215 }
2216
2217 void wxWidgetCocoaImpl::SetCursor(const wxCursor& cursor)
2218 {
2219     if ( !wxIsBusy() )
2220     {
2221         NSPoint location = [NSEvent mouseLocation];
2222         location = [[m_osxView window] convertScreenToBase:location];
2223         NSPoint locationInView = [m_osxView convertPoint:location fromView:nil];
2224
2225         if( NSMouseInRect(locationInView, [m_osxView bounds], YES) )
2226         {
2227             [(NSCursor*)cursor.GetHCURSOR() set];
2228         }
2229     }
2230     [[m_osxView window] invalidateCursorRectsForView:m_osxView];
2231 }
2232
2233 void wxWidgetCocoaImpl::CaptureMouse()
2234 {
2235     [[m_osxView window] disableCursorRects];
2236 }
2237
2238 void wxWidgetCocoaImpl::ReleaseMouse()
2239 {
2240     [[m_osxView window] enableCursorRects];
2241 }
2242
2243 void wxWidgetCocoaImpl::SetFlipped(bool flipped)
2244 {
2245     m_isFlipped = flipped;
2246 }
2247
2248 //
2249 // Factory methods
2250 //
2251
2252 wxWidgetImpl* wxWidgetImpl::CreateUserPane( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent),
2253     wxWindowID WXUNUSED(id), const wxPoint& pos, const wxSize& size,
2254     long WXUNUSED(style), long WXUNUSED(extraStyle))
2255 {
2256     NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
2257     wxNSView* v = [[wxNSView alloc] initWithFrame:r];
2258
2259     // temporary hook for dnd
2260     [v registerForDraggedTypes:[NSArray arrayWithObjects:
2261         NSStringPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPICTPboardType, NSPDFPboardType, nil]];
2262
2263     wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( wxpeer, v, false, true );
2264     return c;
2265 }
2266
2267 wxWidgetImpl* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
2268 {
2269     NSWindow* tlw = now->GetWXWindow();
2270     
2271     wxWidgetCocoaImpl* c = NULL;
2272     if ( now->IsNativeWindowWrapper() )
2273     {
2274         NSView* cv = [tlw contentView];
2275         c = new wxWidgetCocoaImpl( now, cv, true );
2276         // increase ref count, because the impl destructor will decrement it again
2277         CFRetain(cv);
2278         if ( !now->IsShown() )
2279             [cv setHidden:NO];
2280         
2281     }
2282     else
2283     {
2284         wxNSView* v = [[wxNSView alloc] initWithFrame:[[tlw contentView] frame]];
2285         c = new wxWidgetCocoaImpl( now, v, true );
2286         c->InstallEventHandler();
2287         [tlw setContentView:v];
2288     }
2289     return c;
2290 }