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