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