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