* When hiding a wxWindow make sure that none of its subviews are the first
[wxWidgets.git] / src / cocoa / window.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/window.mm
3 // Purpose:     wxWindowCocoa
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2002/12/26
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2002 David Elliott
9 // Licence:     wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifndef WX_PRECOMP
15     #include "wx/log.h"
16     #include "wx/window.h"
17     #include "wx/dc.h"
18     #include "wx/dcclient.h"
19     #include "wx/utils.h"
20 #endif //WX_PRECOMP
21
22 #include "wx/tooltip.h"
23
24 #include "wx/cocoa/dc.h"
25 #include "wx/cocoa/autorelease.h"
26 #include "wx/cocoa/string.h"
27 #include "wx/cocoa/trackingrectmanager.h"
28 #include "wx/cocoa/private/scrollview.h"
29 #include "wx/mac/corefoundation/cfref.h"
30 #include "wx/cocoa/ObjcRef.h"
31
32 #import <Foundation/NSArray.h>
33 #import <Foundation/NSRunLoop.h>
34 #include "wx/cocoa/objc/NSView.h"
35 #import <AppKit/NSEvent.h>
36 #import <AppKit/NSScrollView.h>
37 #import <AppKit/NSScroller.h>
38 #import <AppKit/NSColor.h>
39 #import <AppKit/NSClipView.h>
40 #import <Foundation/NSException.h>
41 #import <AppKit/NSApplication.h>
42 #import <AppKit/NSWindow.h>
43 #import <AppKit/NSScreen.h>
44
45 // Turn this on to paint green over the dummy views for debugging
46 #undef WXCOCOA_FILL_DUMMY_VIEW
47
48 #ifdef WXCOCOA_FILL_DUMMY_VIEW
49 #import <AppKit/NSBezierPath.h>
50 #endif //def WXCOCOA_FILL_DUMMY_VIEW
51
52 // STL list used by wxCocoaMouseMovedEventSynthesizer
53 #include <list>
54
55 /* NSComparisonResult is typedef'd as an enum pre-Leopard but typedef'd as
56  * NSInteger post-Leopard.  Pre-Leopard the Cocoa toolkit expects a function
57  * returning int and not NSComparisonResult.  Post-Leopard the Cocoa toolkit
58  * expects a function returning the new non-enum NSComparsionResult.
59  * Hence we create a typedef named CocoaWindowCompareFunctionResult.
60  */
61 #if defined(NSINTEGER_DEFINED)
62 typedef NSComparisonResult CocoaWindowCompareFunctionResult;
63 #else
64 typedef int CocoaWindowCompareFunctionResult;
65 #endif
66
67 // A category for methods that are only present in Panther's SDK
68 @interface NSView(wxNSViewPrePantherCompatibility)
69 - (void)getRectsBeingDrawn:(const NSRect **)rects count:(int *)count;
70 @end
71
72 // ========================================================================
73 // Helper functions for converting to/from wxWidgets coordinates and a
74 // specified NSView's coordinate system.
75 // ========================================================================
76 NSPoint CocoaTransformNSViewBoundsToWx(NSView *nsview, NSPoint pointBounds)
77 {
78     wxCHECK_MSG(nsview, pointBounds, wxT("Need to have a Cocoa view to do translation"));
79     if([nsview isFlipped])
80         return pointBounds;
81     NSRect ourBounds = [nsview bounds];
82     return NSMakePoint
83     (   pointBounds.x
84     ,   ourBounds.size.height - pointBounds.y
85     );
86 }
87
88 NSRect CocoaTransformNSViewBoundsToWx(NSView *nsview, NSRect rectBounds)
89 {
90     wxCHECK_MSG(nsview, rectBounds, wxT("Need to have a Cocoa view to do translation"));
91     if([nsview isFlipped])
92         return rectBounds;
93     NSRect ourBounds = [nsview bounds];
94     return NSMakeRect
95     (   rectBounds.origin.x
96     ,   ourBounds.size.height - (rectBounds.origin.y + rectBounds.size.height)
97     ,   rectBounds.size.width
98     ,   rectBounds.size.height
99     );
100 }
101
102 NSPoint CocoaTransformNSViewWxToBounds(NSView *nsview, NSPoint pointWx)
103 {
104     wxCHECK_MSG(nsview, pointWx, wxT("Need to have a Cocoa view to do translation"));
105     if([nsview isFlipped])
106         return pointWx;
107     NSRect ourBounds = [nsview bounds];
108     return NSMakePoint
109     (   pointWx.x
110     ,   ourBounds.size.height - pointWx.y
111     );
112 }
113
114 NSRect CocoaTransformNSViewWxToBounds(NSView *nsview, NSRect rectWx)
115 {
116     wxCHECK_MSG(nsview, rectWx, wxT("Need to have a Cocoa view to do translation"));
117     if([nsview isFlipped])
118         return rectWx;
119     NSRect ourBounds = [nsview bounds];
120     return NSMakeRect
121     (   rectWx.origin.x
122     ,   ourBounds.size.height - (rectWx.origin.y + rectWx.size.height)
123     ,   rectWx.size.width
124     ,   rectWx.size.height
125     );
126 }
127
128 // ============================================================================
129 // Screen coordinate helpers
130 // ============================================================================
131
132 /*
133 General observation about Cocoa screen coordinates:
134 It is documented that the first object of the [NSScreen screens] array is the screen with the menubar.
135
136 It is not documented (but true as far as I can tell) that (0,0) in Cocoa screen coordinates is always
137 the BOTTOM-right corner of this screen.  Recall that Cocoa uses cartesian coordinates so y-increase is up.
138
139 It isn't clearly documented but visibleFrame returns a rectangle in screen coordinates, not a rectangle
140 relative to that screen's frame.  The only real way to test this is to configure two screens one atop
141 the other such that the menubar screen is on top.  The Dock at the bottom of the screen will then
142 eat into the visibleFrame of screen 1 by incrementing it's y-origin.  Thus if you arrange two
143 1920x1200 screens top/bottom then screen 1 (the bottom screen) will have frame origin (0,-1200) and
144 visibleFrame origin (0,-1149) which is exactly 51 pixels higher than the full frame origin.
145
146 In wxCocoa, we somewhat arbitrarily declare that wx (0,0) is the TOP-left of screen 0's frame (the entire screen).
147 However, this isn't entirely arbitrary because the Quartz Display Services (CGDisplay) uses this same scheme.
148 This works out nicely because wxCocoa's wxDisplay is implemented using Quartz Display Services instead of NSScreen.
149 */
150
151 namespace { // file namespace
152
153 class wxCocoaPrivateScreenCoordinateTransformer
154 {
155     DECLARE_NO_COPY_CLASS(wxCocoaPrivateScreenCoordinateTransformer)
156 public:
157     wxCocoaPrivateScreenCoordinateTransformer();
158     ~wxCocoaPrivateScreenCoordinateTransformer();
159     wxPoint OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame);
160     NSPoint OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible);
161
162 protected:
163     NSScreen *m_screenZero;
164     NSRect m_screenZeroFrame;
165 };
166
167 // NOTE: This is intended to be a short-lived object.  A future enhancment might
168 // make it a global and reconfigure it upon some notification that the screen layout
169 // has changed.
170 inline wxCocoaPrivateScreenCoordinateTransformer::wxCocoaPrivateScreenCoordinateTransformer()
171 {
172     NSArray *screens = [NSScreen screens];
173
174     [screens retain];
175
176     m_screenZero = nil;
177     if(screens != nil && [screens count] > 0)
178         m_screenZero = [[screens objectAtIndex:0] retain];
179
180     [screens release];
181
182     if(m_screenZero != nil)
183         m_screenZeroFrame = [m_screenZero frame];
184     else
185     {
186         wxLogWarning(wxT("Can't translate to/from wx screen coordinates and Cocoa screen coordinates"));
187         // Just blindly assume 1024x768 so that at least we can sort of flip things around into
188         // Cocoa coordinates.
189         // NOTE: Theoretically this case should never happen anyway.
190         m_screenZeroFrame = NSMakeRect(0,0,1024,768);
191     }
192 }
193
194 inline wxCocoaPrivateScreenCoordinateTransformer::~wxCocoaPrivateScreenCoordinateTransformer()
195 {
196     [m_screenZero release];
197     m_screenZero = nil;
198 }
199
200 inline wxPoint wxCocoaPrivateScreenCoordinateTransformer::OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame)
201 {
202     // x and y are in wx screen coordinates which we're going to arbitrarily define such that
203     // (0,0) is the TOP-left of screen 0 (the one with the menubar)
204     // NOTE WELL: This means that (0,0) is _NOT_ an appropriate position for a window.
205
206     wxPoint theWxOrigin;
207
208     // Working in Cocoa's screen coordinates we must realize that the x coordinate we want is
209     // the distance between the left side (origin.x) of the window's frame and the left side of
210     // screen zero's frame.
211     theWxOrigin.x = windowFrame.origin.x - m_screenZeroFrame.origin.x;
212
213     // Working in Cocoa's screen coordinates we must realize that the y coordinate we want is
214     // actually the distance between the top-left of the screen zero frame and the top-left
215     // of the window's frame.
216
217     theWxOrigin.y = (m_screenZeroFrame.origin.y + m_screenZeroFrame.size.height) - (windowFrame.origin.y + windowFrame.size.height);
218
219     return theWxOrigin;
220 }
221
222 inline NSPoint wxCocoaPrivateScreenCoordinateTransformer::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible)
223 {
224     NSPoint theCocoaOrigin;
225
226     // The position is in wx screen coordinates which we're going to arbitrarily define such that
227     // (0,0) is the TOP-left of screen 0 (the one with the menubar)
228
229     // NOTE: The usable rectangle is smaller and hence we have the keepOriginVisible flag
230     // which will move the origin downward and/or left as necessary if the origin is
231     // inside the screen0 rectangle (i.e. x/y >= 0 in wx coordinates) and outside the
232     // visible frame (i.e. x/y < the top/left of the screen0 visible frame in wx coordinates)
233     // We don't munge origin coordinates < 0 because it actually is possible that the menubar is on
234     // the top of the bottom screen and thus that origin is completely valid!
235     if(keepOriginVisible && (m_screenZero != nil))
236     {
237         // Do al of this in wx coordinates because it's far simpler since we're dealing with top/left points
238         wxPoint visibleOrigin = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates([m_screenZero visibleFrame]);
239         if(x >= 0 && x < visibleOrigin.x)
240             x = visibleOrigin.x;
241         if(y >= 0 && y < visibleOrigin.y)
242             y = visibleOrigin.y;
243     }
244
245     // The x coordinate is simple as it's just relative to screen zero's frame
246     theCocoaOrigin.x = m_screenZeroFrame.origin.x + x;
247     // Working in Cocoa's coordinates think to start at the bottom of screen zero's frame and add
248     // the height of that rect which gives us the coordinate for the top of the visible rect.  Now realize that
249     // the wx coordinates are flipped so if y is say 10 then we want to be 10 pixels down from that and thus
250     // we subtract y.  But then we still need to take into account the size of the window which is h and subtract
251     // that to get the bottom-left origin of the rectangle.
252     theCocoaOrigin.y = m_screenZeroFrame.origin.y + m_screenZeroFrame.size.height - y - height;
253
254     return theCocoaOrigin;
255 }
256
257 } // namespace
258
259 wxPoint wxWindowCocoa::OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame)
260 {
261     wxCocoaPrivateScreenCoordinateTransformer transformer;
262     return transformer.OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(windowFrame);
263 }
264
265 NSPoint wxWindowCocoa::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible)
266 {
267     wxCocoaPrivateScreenCoordinateTransformer transformer;
268     return transformer.OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x,y,width,height,keepOriginVisible);
269 }
270
271 // ========================================================================
272 // wxWindowCocoaHider
273 // ========================================================================
274 class wxWindowCocoaHider: protected wxCocoaNSView
275 {
276     DECLARE_NO_COPY_CLASS(wxWindowCocoaHider)
277 public:
278     wxWindowCocoaHider(wxWindow *owner);
279     virtual ~wxWindowCocoaHider();
280     inline WX_NSView GetNSView() { return m_dummyNSView; }
281 protected:
282     wxWindowCocoa *m_owner;
283     WX_NSView m_dummyNSView;
284     virtual void Cocoa_FrameChanged(void);
285     virtual void Cocoa_synthesizeMouseMoved(void) {}
286 #ifdef WXCOCOA_FILL_DUMMY_VIEW
287     virtual bool Cocoa_drawRect(const NSRect& rect);
288 #endif //def WXCOCOA_FILL_DUMMY_VIEW
289 private:
290     wxWindowCocoaHider();
291 };
292
293 // ========================================================================
294 // wxDummyNSView
295 // ========================================================================
296 @interface wxDummyNSView : NSView
297 - (NSView *)hitTest:(NSPoint)aPoint;
298 @end
299 WX_DECLARE_GET_OBJC_CLASS(wxDummyNSView,NSView)
300
301 @implementation wxDummyNSView : NSView
302 - (NSView *)hitTest:(NSPoint)aPoint
303 {
304     return nil;
305 }
306
307 @end
308 WX_IMPLEMENT_GET_OBJC_CLASS(wxDummyNSView,NSView)
309
310 // ========================================================================
311 // wxWindowCocoaHider
312 //  NOTE: This class and method of hiding predates setHidden: support in
313 //  the toolkit.  The hack used here is to replace the view with a stand-in
314 //  that will be subject to the usual Cocoa resizing rules.
315 //  When possible (i.e. when running on 10.3 or higher) we make it hidden
316 //  mostly as an optimization so Cocoa doesn't have to consider it when
317 //  drawing or finding key views.
318 // ========================================================================
319 wxWindowCocoaHider::wxWindowCocoaHider(wxWindow *owner)
320 :   m_owner(owner)
321 {
322     wxASSERT(owner);
323     wxASSERT(owner->GetNSViewForHiding());
324     m_dummyNSView = [[WX_GET_OBJC_CLASS(wxDummyNSView) alloc]
325         initWithFrame:[owner->GetNSViewForHiding() frame]];
326     [m_dummyNSView setAutoresizingMask: [owner->GetNSViewForHiding() autoresizingMask]];
327     AssociateNSView(m_dummyNSView);
328
329     if([m_dummyNSView respondsToSelector:@selector(setHidden:)])
330         [m_dummyNSView setHidden:YES];
331 }
332
333 wxWindowCocoaHider::~wxWindowCocoaHider()
334 {
335     DisassociateNSView(m_dummyNSView);
336     [m_dummyNSView release];
337 }
338
339 void wxWindowCocoaHider::Cocoa_FrameChanged(void)
340 {
341     // Keep the real window in synch with the dummy
342     wxASSERT(m_dummyNSView);
343     [m_owner->GetNSViewForHiding() setFrame:[m_dummyNSView frame]];
344 }
345
346
347 #ifdef WXCOCOA_FILL_DUMMY_VIEW
348 bool wxWindowCocoaHider::Cocoa_drawRect(const NSRect& rect)
349 {
350     NSBezierPath *bezpath = [NSBezierPath bezierPathWithRect:rect];
351     [[NSColor greenColor] set];
352     [bezpath stroke];
353     [bezpath fill];
354     return true;
355 }
356 #endif //def WXCOCOA_FILL_DUMMY_VIEW
357
358
359 /*! @class WXManualScrollView
360     @abstract   An NSScrollView subclass which implements wx scroll behavior
361     @discussion
362     Overrides default behavior of NSScrollView such that this class receives
363     the scroller action messages and allows the wxCocoaScrollView to act
364     on them accordingly.  In particular, because the NSScrollView will not
365     receive action messages from the scroller, it will not adjust the
366     document view.  This must be done manually using the ScrollWindow
367     method of wxWindow.
368  */
369 @interface WXManualScrollView : NSScrollView
370 {
371     /*! @field      m_wxCocoaScrollView
372      */
373     wxWindowCocoaScrollView *m_wxCocoaScrollView;
374 }
375
376 // Override these to set up the target/action correctly
377 - (void)setHorizontalScroller:(NSScroller *)aScroller;
378 - (void)setVerticalScroller:(NSScroller *)aScroller;
379 - (void)setHasHorizontalScroller:(BOOL)flag;
380 - (void)setHasVerticalScroller:(BOOL)flag;
381
382 // NOTE: _wx_ prefix means "private" method like _ that Apple (and only Apple) uses.
383 - (wxWindowCocoaScrollView*)_wx_wxCocoaScrollView;
384 - (void)_wx_setWxCocoaScrollView:(wxWindowCocoaScrollView*)theWxScrollView;
385
386 /*! @method     _wx_doScroller
387     @abstract   Handles action messages from the scrollers
388     @discussion
389     Similar to Apple's _doScroller: method which is private and not documented.
390     We do not, however, call that method.  Instead, we effectively override
391     it entirely.  We don't override it by naming ourself the same thing because
392     the base class code may or may not call that method for other reasons we
393     simply cannot know about.
394  */
395 - (void)_wx_doScroller:(id)sender;
396
397 @end
398
399
400 @implementation WXManualScrollView : NSScrollView
401
402 static inline void WXManualScrollView_DoSetScrollerTargetAction(WXManualScrollView *self, NSScroller *aScroller)
403 {
404     if(aScroller != NULL && [self _wx_wxCocoaScrollView] != NULL)
405     {
406         [aScroller setTarget:self];
407         [aScroller setAction:@selector(_wx_doScroller:)];
408     }
409 }
410
411 - (void)setHorizontalScroller:(NSScroller *)aScroller
412 {
413     [super setHorizontalScroller:aScroller];
414     WXManualScrollView_DoSetScrollerTargetAction(self, aScroller);
415 }
416
417 - (void)setVerticalScroller:(NSScroller *)aScroller
418 {
419     [super setVerticalScroller:aScroller];
420     WXManualScrollView_DoSetScrollerTargetAction(self, aScroller);
421 }
422
423 - (void)setHasHorizontalScroller:(BOOL)flag
424 {
425     [super setHasHorizontalScroller:flag];
426     WXManualScrollView_DoSetScrollerTargetAction(self, [self horizontalScroller]);
427 }
428
429 - (void)setHasVerticalScroller:(BOOL)flag
430 {
431     [super setHasVerticalScroller:flag];
432     WXManualScrollView_DoSetScrollerTargetAction(self, [self verticalScroller]);
433 }
434
435 - (wxWindowCocoaScrollView*)_wx_wxCocoaScrollView
436 {   return m_wxCocoaScrollView; }
437
438 - (void)_wx_setWxCocoaScrollView:(wxWindowCocoaScrollView*)theWxScrollView
439 {
440     m_wxCocoaScrollView = theWxScrollView;
441     [self setHorizontalScroller:[self horizontalScroller]];
442     [self setVerticalScroller:[self verticalScroller]];
443 }
444
445 - (void)_wx_doScroller:(id)sender
446 {
447     if(m_wxCocoaScrollView != NULL)
448         m_wxCocoaScrollView->_wx_doScroller(sender);
449     else
450         wxLogError(wxT("Unexpected action message received from NSScroller"));
451 }
452
453 - (void)reflectScrolledClipView:(NSClipView *)aClipView
454 {
455     struct _ScrollerBackup
456     {
457         _ScrollerBackup(NSScroller *aScroller)
458         :   m_scroller(aScroller)
459         ,   m_floatValue(aScroller!=nil?[aScroller floatValue]:0.0)
460         ,   m_knobProportion(aScroller!=nil?[aScroller knobProportion]:1.0)
461         ,   m_isEnabled(aScroller!=nil?[aScroller isEnabled]:false)
462         {
463         }
464         NSScroller *m_scroller;
465         CGFloat m_floatValue;
466         CGFloat m_knobProportion;
467         BOOL m_isEnabled;
468         ~_ScrollerBackup()
469         {
470             if(m_scroller != nil)
471             {
472                 [m_scroller setFloatValue:m_floatValue knobProportion:m_knobProportion];
473                 [m_scroller setEnabled:m_isEnabled];
474             }
475         }
476     private:
477         _ScrollerBackup();
478         _ScrollerBackup(_ScrollerBackup const&);
479         _ScrollerBackup& operator=(_ScrollerBackup const&);
480     };
481     _ScrollerBackup _horizontalBackup([self horizontalScroller]);
482     _ScrollerBackup _verticalBackup([self verticalScroller]);
483     // We MUST call super's implementation or else nothing seems to work right at all.
484     // However, we need our scrollers not to change values due to the document window
485     // moving so we cheat and save/restore their values across this call.
486     [super reflectScrolledClipView: aClipView];
487 }
488
489 @end
490 WX_IMPLEMENT_GET_OBJC_CLASS(WXManualScrollView,NSScrollView)
491
492 // ========================================================================
493 // wxFlippedNSClipView
494 // ========================================================================
495 @interface wxFlippedNSClipView : NSClipView
496 - (BOOL)isFlipped;
497 @end
498 WX_DECLARE_GET_OBJC_CLASS(wxFlippedNSClipView,NSClipView)
499
500 @implementation wxFlippedNSClipView : NSClipView
501 - (BOOL)isFlipped
502 {
503     return YES;
504 }
505
506 @end
507 WX_IMPLEMENT_GET_OBJC_CLASS(wxFlippedNSClipView,NSClipView)
508
509 // ========================================================================
510 // wxWindowCocoaScrollView
511 // ========================================================================
512 wxWindowCocoaScrollView::wxWindowCocoaScrollView(wxWindow *owner)
513 :   m_owner(owner)
514 ,   m_cocoaNSScrollView() // nil
515 ,   m_scrollRange() // {0,0}
516 ,   m_scrollThumb() // {0,0}
517 ,   m_virtualOrigin(0,0)
518 {
519     wxAutoNSAutoreleasePool pool;
520     wxASSERT(owner);
521     wxASSERT(owner->GetNSView());
522     m_isNativeView = ![owner->GetNSView() isKindOfClass:[WX_GET_OBJC_CLASS(WXNSView) class]];
523     m_cocoaNSScrollView = [(m_isNativeView?[NSScrollView alloc]:[WXManualScrollView alloc])
524         initWithFrame:[owner->GetNSView() frame]];
525     AssociateNSView(m_cocoaNSScrollView);
526     if(m_isNativeView)
527     {
528         /*  Set a bezel border around the entire thing because it looks funny without it.
529             TODO: Be sure to undo any borders on the real view (if any) and apply them
530             to this view if necessary. Right now, there is no border support in wxCocoa
531             so this isn't an issue.
532          */
533         [m_cocoaNSScrollView setBorderType:NSBezelBorder];
534     }
535     else
536     {
537         [(WXManualScrollView*)m_cocoaNSScrollView _wx_setWxCocoaScrollView: this];
538         // Don't set a bezel because we might be creating a scroll view due to being
539         // the "target window" of a wxScrolledWindow.  That is to say that the user
540         // has absolutely no intention of scrolling the clip view used by this
541         // NSScrollView.
542     }
543
544     /* Replace the default NSClipView with a flipped one.  This ensures
545        scrolling is "pinned" to the top-left instead of bottom-right. */
546     NSClipView *flippedClip = [[WX_GET_OBJC_CLASS(wxFlippedNSClipView) alloc]
547         initWithFrame: [[m_cocoaNSScrollView contentView] frame]];
548     [m_cocoaNSScrollView setContentView:flippedClip];
549     [flippedClip release];
550
551     // In all cases we must encapsulate the real NSView properly
552     Encapsulate();
553 }
554
555 void wxWindowCocoaScrollView::Encapsulate()
556 {
557     // Set the scroll view autoresizingMask to match the current NSView
558     [m_cocoaNSScrollView setAutoresizingMask: [m_owner->GetNSView() autoresizingMask]];
559     [m_owner->GetNSView() setAutoresizingMask: NSViewNotSizable];
560     // NOTE: replaceSubView will cause m_cocaNSView to be released
561     // except when it hasn't been added into an NSView hierarchy in which
562     // case it doesn't need to be and this should work out to a no-op
563     m_owner->CocoaReplaceView(m_owner->GetNSView(), m_cocoaNSScrollView);
564     // The NSView is still retained by owner
565     [m_cocoaNSScrollView setDocumentView: m_owner->GetNSView()];
566     // Now it's also retained by the NSScrollView
567 }
568
569 void wxWindowCocoaScrollView::Unencapsulate()
570 {
571     [m_cocoaNSScrollView setDocumentView: nil];
572     m_owner->CocoaReplaceView(m_cocoaNSScrollView, m_owner->GetNSView());
573     if(![[m_owner->GetNSView() superview] isFlipped])
574         [m_owner->GetNSView() setAutoresizingMask: NSViewMinYMargin];
575 }
576
577 wxWindowCocoaScrollView::~wxWindowCocoaScrollView()
578 {
579     DisassociateNSView(m_cocoaNSScrollView);
580     if(!m_isNativeView)
581     {
582         [(WXManualScrollView*)m_cocoaNSScrollView _wx_setWxCocoaScrollView:NULL];
583     }
584     [m_cocoaNSScrollView release];
585 }
586
587 void wxWindowCocoaScrollView::ClientSizeToSize(int &width, int &height)
588 {
589     NSSize frameSize = [NSScrollView
590         frameSizeForContentSize: NSMakeSize(width,height)
591         hasHorizontalScroller: [m_cocoaNSScrollView hasHorizontalScroller]
592         hasVerticalScroller: [m_cocoaNSScrollView hasVerticalScroller]
593         borderType: [m_cocoaNSScrollView borderType]];
594     width = (int)frameSize.width;
595     height = (int)frameSize.height;
596 }
597
598 void wxWindowCocoaScrollView::DoGetClientSize(int *x, int *y) const
599 {
600     NSSize nssize = [m_cocoaNSScrollView contentSize];
601     if(x)
602         *x = (int)nssize.width;
603     if(y)
604         *y = (int)nssize.height;
605 }
606
607 static inline void SetCocoaScroller(NSScroller *aScroller, int WXUNUSED(orientation), int position, int thumbSize, int range)
608 {
609     wxCHECK_RET(aScroller != nil, wxT("Expected the NSScrollView to have a scroller"));
610
611     // NOTE: thumbSize is already ensured to be >= 1 and <= range by our caller
612     // unless range = 0 in which case we shouldn't have been be called.
613     wxCHECK_RET(range > 0, wxT("Internal wxCocoa bug: shouldn't have been called with 0 range"));
614
615     // Range of valid position values is from 0 to effectiveRange
616     // NOTE: if thumbSize == range then effectiveRange is 0.
617     // thumbSize is at least 1 which gives range from 0 to range - 1 inclusive
618     // which is exactly what we want.
619     int effectiveRange = range - thumbSize;
620
621     // knobProportion is hopefully easy to understand
622     // Note that thumbSize is already guaranteed >= 1 by our caller.
623     CGFloat const knobProportion = CGFloat(thumbSize)/CGFloat(range);
624
625     // NOTE: When effectiveRange is zero there really is no valid position
626     // We arbitrarily pick 0.0 which is the same as a scroller in the home position.
627     CGFloat const floatValue = (effectiveRange != 0)?CGFloat(position)/CGFloat(effectiveRange):0.0;
628
629     [aScroller setFloatValue:floatValue knobProportion: knobProportion];
630     // Make sure it's visibly working
631     [aScroller setEnabled:YES];
632 }
633
634 void wxWindowCocoaScrollView::SetScrollPos(wxOrientation orientation, int position)
635 {
636     // NOTE: Rather than using only setFloatValue: (which we could do) we instead
637     // simply share the SetCocoaScroller call because all but the knobProportion
638     // calculations have to be done anyway.
639     if(orientation & wxHORIZONTAL)
640     {
641         NSScroller *aScroller = [m_cocoaNSScrollView horizontalScroller];
642         if(aScroller != nil)
643             SetCocoaScroller(aScroller, orientation, position, m_scrollThumb[0], m_scrollRange[0]);
644     }
645     if(orientation & wxVERTICAL)
646     {
647         NSScroller *aScroller = [m_cocoaNSScrollView verticalScroller];
648         if(aScroller != nil)
649             SetCocoaScroller(aScroller, orientation, position, m_scrollThumb[1], m_scrollRange[1]);
650     }
651 }
652
653 void wxWindowCocoaScrollView::SetScrollbar(int orientation, int position, int thumbSize, int range)
654 {
655     // FIXME: API assumptions:
656     // 1. If the user wants to remove a scroller he gives range 0.
657     // 2. If the user wants to disable a scroller he sets thumbSize == range
658     //    in which case it is logically impossible to scroll.
659     //    The scroller shall still be displayed.
660
661     // Ensure that range is >= 0.
662     wxASSERT(range >= 0);
663     if(range < 0)
664         range = 0;
665
666     // Ensure that thumbSize <= range
667     wxASSERT(thumbSize <= range);
668     // Also ensure thumbSize >= 1 but don't complain if it isn't
669     if(thumbSize < 1)
670         thumbSize = 1;
671     // Now make sure it's really less than range, even if we just set it to 1
672     if(thumbSize > range)
673         thumbSize = range;
674
675     bool needScroller = (range != 0);
676
677     // Can potentially set both horizontal and vertical at the same time although this is
678     // probably not very useful.
679     if(orientation & wxHORIZONTAL)
680     {
681         m_scrollRange[0] = range;
682         m_scrollThumb[0] = thumbSize;
683         if(!m_isNativeView)
684         {
685             [m_cocoaNSScrollView setHasHorizontalScroller:needScroller];
686             if(needScroller)
687                 SetCocoaScroller([m_cocoaNSScrollView horizontalScroller], orientation, position, thumbSize, range);
688         }
689     }
690
691     if(orientation & wxVERTICAL)
692     {
693         m_scrollRange[1] = range;
694         m_scrollThumb[1] = thumbSize;
695         if(!m_isNativeView)
696         {
697             [m_cocoaNSScrollView setHasVerticalScroller:needScroller];
698             if(needScroller)
699                 SetCocoaScroller([m_cocoaNSScrollView verticalScroller], orientation, position, thumbSize, range);
700         }
701     }
702 }
703
704 int wxWindowCocoaScrollView::GetScrollPos(wxOrientation orient)
705 {
706     if((orient & wxBOTH) == wxBOTH)
707     {
708         wxLogError(wxT("GetScrollPos called for wxHORIZONTAL and wxVERTICAL together which makes no sense"));
709         return 0;
710     }
711     int effectiveScrollRange;
712     NSScroller *cocoaScroller;
713     if(orient & wxHORIZONTAL)
714     {
715         effectiveScrollRange = m_scrollRange[0] - m_scrollThumb[0];
716         cocoaScroller = [m_cocoaNSScrollView horizontalScroller];
717     }
718     else if(orient & wxVERTICAL)
719     {
720         effectiveScrollRange = m_scrollRange[1] - m_scrollThumb[1];
721         cocoaScroller = [m_cocoaNSScrollView verticalScroller];
722     }
723     else
724     {
725         wxLogError(wxT("GetScrollPos called without an orientation which makes no sense"));
726         return 0;
727     }
728     if(cocoaScroller == nil)
729     {   // Document is not scrolled
730         return 0;
731     }
732     /*
733         The effective range of a scroll bar as defined by wxWidgets is from 0 to (range - thumbSize).
734         That is a scroller at the left/top position is at 0 and a scroller at the bottom/right
735         position is at range-thumbsize.
736
737         The range of an NSScroller is 0.0 to 1.0.  Much easier! NOTE: Apple doesn't really specify
738         but GNUStep docs do say that 0.0 is top/left and 1.0 is bottom/right.  This is actualy
739         in contrast to NSSlider which generally has 1.0 at the TOP when it's done vertically.
740      */
741     CGFloat cocoaScrollPos = [cocoaScroller floatValue];
742     return effectiveScrollRange * cocoaScrollPos;
743 }
744
745 int wxWindowCocoaScrollView::GetScrollRange(wxOrientation orient)
746 {
747     if((orient & wxBOTH) == wxBOTH)
748     {
749         wxLogError(wxT("GetScrollRange called for wxHORIZONTAL and wxVERTICAL together which makes no sense"));
750         return 0;
751     }
752     if(orient & wxHORIZONTAL)
753     {
754         return m_scrollRange[0];
755     }
756     else if(orient & wxVERTICAL)
757     {
758         return m_scrollRange[1];
759     }
760     else
761     {
762         wxLogError(wxT("GetScrollPos called without an orientation which makes no sense"));
763         return 0;
764     }
765 }
766
767 int wxWindowCocoaScrollView::GetScrollThumb(wxOrientation orient)
768 {
769     if((orient & wxBOTH) == wxBOTH)
770     {
771         wxLogError(wxT("GetScrollThumb called for wxHORIZONTAL and wxVERTICAL together which makes no sense"));
772         return 0;
773     }
774     if(orient & wxHORIZONTAL)
775     {
776         return m_scrollThumb[0];
777     }
778     else if(orient & wxVERTICAL)
779     {
780         return m_scrollThumb[1];
781     }
782     else
783     {
784         wxLogError(wxT("GetScrollThumb called without an orientation which makes no sense"));
785         return 0;
786     }
787 }
788
789 /*!
790     Moves the contents (all existing drawing as well as all all child wxWindow) by the specified
791     amount expressed in the wxWindow's own coordinate system.  This is used to implement scrolling
792     but the usage is rather interesting.  When scrolling right (e.g. increasing the value of
793     the scroller) you must give a negative delta x (e.g. moving the contents LEFT).  Likewise,
794     when scrolling the window down, increasing the value of the scroller, you give a negative
795     delta y which moves the contents up.
796
797     wxCocoa notes: To accomplish this trick in Cocoa we basically do what NSScrollView would
798     have done and that is adjust the content view's bounds origin.  The content view is somewhat
799     confusingly the NSClipView which is more or less sort of the pImpl for NSScrollView
800     The real NSView with the user's content (e.g. the "virtual area" in wxWidgets parlance)
801     is called the document view in NSScrollView parlance.
802
803     The bounds origin is basically the exact opposite concept.  Whereas in Windows the client
804     coordinate system remains constant and the content must shift left/up for increases
805     of scrolling, in Cocoa the coordinate system is actually the virtual one.  So we must
806     instead shift the bounds rectangle right/down to get the effect of the content moving
807     left/up.  Basically, it's a higher level interface than that provided by wxWidgets
808     so essentially we're implementing the low-level move content interface in terms of
809     the high-level move the viewport (the bounds) over top that content (the document
810     view which is the virtual area to wx).
811
812     For all intents and purposes that basically just means that we subtract the deltas
813     from the bounds origin and thus a negative delta actually increases the bounds origin
814     and a positive delta actually decreases it.  This is absolutely true for the horizontal
815     axis but there's a catch in the vertical axis.  If the content view (the clip view) is
816     flipped (and we do this by default) then it works exactly like the horizontal axis.
817     If it is not flipped (i.e. it is in postscript coordinates which are opposite to
818     wxWidgets) then the sense needs to be reversed.
819
820     However, this plays hell with window positions.  The frame rects of any child views
821     do not change origin and this is actually important because if they did, the views
822     would send frame changed notifications, not to mention that Cocoa just doesn't really
823     do scrolling that way, it does it the way we do it here.
824
825     To fix this we implement GetPosition for child windows to not merely consult its
826     superview at the Cocoa level in order to do proper Cocoa->wx coordinate transform
827     but to actually consult is parent wxWindow because it makes a big difference if
828     the parent is scrolled. Argh.  (FIXME: This isn't actually implemented yet)
829  */
830 void wxWindowCocoaScrollView::ScrollWindow(int dx, int dy, const wxRect*)
831 {
832     // Update our internal origin so we know how much the application code
833     // expects us to have been scrolled.
834     m_virtualOrigin.x += dx;
835     m_virtualOrigin.y += dy;
836
837     // Scroll the window using the standard Cocoa method of adjusting the
838     // clip view's bounds in the opposite fashion.
839     NSClipView *contentView = [m_cocoaNSScrollView contentView];
840     NSRect clipViewBoundsRect = [contentView bounds];
841     clipViewBoundsRect.origin.x -= dx;
842     if([contentView isFlipped])
843         clipViewBoundsRect.origin.y -= dy;
844     else
845         clipViewBoundsRect.origin.y += dy;
846     [contentView scrollToPoint:clipViewBoundsRect.origin];
847 }
848
849 void wxWindowCocoaScrollView::_wx_doScroller(NSScroller *sender)
850 {
851     wxOrientation orientation;
852     if(sender == [m_cocoaNSScrollView horizontalScroller])
853         orientation = wxHORIZONTAL;
854     else if(sender == [m_cocoaNSScrollView verticalScroller])
855         orientation = wxVERTICAL;
856     else
857     {
858         wxLogDebug(wxT("Received action message from unexpected NSScroller"));
859         return;
860     }
861     // NOTE: Cocoa does not move the scroller for page up/down or line
862     // up/down events.  That means the value will be the old value.
863     // For thumbtrack events, the value is the new value.
864     int scrollpos = GetScrollPos(orientation);
865     int commandType;
866     switch([sender hitPart])
867     {
868     default:
869     case NSScrollerNoPart:
870     case NSScrollerKnob:        // Drag of knob
871     case NSScrollerKnobSlot:    // Jump directly to position
872         commandType = wxEVT_SCROLLWIN_THUMBTRACK;
873         break;
874     case NSScrollerDecrementPage:
875         commandType = wxEVT_SCROLLWIN_PAGEUP;
876         break;
877     case NSScrollerIncrementPage:
878         commandType = wxEVT_SCROLLWIN_PAGEDOWN;
879         break;
880     case NSScrollerDecrementLine:
881         commandType = wxEVT_SCROLLWIN_LINEUP;
882         break;
883     case NSScrollerIncrementLine:
884         commandType = wxEVT_SCROLLWIN_LINEDOWN;
885         break;
886     }
887     wxScrollWinEvent event(commandType, scrollpos, orientation);
888     event.SetEventObject(m_owner);
889     m_owner->HandleWindowEvent(event);
890 }
891
892 void wxWindowCocoaScrollView::UpdateSizes()
893 {
894     // Using the virtual size, figure out what the document frame size should be
895     // NOTE: Assume that the passed in virtualSize is already >= the client size
896     wxSize virtualSize = m_owner->GetVirtualSize();
897
898     // Get the document's current frame
899     NSRect documentViewFrame = [m_owner->GetNSView() frame];
900     NSRect newFrame = documentViewFrame;
901     newFrame.size = NSMakeSize(virtualSize.x, virtualSize.y);
902
903     if(!NSEqualRects(newFrame, documentViewFrame))
904     {
905         [m_owner->GetNSView() setFrame:newFrame];
906     }
907 }
908
909 void wxWindowCocoaScrollView::Cocoa_FrameChanged(void)
910 {
911     wxLogTrace(wxTRACE_COCOA,wxT("wxWindowCocoaScrollView=%p::Cocoa_FrameChanged for wxWindow %p"), this, m_owner);
912     wxSizeEvent event(m_owner->GetSize(), m_owner->GetId());
913     event.SetEventObject(m_owner);
914     m_owner->HandleWindowEvent(event);
915
916     /*  If the view is not a native one then it's being managed by wx.  In this case the control
917         may decide to change its virtual size and we must update the document view's size to
918         match.  For native views the virtual size will never have been set so we do not want
919         to use it at all.
920      */
921     if(!m_isNativeView)
922         UpdateSizes();
923 }
924
925 // ========================================================================
926 // wxWindowCocoa
927 // ========================================================================
928 // normally the base classes aren't included, but wxWindow is special
929 #ifdef __WXUNIVERSAL__
930 IMPLEMENT_ABSTRACT_CLASS(wxWindowCocoa, wxWindowBase)
931 #else
932 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
933 #endif
934
935 BEGIN_EVENT_TABLE(wxWindowCocoa, wxWindowBase)
936 END_EVENT_TABLE()
937
938 wxWindow *wxWindowCocoa::sm_capturedWindow = NULL;
939
940 // Constructor
941 void wxWindowCocoa::Init()
942 {
943     m_cocoaNSView = NULL;
944     m_cocoaHider = NULL;
945     m_wxCocoaScrollView = NULL;
946     m_isBeingDeleted = false;
947     m_isInPaint = false;
948     m_visibleTrackingRectManager = NULL;
949 }
950
951 // Constructor
952 bool wxWindow::Create(wxWindow *parent, wxWindowID winid,
953            const wxPoint& pos,
954            const wxSize& size,
955            long style,
956            const wxString& name)
957 {
958     if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
959         return false;
960
961     // TODO: create the window
962     m_cocoaNSView = NULL;
963     SetNSView([[WX_GET_OBJC_CLASS(WXNSView) alloc] initWithFrame: MakeDefaultNSRect(size)]);
964     [m_cocoaNSView release];
965
966     if (m_parent)
967     {
968         m_parent->AddChild(this);
969         m_parent->CocoaAddChild(this);
970         SetInitialFrameRect(pos,size);
971     }
972
973     return true;
974 }
975
976 // Destructor
977 wxWindow::~wxWindow()
978 {
979     wxAutoNSAutoreleasePool pool;
980     DestroyChildren();
981
982     // Make sure our parent (in the wxWidgets sense) is our superview
983     // before we go removing from it.
984     if(m_parent && m_parent->GetNSView()==[GetNSViewForSuperview() superview])
985         CocoaRemoveFromParent();
986     delete m_cocoaHider;
987     delete m_wxCocoaScrollView;
988     if(m_cocoaNSView)
989         SendDestroyEvent();
990     SetNSView(NULL);
991 }
992
993 void wxWindowCocoa::CocoaAddChild(wxWindowCocoa *child)
994 {
995     // Pool here due to lack of one during wx init phase
996     wxAutoNSAutoreleasePool pool;
997
998     NSView *childView = child->GetNSViewForSuperview();
999
1000     wxASSERT(childView);
1001     [m_cocoaNSView addSubview: childView];
1002 }
1003
1004 void wxWindowCocoa::CocoaRemoveFromParent(void)
1005 {
1006     [GetNSViewForSuperview() removeFromSuperview];
1007 }
1008
1009 void wxWindowCocoa::SetNSView(WX_NSView cocoaNSView)
1010 {
1011     // Clear the visible area tracking rect if we have one.
1012     delete m_visibleTrackingRectManager;
1013     m_visibleTrackingRectManager = NULL;
1014
1015     bool need_debug = cocoaNSView || m_cocoaNSView;
1016     if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [m_cocoaNSView=%p retainCount]=%d"),this,m_cocoaNSView,[m_cocoaNSView retainCount]);
1017     DisassociateNSView(m_cocoaNSView);
1018     wxGCSafeRetain(cocoaNSView);
1019     wxGCSafeRelease(m_cocoaNSView);
1020     m_cocoaNSView = cocoaNSView;
1021     AssociateNSView(m_cocoaNSView);
1022     if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [cocoaNSView=%p retainCount]=%d"),this,cocoaNSView,[cocoaNSView retainCount]);
1023 }
1024
1025 WX_NSView wxWindowCocoa::GetNSViewForSuperview() const
1026 {
1027     return m_cocoaHider
1028         ?   m_cocoaHider->GetNSView()
1029         :   m_wxCocoaScrollView
1030             ?   m_wxCocoaScrollView->GetNSScrollView()
1031             :   m_cocoaNSView;
1032 }
1033
1034 WX_NSView wxWindowCocoa::GetNSViewForHiding() const
1035 {
1036     return m_wxCocoaScrollView
1037         ?   m_wxCocoaScrollView->GetNSScrollView()
1038         :   m_cocoaNSView;
1039 }
1040
1041 NSPoint wxWindowCocoa::CocoaTransformBoundsToWx(NSPoint pointBounds)
1042 {
1043     // TODO: Handle scrolling offset
1044     return CocoaTransformNSViewBoundsToWx(GetNSView(), pointBounds);
1045 }
1046
1047 NSRect wxWindowCocoa::CocoaTransformBoundsToWx(NSRect rectBounds)
1048 {
1049     // TODO: Handle scrolling offset
1050     return CocoaTransformNSViewBoundsToWx(GetNSView(), rectBounds);
1051 }
1052
1053 NSPoint wxWindowCocoa::CocoaTransformWxToBounds(NSPoint pointWx)
1054 {
1055     // TODO: Handle scrolling offset
1056     return CocoaTransformNSViewWxToBounds(GetNSView(), pointWx);
1057 }
1058
1059 NSRect wxWindowCocoa::CocoaTransformWxToBounds(NSRect rectWx)
1060 {
1061     // TODO: Handle scrolling offset
1062     return CocoaTransformNSViewWxToBounds(GetNSView(), rectWx);
1063 }
1064
1065 WX_NSAffineTransform wxWindowCocoa::CocoaGetWxToBoundsTransform()
1066 {
1067     // TODO: Handle scrolling offset
1068     NSAffineTransform *transform = wxCocoaDCImpl::CocoaGetWxToBoundsTransform([GetNSView() isFlipped], [GetNSView() bounds].size.height);
1069     return transform;
1070 }
1071
1072 bool wxWindowCocoa::Cocoa_drawRect(const NSRect &rect)
1073 {
1074     wxLogTrace(wxTRACE_COCOA,wxT("Cocoa_drawRect"));
1075     // Recursion can happen if the event loop runs from within the paint
1076     // handler.  For instance, if an assertion dialog is shown.
1077     // FIXME: This seems less than ideal.
1078     if(m_isInPaint)
1079     {
1080         wxLogDebug(wxT("Paint event recursion!"));
1081         return false;
1082     }
1083     m_isInPaint = true;
1084
1085     // Set m_updateRegion
1086     const NSRect *rects = &rect; // The bounding box of the region
1087     NSInteger countRects = 1;
1088     // Try replacing the larger rectangle with a list of smaller ones:
1089     if ([GetNSView() respondsToSelector:@selector(getRectsBeingDrawn:count:)])
1090         [GetNSView() getRectsBeingDrawn:&rects count:&countRects];
1091
1092     NSRect *transformedRects = (NSRect*)malloc(sizeof(NSRect)*countRects);
1093     for(int i=0; i<countRects; i++)
1094     {
1095         transformedRects[i] = CocoaTransformBoundsToWx(rects[i]);
1096     }
1097     m_updateRegion = wxRegion(transformedRects,countRects);
1098     free(transformedRects);
1099
1100     wxPaintEvent event(m_windowId);
1101     event.SetEventObject(this);
1102     bool ret = HandleWindowEvent(event);
1103     m_isInPaint = false;
1104     return ret;
1105 }
1106
1107 void wxWindowCocoa::InitMouseEvent(wxMouseEvent& event, WX_NSEvent cocoaEvent)
1108 {
1109     wxASSERT_MSG([m_cocoaNSView window]==[cocoaEvent window],wxT("Mouse event for different NSWindow"));
1110     // Mouse events happen at the NSWindow level so we need to convert
1111     // into our bounds coordinates then convert to wx coordinates.
1112     NSPoint cocoaPoint = [m_cocoaNSView convertPoint:[(NSEvent*)cocoaEvent locationInWindow] fromView:nil];
1113     if( m_wxCocoaScrollView != NULL)
1114     {
1115         // This gets the wx client area (i.e. the visible portion of the content) in
1116         // the coordinate system of our (the doucment) view.
1117         NSRect documentVisibleRect = [[m_wxCocoaScrollView->GetNSScrollView() contentView] documentVisibleRect];
1118         // For horizontal, simply subtract the origin.
1119         // e.g. if the origin is at 123 and the user clicks as far left as possible then
1120         // the coordinate that wx wants is 0.
1121         cocoaPoint.x -= documentVisibleRect.origin.x;
1122         if([m_cocoaNSView isFlipped])
1123         {
1124             // In the flipped view case this works exactly like horizontal.
1125             cocoaPoint.y -= documentVisibleRect.origin.y;
1126         }
1127         // For vertical we have to mind non-flipped (e.g. y=0 at bottom) views.
1128         // We also need to mind the fact that we're still in Cocoa coordinates
1129         // and not wx coordinates.  The wx coordinate translation will still occur
1130         // and that is going to be wxY = boundsH - cocoaY for non-flipped views.
1131
1132         // When we consider scrolling we are truly interested in how far the top
1133         // edge of the bounds rectangle is scrolled off the screen.
1134         // Assuming the bounds origin is 0 (which is an assumption we make in
1135         // wxCocoa since wxWidgets has no analog to it) then the top edge of
1136         // the bounds rectangle is simply its height.  The top edge of the
1137         // documentVisibleRect (e.g. the client area) is its height plus
1138         // its origin.
1139         // Thus, we simply need add the distance between the bounds top
1140         // and the client (docuemntVisibleRect) top.
1141         // Or putting it another way, we subtract the distance between the
1142         // client top and the bounds top.
1143         else
1144         {
1145             NSRect bounds = [m_cocoaNSView bounds];
1146             CGFloat scrollYOrigin = (bounds.size.height - (documentVisibleRect.origin.y + documentVisibleRect.size.height));
1147             cocoaPoint.y += scrollYOrigin;
1148         }
1149     }
1150
1151     NSPoint pointWx = CocoaTransformBoundsToWx(cocoaPoint);
1152     // FIXME: Should we be adjusting for client area origin?
1153     const wxPoint &clientorigin = GetClientAreaOrigin();
1154     event.m_x = (wxCoord)pointWx.x - clientorigin.x;
1155     event.m_y = (wxCoord)pointWx.y - clientorigin.y;
1156
1157     event.m_shiftDown = [cocoaEvent modifierFlags] & NSShiftKeyMask;
1158     event.m_controlDown = [cocoaEvent modifierFlags] & NSControlKeyMask;
1159     event.m_altDown = [cocoaEvent modifierFlags] & NSAlternateKeyMask;
1160     event.m_metaDown = [cocoaEvent modifierFlags] & NSCommandKeyMask;
1161
1162     // TODO: set timestamp?
1163     event.SetEventObject(this);
1164     event.SetId(GetId());
1165 }
1166
1167 bool wxWindowCocoa::Cocoa_mouseMoved(WX_NSEvent theEvent)
1168 {
1169     wxMouseEvent event(wxEVT_MOTION);
1170     InitMouseEvent(event,theEvent);
1171     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_mouseMoved @%d,%d"),this,event.m_x,event.m_y);
1172     return HandleWindowEvent(event);
1173 }
1174
1175 void wxWindowCocoa::Cocoa_synthesizeMouseMoved()
1176 {
1177     wxMouseEvent event(wxEVT_MOTION);
1178     NSWindow *window = [GetNSView() window];
1179     NSPoint locationInWindow = [window mouseLocationOutsideOfEventStream];
1180     NSPoint cocoaPoint = [m_cocoaNSView convertPoint:locationInWindow fromView:nil];
1181
1182     NSPoint pointWx = CocoaTransformBoundsToWx(cocoaPoint);
1183     // FIXME: Should we be adjusting for client area origin?
1184     const wxPoint &clientorigin = GetClientAreaOrigin();
1185     event.m_x = (wxCoord)pointWx.x - clientorigin.x;
1186     event.m_y = (wxCoord)pointWx.y - clientorigin.y;
1187
1188     // TODO: Handle shift, control, alt, meta flags
1189     event.SetEventObject(this);
1190     event.SetId(GetId());
1191
1192     wxLogTrace(wxTRACE_COCOA,wxT("wxwin=%p Synthesized Mouse Moved @%d,%d"),this,event.m_x,event.m_y);
1193     HandleWindowEvent(event);
1194 }
1195
1196 bool wxWindowCocoa::Cocoa_mouseEntered(WX_NSEvent theEvent)
1197 {
1198     if(m_visibleTrackingRectManager != NULL && m_visibleTrackingRectManager->IsOwnerOfEvent(theEvent))
1199     {
1200         m_visibleTrackingRectManager->BeginSynthesizingEvents();
1201
1202         // Although we synthesize the mouse moved events we don't poll for them but rather send them only when
1203         // some other event comes in.  That other event is (guess what) mouse moved events that will be sent
1204         // to the NSWindow which will forward them on to the first responder.  We are not likely to be the
1205         // first responder, so the mouseMoved: events are effectively discarded.
1206         [[GetNSView() window] setAcceptsMouseMovedEvents:YES];
1207
1208         wxMouseEvent event(wxEVT_ENTER_WINDOW);
1209         InitMouseEvent(event,theEvent);
1210         wxLogTrace(wxTRACE_COCOA_TrackingRect,wxT("wxwin=%p Mouse Entered TR#%d @%d,%d"),this,[theEvent trackingNumber], event.m_x,event.m_y);
1211         return HandleWindowEvent(event);
1212     }
1213     else
1214         return false;
1215 }
1216
1217 bool wxWindowCocoa::Cocoa_mouseExited(WX_NSEvent theEvent)
1218 {
1219     if(m_visibleTrackingRectManager != NULL && m_visibleTrackingRectManager->IsOwnerOfEvent(theEvent))
1220     {
1221         m_visibleTrackingRectManager->StopSynthesizingEvents();
1222
1223         wxMouseEvent event(wxEVT_LEAVE_WINDOW);
1224         InitMouseEvent(event,theEvent);
1225         wxLogTrace(wxTRACE_COCOA_TrackingRect,wxT("wxwin=%p Mouse Exited TR#%d @%d,%d"),this,[theEvent trackingNumber],event.m_x,event.m_y);
1226         return HandleWindowEvent(event);
1227     }
1228     else
1229         return false;
1230 }
1231
1232 bool wxWindowCocoa::Cocoa_mouseDown(WX_NSEvent theEvent)
1233 {
1234     wxMouseEvent event([theEvent clickCount]<2?wxEVT_LEFT_DOWN:wxEVT_LEFT_DCLICK);
1235     InitMouseEvent(event,theEvent);
1236     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]);
1237     return HandleWindowEvent(event);
1238 }
1239
1240 bool wxWindowCocoa::Cocoa_mouseDragged(WX_NSEvent theEvent)
1241 {
1242     wxMouseEvent event(wxEVT_MOTION);
1243     InitMouseEvent(event,theEvent);
1244     event.m_leftDown = true;
1245     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
1246     return HandleWindowEvent(event);
1247 }
1248
1249 bool wxWindowCocoa::Cocoa_mouseUp(WX_NSEvent theEvent)
1250 {
1251     wxMouseEvent event(wxEVT_LEFT_UP);
1252     InitMouseEvent(event,theEvent);
1253     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Up @%d,%d"),event.m_x,event.m_y);
1254     return HandleWindowEvent(event);
1255 }
1256
1257 bool wxWindowCocoa::Cocoa_rightMouseDown(WX_NSEvent theEvent)
1258 {
1259     wxMouseEvent event([theEvent clickCount]<2?wxEVT_RIGHT_DOWN:wxEVT_RIGHT_DCLICK);
1260     InitMouseEvent(event,theEvent);
1261     wxLogDebug(wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]);
1262     return HandleWindowEvent(event);
1263 }
1264
1265 bool wxWindowCocoa::Cocoa_rightMouseDragged(WX_NSEvent theEvent)
1266 {
1267     wxMouseEvent event(wxEVT_MOTION);
1268     InitMouseEvent(event,theEvent);
1269     event.m_rightDown = true;
1270     wxLogDebug(wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
1271     return HandleWindowEvent(event);
1272 }
1273
1274 bool wxWindowCocoa::Cocoa_rightMouseUp(WX_NSEvent theEvent)
1275 {
1276     wxMouseEvent event(wxEVT_RIGHT_UP);
1277     InitMouseEvent(event,theEvent);
1278     wxLogDebug(wxT("Mouse Up @%d,%d"),event.m_x,event.m_y);
1279     return HandleWindowEvent(event);
1280 }
1281
1282 bool wxWindowCocoa::Cocoa_otherMouseDown(WX_NSEvent theEvent)
1283 {
1284     return false;
1285 }
1286
1287 bool wxWindowCocoa::Cocoa_otherMouseDragged(WX_NSEvent theEvent)
1288 {
1289     return false;
1290 }
1291
1292 bool wxWindowCocoa::Cocoa_otherMouseUp(WX_NSEvent theEvent)
1293 {
1294     return false;
1295 }
1296
1297 void wxWindowCocoa::Cocoa_FrameChanged(void)
1298 {
1299     // We always get this message for the real NSView which may have been
1300     // enclosed in an NSScrollView.  If that's the case then what we're
1301     // effectively getting here is a notifcation that the
1302     // virtual sized changed.. which we don't need to send on since
1303     // wx has no concept of this whatsoever.
1304     bool isViewForSuperview = (m_wxCocoaScrollView == NULL);
1305     if(isViewForSuperview)
1306     {
1307         wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_FrameChanged"),this);
1308         if(m_visibleTrackingRectManager != NULL)
1309             m_visibleTrackingRectManager->RebuildTrackingRect();
1310         wxSizeEvent event(GetSize(), m_windowId);
1311         event.SetEventObject(this);
1312         HandleWindowEvent(event);
1313     }
1314     else
1315     {
1316         wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_FrameChanged ignored"),this);
1317     }
1318 }
1319
1320 bool wxWindowCocoa::Cocoa_resetCursorRects()
1321 {
1322     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_resetCursorRects"),this);
1323
1324     // When we are called there may be a queued tracking rect event (mouse entered or exited) and
1325     // we won't know it.  A specific example is wxGenericHyperlinkCtrl changing the cursor from its
1326     // mouse exited event.  If the control happens to share the edge with its parent window which is
1327     // also tracking mouse events then Cocoa receives two mouse exited events from the window server.
1328     // The first one will cause wxGenericHyperlinkCtrl to call wxWindow::SetCursor which will
1329     // invaildate the cursor rect causing Cocoa to schedule cursor rect reset with the run loop
1330     // which willl in turn call us before exiting for the next user event.
1331
1332     // If we are the parent window then rebuilding our tracking rectangle will cause us to miss
1333     // our mouse exited event because the already queued event will have the old tracking rect
1334     // tag.  The simple solution is to only rebuild our tracking rect if we need to.
1335
1336     if(m_visibleTrackingRectManager != NULL)
1337         m_visibleTrackingRectManager->RebuildTrackingRectIfNeeded();
1338
1339     if(!m_cursor.GetNSCursor())
1340         return false;
1341
1342     [GetNSView() addCursorRect: [GetNSView() visibleRect]  cursor: m_cursor.GetNSCursor()];
1343
1344     return true;
1345 }
1346
1347 bool wxWindowCocoa::SetCursor(const wxCursor &cursor)
1348 {
1349     if(!wxWindowBase::SetCursor(cursor))
1350         return false;
1351
1352     // Set up the cursor rect so that invalidateCursorRectsForView: will destroy it.
1353     // If we don't do this then Cocoa thinks (rightly) that we don't have any cursor
1354     // rects and thus won't ever call resetCursorRects.
1355     [GetNSView() addCursorRect: [GetNSView() visibleRect]  cursor: m_cursor.GetNSCursor()];
1356
1357     // Invalidate the cursor rects so the cursor will change
1358     // Note that it is not enough to remove the old one (if any) and add the new one.
1359     // For the rects to work properly, Cocoa itself must call resetCursorRects.
1360     [[GetNSView() window] invalidateCursorRectsForView:GetNSView()];
1361     return true;
1362 }
1363
1364 bool wxWindowCocoa::Cocoa_viewDidMoveToWindow()
1365 {
1366     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::viewDidMoveToWindow"),this);
1367     // Set up new tracking rects.  I am reasonably sure the new window must be set before doing this.
1368     if(m_visibleTrackingRectManager != NULL)
1369         m_visibleTrackingRectManager->BuildTrackingRect();
1370     return false;
1371 }
1372
1373 bool wxWindowCocoa::Cocoa_viewWillMoveToWindow(WX_NSWindow newWindow)
1374 {
1375     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::viewWillMoveToWindow:%p"),this, newWindow);
1376     // Clear tracking rects.  It is imperative this be done before the new window is set.
1377     if(m_visibleTrackingRectManager != NULL)
1378         m_visibleTrackingRectManager->ClearTrackingRect();
1379     return false;
1380 }
1381
1382 bool wxWindow::Close(bool force)
1383 {
1384     // The only reason this function exists is that it is virtual and
1385     // wxTopLevelWindowCocoa will override it.
1386     return wxWindowBase::Close(force);
1387 }
1388
1389 void wxWindow::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
1390 {
1391     [[oldView superview] replaceSubview:oldView with:newView];
1392 }
1393
1394 void wxWindow::DoEnable(bool enable)
1395 {
1396         CocoaSetEnabled(enable);
1397 }
1398
1399 bool wxWindow::Show(bool show)
1400 {
1401     wxAutoNSAutoreleasePool pool;
1402     // If the window is marked as visible, then it shouldn't have a dummy view
1403     // If the window is marked hidden, then it should have a dummy view
1404     // wxSpinCtrl (generic) abuses m_isShown, don't use it for any logic
1405 //    wxASSERT_MSG( (m_isShown && !m_dummyNSView) || (!m_isShown && m_dummyNSView),wxT("wxWindow: m_isShown does not agree with m_dummyNSView"));
1406     // Return false if there isn't a window to show or hide
1407     NSView *cocoaView = GetNSViewForHiding();
1408     if(!cocoaView)
1409         return false;
1410     if(show)
1411     {
1412         // If state isn't changing, return false
1413         if(!m_cocoaHider)
1414             return false;
1415
1416         // Replace the stand-in view with the real one and destroy the dummy view
1417         CocoaReplaceView(m_cocoaHider->GetNSView(), cocoaView);
1418         wxASSERT(![m_cocoaHider->GetNSView() superview]);
1419         delete m_cocoaHider;
1420         m_cocoaHider = NULL;
1421         wxASSERT([cocoaView superview]);
1422
1423         // Schedule an update of the key view loop (NOTE: 10.4+ only.. argh)
1424         NSWindow *window = [cocoaView window];
1425         if(window != nil)
1426         {
1427             // Delay this until returning to the event loop for a couple of reasons:
1428             // 1. If a lot of stuff is shown/hidden we avoid recalculating needlessly
1429             // 2. NSWindow does not seem to see the newly shown views if we do it right now.
1430             if([window respondsToSelector:@selector(recalculateKeyViewLoop)])
1431                 [window performSelector:@selector(recalculateKeyViewLoop) withObject:nil afterDelay:0.0];
1432         }
1433     }
1434     else
1435     {
1436         // If state isn't changing, return false
1437         if(m_cocoaHider)
1438             return false;
1439
1440         // Handle the first responder
1441         NSWindow *window = [cocoaView window];
1442         if(window != nil)
1443         {
1444             NSResponder *firstResponder = [window firstResponder];
1445             if([firstResponder isKindOfClass:[NSView class]] && [(NSView*)firstResponder isDescendantOf:cocoaView])
1446             {
1447                 BOOL didResign = [window makeFirstResponder:nil];
1448                 // If the current first responder (one of our subviews) refuses to give
1449                 // up its status, then fail now and don't hide this view
1450                 if(didResign == NO)
1451                     return false;
1452             }
1453         }
1454
1455         // Create a new view to stand in for the real one (via wxWindowCocoaHider) and replace
1456         // the real one with the stand in.
1457         m_cocoaHider = new wxWindowCocoaHider(this);
1458         // NOTE: replaceSubview:with will cause m_cocaNSView to be
1459         // (auto)released which balances out addSubview
1460         CocoaReplaceView(cocoaView, m_cocoaHider->GetNSView());
1461         // m_coocaNSView is now only retained by us
1462         wxASSERT([m_cocoaHider->GetNSView() superview]);
1463         wxASSERT(![cocoaView superview]);
1464     }
1465     m_isShown = show;
1466     return true;
1467 }
1468
1469 void wxWindowCocoa::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1470 {
1471     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoSetSizeWindow(%d,%d,%d,%d,Auto: %s%s)"),this,x,y,width,height,(sizeFlags&wxSIZE_AUTO_WIDTH)?"W":".",sizeFlags&wxSIZE_AUTO_HEIGHT?"H":".");
1472     int currentX, currentY;
1473     int currentW, currentH;
1474     DoGetPosition(&currentX, &currentY);
1475     DoGetSize(&currentW, &currentH);
1476     if((x==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
1477         x=currentX;
1478     if((y==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
1479         y=currentY;
1480
1481     AdjustForParentClientOrigin(x,y,sizeFlags);
1482
1483     wxSize size(wxDefaultSize);
1484
1485     if((width==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
1486     {
1487         if(sizeFlags&wxSIZE_AUTO_WIDTH)
1488         {
1489             size=DoGetBestSize();
1490             width=size.x;
1491         }
1492         else
1493             width=currentW;
1494     }
1495     if((height==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
1496     {
1497         if(sizeFlags&wxSIZE_AUTO_HEIGHT)
1498         {
1499             if(size.x==-1)
1500                 size=DoGetBestSize();
1501             height=size.y;
1502         }
1503         else
1504             height=currentH;
1505     }
1506     DoMoveWindow(x,y,width,height);
1507 }
1508
1509 #if wxUSE_TOOLTIPS
1510
1511 void wxWindowCocoa::DoSetToolTip( wxToolTip *tip )
1512 {
1513     wxWindowBase::DoSetToolTip(tip);
1514
1515     if ( m_tooltip )
1516     {
1517         m_tooltip->SetWindow((wxWindow *)this);
1518     }
1519 }
1520
1521 #endif
1522
1523 void wxWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
1524 {
1525     wxAutoNSAutoreleasePool pool;
1526     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoMoveWindow(%d,%d,%d,%d)"),this,x,y,width,height);
1527
1528     NSView *nsview = GetNSViewForSuperview();
1529     NSView *superview = [nsview superview];
1530
1531     wxCHECK_RET(GetParent(), wxT("Window can only be placed correctly when it has a parent"));
1532
1533     NSRect oldFrameRect = [nsview frame];
1534     NSRect newFrameRect = GetParent()->CocoaTransformWxToBounds(NSMakeRect(x,y,width,height));
1535     [nsview setFrame:newFrameRect];
1536     // Be sure to redraw the parent to reflect the changed position
1537     [superview setNeedsDisplayInRect:oldFrameRect];
1538     [superview setNeedsDisplayInRect:newFrameRect];
1539 }
1540
1541 void wxWindowCocoa::SetInitialFrameRect(const wxPoint& pos, const wxSize& size)
1542 {
1543     NSView *nsview = GetNSViewForSuperview();
1544     NSView *superview = [nsview superview];
1545     wxCHECK_RET(superview,wxT("NSView does not have a superview"));
1546     wxCHECK_RET(GetParent(), wxT("Window can only be placed correctly when it has a parent"));
1547     NSRect frameRect = [nsview frame];
1548     if(size.x!=-1)
1549         frameRect.size.width = size.x;
1550     if(size.y!=-1)
1551         frameRect.size.height = size.y;
1552     frameRect.origin.x = pos.x;
1553     frameRect.origin.y = pos.y;
1554     // Tell Cocoa to change the margin between the bottom of the superview
1555     // and the bottom of the control.  Keeps the control pinned to the top
1556     // of its superview so that its position in the wxWidgets coordinate
1557     // system doesn't change.
1558     if(![superview isFlipped])
1559         [nsview setAutoresizingMask: NSViewMinYMargin];
1560     // MUST set the mask before setFrame: which can generate a size event
1561     // and cause a scroller to be added!
1562     frameRect = GetParent()->CocoaTransformWxToBounds(frameRect);
1563     [nsview setFrame: frameRect];
1564 }
1565
1566 // Get total size
1567 void wxWindow::DoGetSize(int *w, int *h) const
1568 {
1569     NSRect cocoaRect = [GetNSViewForSuperview() frame];
1570     if(w)
1571         *w=(int)cocoaRect.size.width;
1572     if(h)
1573         *h=(int)cocoaRect.size.height;
1574     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoGetSize = (%d,%d)"),this,(int)cocoaRect.size.width,(int)cocoaRect.size.height);
1575 }
1576
1577 void wxWindow::DoGetPosition(int *x, int *y) const
1578 {
1579     NSView *nsview = GetNSViewForSuperview();
1580
1581     NSRect cocoaRect = [nsview frame];
1582     NSRect rectWx = GetParent()->CocoaTransformBoundsToWx(cocoaRect);
1583     if(x)
1584         *x=(int)rectWx.origin.x;
1585     if(y)
1586         *y=(int)rectWx.origin.y;
1587     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoGetPosition = (%d,%d)"),this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);
1588 }
1589
1590 WXWidget wxWindow::GetHandle() const
1591 {
1592     return m_cocoaNSView;
1593 }
1594
1595 wxWindow* wxWindow::GetWxWindow() const
1596 {
1597     return (wxWindow*) this;
1598 }
1599
1600 void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
1601 {
1602     [m_cocoaNSView setNeedsDisplay:YES];
1603 }
1604
1605 void wxWindow::SetFocus()
1606 {
1607     if([GetNSView() acceptsFirstResponder])
1608         [[GetNSView() window] makeFirstResponder: GetNSView()];
1609 }
1610
1611 void wxWindow::DoCaptureMouse()
1612 {
1613     // TODO
1614     sm_capturedWindow = this;
1615 }
1616
1617 void wxWindow::DoReleaseMouse()
1618 {
1619     // TODO
1620     sm_capturedWindow = NULL;
1621 }
1622
1623 void wxWindow::DoScreenToClient(int *x, int *y) const
1624 {
1625     // Point in cocoa screen coordinates:
1626     NSPoint cocoaScreenPoint = OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x!=NULL?*x:0, y!=NULL?*y:0, 0, 0, false);
1627     NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
1628     NSWindow *theWindow = [clientView window];
1629
1630     // Point in window's base coordinate system:
1631     NSPoint windowPoint = [theWindow convertScreenToBase:cocoaScreenPoint];
1632     // Point in view's bounds coordinate system
1633     NSPoint boundsPoint = [clientView convertPoint:windowPoint fromView:nil];
1634     // Point in wx client coordinates:
1635     NSPoint theWxClientPoint = CocoaTransformNSViewBoundsToWx(clientView, boundsPoint);
1636     if(x!=NULL)
1637         *x = theWxClientPoint.x;
1638     if(y!=NULL)
1639         *y = theWxClientPoint.y;
1640 }
1641
1642 void wxWindow::DoClientToScreen(int *x, int *y) const
1643 {
1644     // Point in wx client coordinates
1645     NSPoint theWxClientPoint = NSMakePoint(x!=NULL?*x:0, y!=NULL?*y:0);
1646
1647     NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
1648
1649     // Point in the view's bounds coordinate system
1650     NSPoint boundsPoint = CocoaTransformNSViewWxToBounds(clientView, theWxClientPoint);
1651
1652     // Point in the window's base coordinate system
1653     NSPoint windowPoint = [clientView convertPoint:boundsPoint toView:nil];
1654
1655     NSWindow *theWindow = [clientView window];
1656     // Point in Cocoa's screen coordinates
1657     NSPoint screenPoint = [theWindow convertBaseToScreen:windowPoint];
1658
1659     // Act as though this was the origin of a 0x0 rectangle
1660     NSRect screenPointRect = NSMakeRect(screenPoint.x, screenPoint.y, 0, 0);
1661
1662     // Convert that rectangle to wx coordinates
1663     wxPoint theWxScreenPoint = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(screenPointRect);
1664     if(*x)
1665         *x = theWxScreenPoint.x;
1666     if(*y)
1667         *y = theWxScreenPoint.y;
1668 }
1669
1670 // Get size *available for subwindows* i.e. excluding menu bar etc.
1671 void wxWindow::DoGetClientSize(int *x, int *y) const
1672 {
1673     wxLogTrace(wxTRACE_COCOA,wxT("DoGetClientSize:"));
1674     if(m_wxCocoaScrollView)
1675         m_wxCocoaScrollView->DoGetClientSize(x,y);
1676     else
1677         wxWindowCocoa::DoGetSize(x,y);
1678 }
1679
1680 void wxWindow::DoSetClientSize(int width, int height)
1681 {
1682     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("DoSetClientSize=(%d,%d)"),width,height);
1683     if(m_wxCocoaScrollView)
1684         m_wxCocoaScrollView->ClientSizeToSize(width,height);
1685     CocoaSetWxWindowSize(width,height);
1686 }
1687
1688 void wxWindow::CocoaSetWxWindowSize(int width, int height)
1689 {
1690     wxWindowCocoa::DoSetSize(wxDefaultCoord,wxDefaultCoord,width,height,wxSIZE_USE_EXISTING);
1691 }
1692
1693 void wxWindow::SetLabel(const wxString& WXUNUSED(label))
1694 {
1695     // Intentional no-op.
1696 }
1697
1698 wxString wxWindow::GetLabel() const
1699 {
1700     // General Get/Set of labels is implemented in wxControlBase
1701     wxLogDebug(wxT("wxWindow::GetLabel: Should be overridden if needed."));
1702     return wxEmptyString;
1703 }
1704
1705 int wxWindow::GetCharHeight() const
1706 {
1707     // TODO
1708     return 10;
1709 }
1710
1711 int wxWindow::GetCharWidth() const
1712 {
1713     // TODO
1714     return 5;
1715 }
1716
1717 void wxWindow::GetTextExtent(const wxString& string, int *outX, int *outY,
1718         int *outDescent, int *outExternalLeading, const wxFont *inFont) const
1719 {
1720     // FIXME: This obviously ignores the window's font (if any) along with any size
1721     // transformations.  However, it's better than nothing.
1722     // We don't create a wxClientDC because we don't want to accidently be able to use
1723     // it for drawing.
1724     wxClientDC tmpdc(const_cast<wxWindow*>(this));
1725     return tmpdc.GetTextExtent(string, outX, outY, outDescent, outExternalLeading, inFont);
1726 }
1727
1728 // Coordinates relative to the window
1729 void wxWindow::WarpPointer (int x_pos, int y_pos)
1730 {
1731     // TODO
1732 }
1733
1734 int wxWindow::GetScrollPos(int orient) const
1735 {
1736     if(m_wxCocoaScrollView != NULL)
1737         return m_wxCocoaScrollView->GetScrollPos(static_cast<wxOrientation>(orient & wxBOTH));
1738     else
1739         return 0;
1740 }
1741
1742 // This now returns the whole range, not just the number
1743 // of positions that we can scroll.
1744 int wxWindow::GetScrollRange(int orient) const
1745 {
1746     if(m_wxCocoaScrollView != NULL)
1747         return m_wxCocoaScrollView->GetScrollRange(static_cast<wxOrientation>(orient & wxBOTH));
1748     else
1749         return 0;
1750 }
1751
1752 int wxWindow::GetScrollThumb(int orient) const
1753 {
1754     if(m_wxCocoaScrollView != NULL)
1755         return m_wxCocoaScrollView->GetScrollThumb(static_cast<wxOrientation>(orient & wxBOTH));
1756     else
1757         return 0;
1758 }
1759
1760 void wxWindow::SetScrollPos(int orient, int pos, bool refresh)
1761 {
1762     if(m_wxCocoaScrollView != NULL)
1763         return m_wxCocoaScrollView->SetScrollPos(static_cast<wxOrientation>(orient & wxBOTH), pos);
1764 }
1765
1766 void wxWindow::CocoaCreateNSScrollView()
1767 {
1768     if(!m_wxCocoaScrollView)
1769     {
1770         m_wxCocoaScrollView = new wxWindowCocoaScrollView(this);
1771     }
1772 }
1773
1774 // New function that will replace some of the above.
1775 void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible,
1776     int range, bool refresh)
1777 {
1778     CocoaCreateNSScrollView();
1779     m_wxCocoaScrollView->SetScrollbar(orient, pos, thumbVisible, range);
1780     // TODO: Handle refresh (if we even need to)
1781 }
1782
1783 // Does a physical scroll
1784 void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
1785 {
1786     if(m_wxCocoaScrollView != NULL)
1787         m_wxCocoaScrollView->ScrollWindow(dx, dy, rect);
1788 }
1789
1790 void wxWindow::DoSetVirtualSize( int x, int y )
1791 {
1792     // Call wxWindowBase method which will set m_virtualSize to the appropriate value,
1793     // possibly not what the caller passed in.  For example, the current implementation
1794     // clamps the width and height to within the min/max virtual ranges.
1795     // wxDefaultCoord is passed through unchanged but then GetVirtualSize() will correct
1796     // that by returning effectively max(virtual, client)
1797     wxWindowBase::DoSetVirtualSize(x,y);
1798     // Create the scroll view if it hasn't been already.
1799     CocoaCreateNSScrollView();
1800
1801     // The GetVirtualSize automatically increases the size to max(client,virtual)
1802     m_wxCocoaScrollView->UpdateSizes();
1803 }
1804
1805 bool wxWindow::SetFont(const wxFont& font)
1806 {
1807     // FIXME: We may need to handle wx font inheritance.
1808     return wxWindowBase::SetFont(font);
1809 }
1810
1811 #if 0 // these are used when debugging the algorithm.
1812 static char const * const comparisonresultStrings[] =
1813 {   "<"
1814 ,   "=="
1815 ,   ">"
1816 };
1817 #endif
1818
1819 class CocoaWindowCompareContext
1820 {
1821     DECLARE_NO_COPY_CLASS(CocoaWindowCompareContext)
1822 public:
1823     CocoaWindowCompareContext(); // Not implemented
1824     CocoaWindowCompareContext(NSView *target, NSArray *subviews)
1825     {
1826         m_target = target;
1827         // Cocoa sorts subviews in-place.. make a copy
1828         m_subviews = [subviews copy];
1829     }
1830     ~CocoaWindowCompareContext()
1831     {   // release the copy
1832         [m_subviews release];
1833     }
1834     NSView* target()
1835     {   return m_target; }
1836     NSArray* subviews()
1837     {   return m_subviews; }
1838     /* Helper function that returns the comparison based off of the original ordering */
1839     CocoaWindowCompareFunctionResult CompareUsingOriginalOrdering(id first, id second)
1840     {
1841         NSUInteger firstI = [m_subviews indexOfObjectIdenticalTo:first];
1842         NSUInteger secondI = [m_subviews indexOfObjectIdenticalTo:second];
1843         // NOTE: If either firstI or secondI is NSNotFound then it will be NSIntegerMax and thus will
1844         // likely compare higher than the other view which is reasonable considering the only way that
1845         // can happen is if the subview was added after our call to subviews but before the call to
1846         // sortSubviewsUsingFunction:context:.  Thus we don't bother checking.  Particularly because
1847         // that case should never occur anyway because that would imply a multi-threaded GUI call
1848         // which is a big no-no with Cocoa.
1849
1850         // Subviews are ordered from back to front meaning one that is already lower will have an lower index.
1851         NSComparisonResult result = (firstI < secondI)
1852             ?   NSOrderedAscending /* -1 */
1853             :   (firstI > secondI)
1854                 ?   NSOrderedDescending /* 1 */
1855                 :   NSOrderedSame /* 0 */;
1856
1857 #if 0 // Enable this if you need to debug the algorithm.
1858         NSLog(@"%@ [%d] %s %@ [%d]\n", first, firstI, comparisonresultStrings[result+1], second, secondI);
1859 #endif
1860         return result;
1861     }
1862 private:
1863     /* The subview we are trying to Raise or Lower */
1864     NSView *m_target;
1865     /* A copy of the original array of subviews */
1866     NSArray *m_subviews;
1867 };
1868
1869 /* Causes Cocoa to raise the target view to the top of the Z-Order by telling the sort function that
1870  * the target view is always higher than every other view.  When comparing two views neither of
1871  * which is the target, it returns the correct response based on the original ordering
1872  */
1873 static CocoaWindowCompareFunctionResult CocoaRaiseWindowCompareFunction(id first, id second, void *ctx)
1874 {
1875     CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
1876     // first should be ordered higher
1877     if(first==compareContext->target())
1878         return NSOrderedDescending;
1879     // second should be ordered higher
1880     if(second==compareContext->target())
1881         return NSOrderedAscending;
1882     return compareContext->CompareUsingOriginalOrdering(first,second);
1883 }
1884
1885 // Raise the window to the top of the Z order
1886 void wxWindow::Raise()
1887 {
1888 //    wxAutoNSAutoreleasePool pool;
1889     NSView *nsview = GetNSViewForSuperview();
1890     NSView *superview = [nsview superview];
1891     CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1892
1893     [superview sortSubviewsUsingFunction:
1894             CocoaRaiseWindowCompareFunction
1895         context: &compareContext];
1896 }
1897
1898 /* Causes Cocoa to lower the target view to the bottom of the Z-Order by telling the sort function that
1899  * the target view is always lower than every other view.  When comparing two views neither of
1900  * which is the target, it returns the correct response based on the original ordering
1901  */
1902 static CocoaWindowCompareFunctionResult CocoaLowerWindowCompareFunction(id first, id second, void *ctx)
1903 {
1904     CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
1905     // first should be ordered lower
1906     if(first==compareContext->target())
1907         return NSOrderedAscending;
1908     // second should be ordered lower
1909     if(second==compareContext->target())
1910         return NSOrderedDescending;
1911     return compareContext->CompareUsingOriginalOrdering(first,second);
1912 }
1913
1914 // Lower the window to the bottom of the Z order
1915 void wxWindow::Lower()
1916 {
1917     NSView *nsview = GetNSViewForSuperview();
1918     NSView *superview = [nsview superview];
1919     CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1920
1921 #if 0
1922     NSLog(@"Target:\n%@\n", nsview);
1923     NSLog(@"Before:\n%@\n", compareContext.subviews());
1924 #endif
1925     [superview sortSubviewsUsingFunction:
1926             CocoaLowerWindowCompareFunction
1927         context: &compareContext];
1928 #if 0
1929     NSLog(@"After:\n%@\n", [superview subviews]);
1930 #endif
1931 }
1932
1933 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
1934 {
1935     return false;
1936 }
1937
1938 // Get the window with the focus
1939 wxWindow *wxWindowBase::DoFindFocus()
1940 {
1941     // Basically we are somewhat emulating the responder chain here except
1942     // we are only loking for the first responder in the key window or
1943     // upon failing to find one if the main window is different we look
1944     // for the first responder in the main window.
1945
1946     // Note that the firstResponder doesn't necessarily have to be an
1947     // NSView but wxCocoaNSView::GetFromCocoa() will simply return
1948     // NULL unless it finds its argument in its hash map.
1949
1950     wxCocoaNSView *win;
1951
1952     NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
1953     win = wxCocoaNSView::GetFromCocoa(static_cast<NSView*>([keyWindow firstResponder]));
1954     if(win)
1955         return win->GetWxWindow();
1956
1957     NSWindow *mainWindow = [[NSApplication sharedApplication] keyWindow];
1958     if(mainWindow == keyWindow)
1959         return NULL;
1960     win = wxCocoaNSView::GetFromCocoa(static_cast<NSView*>([mainWindow firstResponder]));
1961     if(win)
1962         return win->GetWxWindow();
1963
1964     return NULL;
1965 }
1966
1967 /* static */ wxWindow *wxWindowBase::GetCapture()
1968 {
1969     // TODO
1970     return wxWindowCocoa::sm_capturedWindow;
1971 }
1972
1973 wxWindow *wxGetActiveWindow()
1974 {
1975     // TODO
1976     return NULL;
1977 }
1978
1979 wxPoint wxGetMousePosition()
1980 {
1981     // TODO
1982     return wxDefaultPosition;
1983 }
1984
1985 wxMouseState wxGetMouseState()
1986 {
1987     wxMouseState ms;
1988     // TODO
1989     return ms;
1990 }
1991
1992 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1993 {
1994     pt = wxGetMousePosition();
1995     return NULL;
1996 }
1997
1998 // ========================================================================
1999 // wxCocoaMouseMovedEventSynthesizer
2000 // ========================================================================
2001
2002 #define wxTRACE_COCOA_MouseMovedSynthesizer wxT("COCOA_MouseMovedSynthesizer")
2003
2004 /* This class registers one run loop observer to cover all windows registered with it.
2005  *  It will register the observer when the first view is registerd and unregister the
2006  * observer when the last view is unregistered.
2007  * It is instantiated as a static s_mouseMovedSynthesizer in this file although there
2008  * is no reason it couldn't be instantiated multiple times.
2009  */
2010 class wxCocoaMouseMovedEventSynthesizer
2011 {
2012     DECLARE_NO_COPY_CLASS(wxCocoaMouseMovedEventSynthesizer)
2013 public:
2014     wxCocoaMouseMovedEventSynthesizer()
2015     {   m_lastScreenMouseLocation = NSZeroPoint;
2016     }
2017     ~wxCocoaMouseMovedEventSynthesizer();
2018     void RegisterWxCocoaView(wxCocoaNSView *aView);
2019     void UnregisterWxCocoaView(wxCocoaNSView *aView);
2020     void SynthesizeMouseMovedEvent();
2021     
2022 protected:
2023     void AddRunLoopObserver();
2024     void RemoveRunLoopObserver();
2025     wxCFRef<CFRunLoopObserverRef> m_runLoopObserver;
2026     std::list<wxCocoaNSView*> m_registeredViews;
2027     NSPoint m_lastScreenMouseLocation;
2028     static void SynthesizeMouseMovedEvent(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
2029 };
2030
2031 void wxCocoaMouseMovedEventSynthesizer::RegisterWxCocoaView(wxCocoaNSView *aView)
2032 {
2033     m_registeredViews.push_back(aView);
2034     wxLogTrace(wxTRACE_COCOA_MouseMovedSynthesizer, wxT("Registered wxCocoaNSView=%p"), aView);
2035
2036     if(!m_registeredViews.empty() && m_runLoopObserver == NULL)
2037     {
2038         AddRunLoopObserver();
2039     }
2040 }
2041
2042 void wxCocoaMouseMovedEventSynthesizer::UnregisterWxCocoaView(wxCocoaNSView *aView)
2043 {
2044     m_registeredViews.remove(aView);
2045     wxLogTrace(wxTRACE_COCOA_MouseMovedSynthesizer, wxT("Unregistered wxCocoaNSView=%p"), aView);
2046     if(m_registeredViews.empty() && m_runLoopObserver != NULL)
2047     {
2048         RemoveRunLoopObserver();
2049     }
2050 }
2051
2052 wxCocoaMouseMovedEventSynthesizer::~wxCocoaMouseMovedEventSynthesizer()
2053 {
2054     if(!m_registeredViews.empty())
2055     {
2056         // This means failure to clean up so we report on it as a debug message.
2057         wxLogDebug(wxT("There are still %d wxCocoaNSView registered to receive mouse moved events at static destruction time"), m_registeredViews.size());
2058         m_registeredViews.clear();
2059     }
2060     if(m_runLoopObserver != NULL)
2061     {
2062         // This should not occur unless m_registeredViews was not empty since the last object unregistered should have done this.
2063         wxLogDebug(wxT("Removing run loop observer during static destruction time."));
2064         RemoveRunLoopObserver();
2065     }
2066 }
2067
2068 void wxCocoaMouseMovedEventSynthesizer::SynthesizeMouseMovedEvent(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
2069 {
2070     reinterpret_cast<wxCocoaMouseMovedEventSynthesizer*>(info)->SynthesizeMouseMovedEvent();
2071 }
2072
2073 void wxCocoaMouseMovedEventSynthesizer::AddRunLoopObserver()
2074 {
2075     CFRunLoopObserverContext observerContext =
2076     {   0
2077     ,   this
2078     ,   NULL
2079     ,   NULL
2080     ,   NULL
2081     };
2082
2083     // The kCFRunLoopExit observation point is used such that we hook the run loop after it has already decided that
2084     // it is going to exit which is generally for the purpose of letting the event loop process the next Cocoa event.
2085
2086     // Executing our procedure within the run loop (e.g. kCFRunLoopBeforeWaiting which was used before) results
2087     // in our observer procedure being called before the run loop has decided that it is going to return control to
2088     // the Cocoa event loop.  One major problem is uncovered by the wxGenericHyperlinkCtrl (consider this to be "user
2089     // code") which changes the window's cursor and thus causes the cursor rectangle's to be invalidated.
2090
2091     // Cocoa implements this invalidation using a delayed notification scheme whereby the resetCursorRects method
2092     // won't be called until the CFRunLoop gets around to it.  If the CFRunLoop has not yet exited then it will get
2093     // around to it before letting the event loop do its work.  This has some very odd effects on the way the
2094     // newly created tracking rects function.  In particular, we will often miss the mouseExited: message if the
2095     // user flicks the mouse quickly enough such that the mouse is already outside of the tracking rect by the
2096     // time the new one is built.
2097
2098     // Observing from the kCFRunLoopExit point gives Cocoa's event loop an opportunity to chew some events before it cedes
2099     // control back to the CFRunLoop, thus causing the delayed notifications to fire at an appropriate time and
2100     // the mouseExited: message to be sent properly.
2101
2102     m_runLoopObserver.reset(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopExit, TRUE, 0, SynthesizeMouseMovedEvent, &observerContext));
2103     CFRunLoopAddObserver([[NSRunLoop currentRunLoop] getCFRunLoop], m_runLoopObserver, kCFRunLoopCommonModes);
2104     wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Added tracking rect run loop observer"));
2105 }
2106
2107 void wxCocoaMouseMovedEventSynthesizer::RemoveRunLoopObserver()
2108 {
2109     CFRunLoopRemoveObserver([[NSRunLoop currentRunLoop] getCFRunLoop], m_runLoopObserver, kCFRunLoopCommonModes);
2110     m_runLoopObserver.reset();
2111     wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Removed tracking rect run loop observer"));
2112 }
2113
2114 void wxCocoaMouseMovedEventSynthesizer::SynthesizeMouseMovedEvent()
2115 {
2116     NSPoint screenMouseLocation = [NSEvent mouseLocation];
2117     // Checking the last mouse location is done for a few reasons:
2118     // 1. We are observing every iteration of the event loop so we'd be sending out a lot of extraneous events
2119     //    telling the app the mouse moved when the user hit a key for instance.
2120     // 2. When handling the mouse moved event, user code can do something to the view which will cause Cocoa to
2121     //    call resetCursorRects.  Cocoa does this by using a delayed notification which means the event loop gets
2122     //    pumped once which would mean that if we didn't check the mouse location we'd get into a never-ending
2123     //    loop causing the tracking rectangles to constantly be reset.
2124     if(screenMouseLocation.x != m_lastScreenMouseLocation.x || screenMouseLocation.y != m_lastScreenMouseLocation.y)
2125     {
2126         m_lastScreenMouseLocation = screenMouseLocation;
2127         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Synthesizing mouse moved at screen (%f,%f)"), screenMouseLocation.x, screenMouseLocation.y);
2128         for(std::list<wxCocoaNSView*>::iterator i = m_registeredViews.begin(); i != m_registeredViews.end(); ++i)
2129         {
2130             (*i)->Cocoa_synthesizeMouseMoved();
2131         }
2132     }
2133 }
2134
2135 // Singleton used for all views:
2136 static wxCocoaMouseMovedEventSynthesizer s_mouseMovedSynthesizer;
2137
2138 // ========================================================================
2139 // wxCocoaTrackingRectManager
2140 // ========================================================================
2141
2142 wxCocoaTrackingRectManager::wxCocoaTrackingRectManager(wxWindow *window)
2143 :   m_window(window)
2144 {
2145     m_isTrackingRectActive = false;
2146     BuildTrackingRect();
2147 }
2148
2149 void wxCocoaTrackingRectManager::ClearTrackingRect()
2150 {
2151     if(m_isTrackingRectActive)
2152     {
2153         [m_window->GetNSView() removeTrackingRect:m_trackingRectTag];
2154         m_isTrackingRectActive = false;
2155         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("%s@%p: Removed tracking rect #%d"), m_window->GetClassInfo()->GetClassName(), m_window, m_trackingRectTag);
2156     }
2157     // If we were doing periodic events we need to clear those too
2158     StopSynthesizingEvents();
2159 }
2160
2161 void wxCocoaTrackingRectManager::StopSynthesizingEvents()
2162 {
2163     s_mouseMovedSynthesizer.UnregisterWxCocoaView(m_window);
2164 }
2165
2166 void wxCocoaTrackingRectManager::BuildTrackingRect()
2167 {
2168     // Pool here due to lack of one during wx init phase
2169     wxAutoNSAutoreleasePool pool;
2170
2171     wxASSERT_MSG(!m_isTrackingRectActive, wxT("Tracking rect was not cleared"));
2172
2173     NSView *theView = m_window->GetNSView();
2174
2175     if([theView window] != nil)
2176     {
2177         NSRect visibleRect = [theView visibleRect];
2178
2179         m_trackingRectTag = [theView addTrackingRect:visibleRect owner:theView userData:NULL assumeInside:NO];
2180         m_trackingRectInWindowCoordinates = [theView convertRect:visibleRect toView:nil];
2181         m_isTrackingRectActive = true;
2182
2183         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("%s@%p: Added tracking rect #%d"), m_window->GetClassInfo()->GetClassName(), m_window, m_trackingRectTag);
2184     }
2185 }
2186
2187 void wxCocoaTrackingRectManager::BeginSynthesizingEvents()
2188 {
2189     s_mouseMovedSynthesizer.RegisterWxCocoaView(m_window);
2190 }
2191
2192 void wxCocoaTrackingRectManager::RebuildTrackingRectIfNeeded()
2193 {
2194     if(m_isTrackingRectActive)
2195     {
2196         NSView *theView = m_window->GetNSView();
2197         NSRect currentRect = [theView convertRect:[theView visibleRect] toView:nil];
2198         if(NSEqualRects(m_trackingRectInWindowCoordinates,currentRect))
2199         {
2200             wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Ignored request to rebuild TR#%d"), m_trackingRectTag);
2201             return;
2202         }
2203     }
2204     RebuildTrackingRect();
2205 }
2206
2207 void wxCocoaTrackingRectManager::RebuildTrackingRect()
2208 {
2209     ClearTrackingRect();
2210     BuildTrackingRect();
2211 }
2212
2213 wxCocoaTrackingRectManager::~wxCocoaTrackingRectManager()
2214 {
2215     ClearTrackingRect();
2216 }
2217
2218 bool wxCocoaTrackingRectManager::IsOwnerOfEvent(NSEvent *anEvent)
2219 {
2220     return m_isTrackingRectActive && (m_trackingRectTag == [anEvent trackingNumber]);
2221 }
2222