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