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