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