Don't force the child's m_isShown state to match that of the parent in CocoaAddChild.
[wxWidgets.git] / src / cocoa / window.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/window.mm
3 // Purpose:     wxWindowCocoa
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2002/12/26
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2002 David Elliott
9 // Licence:     wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifndef WX_PRECOMP
15     #include "wx/log.h"
16     #include "wx/window.h"
17     #include "wx/dc.h"
18     #include "wx/utils.h"
19 #endif //WX_PRECOMP
20
21 #include "wx/tooltip.h"
22
23 #include "wx/cocoa/autorelease.h"
24 #include "wx/cocoa/string.h"
25 #include "wx/cocoa/trackingrectmanager.h"
26 #include "wx/mac/corefoundation/cfref.h"
27
28 #import <Foundation/NSArray.h>
29 #import <Foundation/NSRunLoop.h>
30 #include "wx/cocoa/objc/NSView.h"
31 #import <AppKit/NSEvent.h>
32 #import <AppKit/NSScrollView.h>
33 #import <AppKit/NSColor.h>
34 #import <AppKit/NSClipView.h>
35 #import <Foundation/NSException.h>
36 #import <AppKit/NSApplication.h>
37 #import <AppKit/NSWindow.h>
38 #import <AppKit/NSScreen.h>
39
40 // Turn this on to paint green over the dummy views for debugging
41 #undef WXCOCOA_FILL_DUMMY_VIEW
42
43 #ifdef WXCOCOA_FILL_DUMMY_VIEW
44 #import <AppKit/NSBezierPath.h>
45 #endif //def WXCOCOA_FILL_DUMMY_VIEW
46
47 // STL list used by wxCocoaMouseMovedEventSynthesizer
48 #include <list>
49
50 /* NSComparisonResult is typedef'd as an enum pre-Leopard but typedef'd as
51  * NSInteger post-Leopard.  Pre-Leopard the Cocoa toolkit expects a function
52  * returning int and not NSComparisonResult.  Post-Leopard the Cocoa toolkit
53  * expects a function returning the new non-enum NSComparsionResult.
54  * Hence we create a typedef named CocoaWindowCompareFunctionResult.
55  */
56 #if defined(NSINTEGER_DEFINED)
57 typedef NSComparisonResult CocoaWindowCompareFunctionResult;
58 #else
59 typedef int CocoaWindowCompareFunctionResult;
60 #endif
61
62 // A category for methods that are only present in Panther's SDK
63 @interface NSView(wxNSViewPrePantherCompatibility)
64 - (void)getRectsBeingDrawn:(const NSRect **)rects count:(int *)count;
65 @end
66
67 // ========================================================================
68 // Helper functions for converting to/from wxWidgets coordinates and a
69 // specified NSView's coordinate system.
70 // ========================================================================
71 NSPoint CocoaTransformNSViewBoundsToWx(NSView *nsview, NSPoint pointBounds)
72 {
73     wxCHECK_MSG(nsview, pointBounds, wxT("Need to have a Cocoa view to do translation"));
74     if([nsview isFlipped])
75         return pointBounds;
76     NSRect ourBounds = [nsview bounds];
77     return NSMakePoint
78     (   pointBounds.x
79     ,   ourBounds.size.height - pointBounds.y
80     );
81 }
82
83 NSRect CocoaTransformNSViewBoundsToWx(NSView *nsview, NSRect rectBounds)
84 {
85     wxCHECK_MSG(nsview, rectBounds, wxT("Need to have a Cocoa view to do translation"));
86     if([nsview isFlipped])
87         return rectBounds;
88     NSRect ourBounds = [nsview bounds];
89     return NSMakeRect
90     (   rectBounds.origin.x
91     ,   ourBounds.size.height - (rectBounds.origin.y + rectBounds.size.height)
92     ,   rectBounds.size.width
93     ,   rectBounds.size.height
94     );
95 }
96
97 NSPoint CocoaTransformNSViewWxToBounds(NSView *nsview, NSPoint pointWx)
98 {
99     wxCHECK_MSG(nsview, pointWx, wxT("Need to have a Cocoa view to do translation"));
100     if([nsview isFlipped])
101         return pointWx;
102     NSRect ourBounds = [nsview bounds];
103     return NSMakePoint
104     (   pointWx.x
105     ,   ourBounds.size.height - pointWx.y
106     );
107 }
108
109 NSRect CocoaTransformNSViewWxToBounds(NSView *nsview, NSRect rectWx)
110 {
111     wxCHECK_MSG(nsview, rectWx, wxT("Need to have a Cocoa view to do translation"));
112     if([nsview isFlipped])
113         return rectWx;
114     NSRect ourBounds = [nsview bounds];
115     return NSMakeRect
116     (   rectWx.origin.x
117     ,   ourBounds.size.height - (rectWx.origin.y + rectWx.size.height)
118     ,   rectWx.size.width
119     ,   rectWx.size.height
120     );
121 }
122
123 // ============================================================================
124 // Screen coordinate helpers
125 // ============================================================================
126
127 /*
128 General observation about Cocoa screen coordinates:
129 It is documented that the first object of the [NSScreen screens] array is the screen with the menubar.
130
131 It is not documented (but true as far as I can tell) that (0,0) in Cocoa screen coordinates is always
132 the BOTTOM-right corner of this screen.  Recall that Cocoa uses cartesian coordinates so y-increase is up.
133
134 It isn't clearly documented but visibleFrame returns a rectangle in screen coordinates, not a rectangle
135 relative to that screen's frame.  The only real way to test this is to configure two screens one atop
136 the other such that the menubar screen is on top.  The Dock at the bottom of the screen will then
137 eat into the visibleFrame of screen 1 by incrementing it's y-origin.  Thus if you arrange two
138 1920x1200 screens top/bottom then screen 1 (the bottom screen) will have frame origin (0,-1200) and
139 visibleFrame origin (0,-1149) which is exactly 51 pixels higher than the full frame origin.
140
141 In wxCocoa, we somewhat arbitrarily declare that wx (0,0) is the TOP-left of screen 0's frame (the entire screen).
142 However, this isn't entirely arbitrary because the Quartz Display Services (CGDisplay) uses this same scheme.
143 This works out nicely because wxCocoa's wxDisplay is implemented using Quartz Display Services instead of NSScreen.
144 */
145
146 namespace { // file namespace
147
148 class wxCocoaPrivateScreenCoordinateTransformer
149 {
150     DECLARE_NO_COPY_CLASS(wxCocoaPrivateScreenCoordinateTransformer)
151 public:
152     wxCocoaPrivateScreenCoordinateTransformer();
153     ~wxCocoaPrivateScreenCoordinateTransformer();
154     wxPoint OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame);
155     NSPoint OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible);
156
157 protected:
158     NSScreen *m_screenZero;
159     NSRect m_screenZeroFrame;
160 };
161
162 // NOTE: This is intended to be a short-lived object.  A future enhancment might
163 // make it a global and reconfigure it upon some notification that the screen layout
164 // has changed.
165 inline wxCocoaPrivateScreenCoordinateTransformer::wxCocoaPrivateScreenCoordinateTransformer()
166 {
167     NSArray *screens = [NSScreen screens];
168
169     [screens retain];
170
171     m_screenZero = nil;
172     if(screens != nil && [screens count] > 0)
173         m_screenZero = [[screens objectAtIndex:0] retain];
174
175     [screens release];
176
177     if(m_screenZero != nil)
178         m_screenZeroFrame = [m_screenZero frame];
179     else
180     {
181         wxLogWarning(wxT("Can't translate to/from wx screen coordinates and Cocoa screen coordinates"));
182         // Just blindly assume 1024x768 so that at least we can sort of flip things around into
183         // Cocoa coordinates.
184         // NOTE: Theoretically this case should never happen anyway.
185         m_screenZeroFrame = NSMakeRect(0,0,1024,768);
186     }
187 }
188
189 inline wxCocoaPrivateScreenCoordinateTransformer::~wxCocoaPrivateScreenCoordinateTransformer()
190 {
191     [m_screenZero release];
192     m_screenZero = nil;
193 }
194
195 inline wxPoint wxCocoaPrivateScreenCoordinateTransformer::OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame)
196 {
197     // x and y are in wx screen coordinates which we're going to arbitrarily define such that
198     // (0,0) is the TOP-left of screen 0 (the one with the menubar)
199     // NOTE WELL: This means that (0,0) is _NOT_ an appropriate position for a window.
200
201     wxPoint theWxOrigin;
202
203     // Working in Cocoa's screen coordinates we must realize that the x coordinate we want is
204     // the distance between the left side (origin.x) of the window's frame and the left side of
205     // screen zero's frame.
206     theWxOrigin.x = windowFrame.origin.x - m_screenZeroFrame.origin.x;
207
208     // Working in Cocoa's screen coordinates we must realize that the y coordinate we want is
209     // actually the distance between the top-left of the screen zero frame and the top-left
210     // of the window's frame.
211
212     theWxOrigin.y = (m_screenZeroFrame.origin.y + m_screenZeroFrame.size.height) - (windowFrame.origin.y + windowFrame.size.height);
213
214     return theWxOrigin;
215 }
216
217 inline NSPoint wxCocoaPrivateScreenCoordinateTransformer::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible)
218 {
219     NSPoint theCocoaOrigin;
220
221     // The position is in wx screen coordinates which we're going to arbitrarily define such that
222     // (0,0) is the TOP-left of screen 0 (the one with the menubar)
223
224     // NOTE: The usable rectangle is smaller and hence we have the keepOriginVisible flag
225     // which will move the origin downward and/or left as necessary if the origin is
226     // inside the screen0 rectangle (i.e. x/y >= 0 in wx coordinates) and outside the
227     // visible frame (i.e. x/y < the top/left of the screen0 visible frame in wx coordinates)
228     // We don't munge origin coordinates < 0 because it actually is possible that the menubar is on
229     // the top of the bottom screen and thus that origin is completely valid!
230     if(keepOriginVisible && (m_screenZero != nil))
231     {
232         // Do al of this in wx coordinates because it's far simpler since we're dealing with top/left points
233         wxPoint visibleOrigin = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates([m_screenZero visibleFrame]);
234         if(x >= 0 && x < visibleOrigin.x)
235             x = visibleOrigin.x;
236         if(y >= 0 && y < visibleOrigin.y)
237             y = visibleOrigin.y;
238     }
239
240     // The x coordinate is simple as it's just relative to screen zero's frame
241     theCocoaOrigin.x = m_screenZeroFrame.origin.x + x;
242     // Working in Cocoa's coordinates think to start at the bottom of screen zero's frame and add
243     // the height of that rect which gives us the coordinate for the top of the visible rect.  Now realize that
244     // the wx coordinates are flipped so if y is say 10 then we want to be 10 pixels down from that and thus
245     // we subtract y.  But then we still need to take into account the size of the window which is h and subtract
246     // that to get the bottom-left origin of the rectangle.
247     theCocoaOrigin.y = m_screenZeroFrame.origin.y + m_screenZeroFrame.size.height - y - height;
248
249     return theCocoaOrigin;
250 }
251
252 } // namespace
253
254 wxPoint wxWindowCocoa::OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame)
255 {
256     wxCocoaPrivateScreenCoordinateTransformer transformer;
257     return transformer.OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(windowFrame);
258 }
259
260 NSPoint wxWindowCocoa::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible)
261 {
262     wxCocoaPrivateScreenCoordinateTransformer transformer;
263     return transformer.OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x,y,width,height,keepOriginVisible);
264 }
265
266 // ========================================================================
267 // wxWindowCocoaHider
268 // ========================================================================
269 class wxWindowCocoaHider: protected wxCocoaNSView
270 {
271     DECLARE_NO_COPY_CLASS(wxWindowCocoaHider)
272 public:
273     wxWindowCocoaHider(wxWindow *owner);
274     virtual ~wxWindowCocoaHider();
275     inline WX_NSView GetNSView() { return m_dummyNSView; }
276 protected:
277     wxWindowCocoa *m_owner;
278     WX_NSView m_dummyNSView;
279     virtual void Cocoa_FrameChanged(void);
280     virtual void Cocoa_synthesizeMouseMoved(void) {}
281 #ifdef WXCOCOA_FILL_DUMMY_VIEW
282     virtual bool Cocoa_drawRect(const NSRect& rect);
283 #endif //def WXCOCOA_FILL_DUMMY_VIEW
284 private:
285     wxWindowCocoaHider();
286 };
287
288 // ========================================================================
289 // wxWindowCocoaScrollView
290 // ========================================================================
291 class wxWindowCocoaScrollView: protected wxCocoaNSView
292 {
293     DECLARE_NO_COPY_CLASS(wxWindowCocoaScrollView)
294 public:
295     wxWindowCocoaScrollView(wxWindow *owner);
296     virtual ~wxWindowCocoaScrollView();
297     inline WX_NSScrollView GetNSScrollView() { return m_cocoaNSScrollView; }
298     void ClientSizeToSize(int &width, int &height);
299     void DoGetClientSize(int *x, int *y) const;
300     void Encapsulate();
301     void Unencapsulate();
302 protected:
303     wxWindowCocoa *m_owner;
304     WX_NSScrollView m_cocoaNSScrollView;
305     virtual void Cocoa_FrameChanged(void);
306     virtual void Cocoa_synthesizeMouseMoved(void) {}
307 private:
308     wxWindowCocoaScrollView();
309 };
310
311 // ========================================================================
312 // wxDummyNSView
313 // ========================================================================
314 @interface wxDummyNSView : NSView
315 - (NSView *)hitTest:(NSPoint)aPoint;
316 @end
317 WX_DECLARE_GET_OBJC_CLASS(wxDummyNSView,NSView)
318
319 @implementation wxDummyNSView : NSView
320 - (NSView *)hitTest:(NSPoint)aPoint
321 {
322     return nil;
323 }
324
325 @end
326 WX_IMPLEMENT_GET_OBJC_CLASS(wxDummyNSView,NSView)
327
328 // ========================================================================
329 // wxWindowCocoaHider
330 // ========================================================================
331 wxWindowCocoaHider::wxWindowCocoaHider(wxWindow *owner)
332 :   m_owner(owner)
333 {
334     wxASSERT(owner);
335     wxASSERT(owner->GetNSViewForHiding());
336     m_dummyNSView = [[WX_GET_OBJC_CLASS(wxDummyNSView) alloc]
337         initWithFrame:[owner->GetNSViewForHiding() frame]];
338     [m_dummyNSView setAutoresizingMask: [owner->GetNSViewForHiding() autoresizingMask]];
339     AssociateNSView(m_dummyNSView);
340 }
341
342 wxWindowCocoaHider::~wxWindowCocoaHider()
343 {
344     DisassociateNSView(m_dummyNSView);
345     [m_dummyNSView release];
346 }
347
348 void wxWindowCocoaHider::Cocoa_FrameChanged(void)
349 {
350     // Keep the real window in synch with the dummy
351     wxASSERT(m_dummyNSView);
352     [m_owner->GetNSViewForHiding() setFrame:[m_dummyNSView frame]];
353 }
354
355
356 #ifdef WXCOCOA_FILL_DUMMY_VIEW
357 bool wxWindowCocoaHider::Cocoa_drawRect(const NSRect& rect)
358 {
359     NSBezierPath *bezpath = [NSBezierPath bezierPathWithRect:rect];
360     [[NSColor greenColor] set];
361     [bezpath stroke];
362     [bezpath fill];
363     return true;
364 }
365 #endif //def WXCOCOA_FILL_DUMMY_VIEW
366
367 // ========================================================================
368 // wxFlippedNSClipView
369 // ========================================================================
370 @interface wxFlippedNSClipView : NSClipView
371 - (BOOL)isFlipped;
372 @end
373 WX_DECLARE_GET_OBJC_CLASS(wxFlippedNSClipView,NSClipView)
374
375 @implementation wxFlippedNSClipView : NSClipView
376 - (BOOL)isFlipped
377 {
378     return YES;
379 }
380
381 @end
382 WX_IMPLEMENT_GET_OBJC_CLASS(wxFlippedNSClipView,NSClipView)
383
384 // ========================================================================
385 // wxWindowCocoaScrollView
386 // ========================================================================
387 wxWindowCocoaScrollView::wxWindowCocoaScrollView(wxWindow *owner)
388 :   m_owner(owner)
389 {
390     wxAutoNSAutoreleasePool pool;
391     wxASSERT(owner);
392     wxASSERT(owner->GetNSView());
393     m_cocoaNSScrollView = [[NSScrollView alloc]
394         initWithFrame:[owner->GetNSView() frame]];
395     AssociateNSView(m_cocoaNSScrollView);
396
397     /* Replace the default NSClipView with a flipped one.  This ensures
398        scrolling is "pinned" to the top-left instead of bottom-right. */
399     NSClipView *flippedClip = [[WX_GET_OBJC_CLASS(wxFlippedNSClipView) alloc]
400         initWithFrame: [[m_cocoaNSScrollView contentView] frame]];
401     [m_cocoaNSScrollView setContentView:flippedClip];
402     [flippedClip release];
403
404     [m_cocoaNSScrollView setBackgroundColor: [NSColor windowBackgroundColor]];
405     [m_cocoaNSScrollView setHasHorizontalScroller: YES];
406     [m_cocoaNSScrollView setHasVerticalScroller: YES];
407     Encapsulate();
408 }
409
410 void wxWindowCocoaScrollView::Encapsulate()
411 {
412     // Set the scroll view autoresizingMask to match the current NSView
413     [m_cocoaNSScrollView setAutoresizingMask: [m_owner->GetNSView() autoresizingMask]];
414     [m_owner->GetNSView() setAutoresizingMask: NSViewNotSizable];
415     // NOTE: replaceSubView will cause m_cocaNSView to be released
416     // except when it hasn't been added into an NSView hierarchy in which
417     // case it doesn't need to be and this should work out to a no-op
418     m_owner->CocoaReplaceView(m_owner->GetNSView(), m_cocoaNSScrollView);
419     // The NSView is still retained by owner
420     [m_cocoaNSScrollView setDocumentView: m_owner->GetNSView()];
421     // Now it's also retained by the NSScrollView
422 }
423
424 void wxWindowCocoaScrollView::Unencapsulate()
425 {
426     [m_cocoaNSScrollView setDocumentView: nil];
427     m_owner->CocoaReplaceView(m_cocoaNSScrollView, m_owner->GetNSView());
428     if(![[m_owner->GetNSView() superview] isFlipped])
429         [m_owner->GetNSView() setAutoresizingMask: NSViewMinYMargin];
430 }
431
432 wxWindowCocoaScrollView::~wxWindowCocoaScrollView()
433 {
434     DisassociateNSView(m_cocoaNSScrollView);
435     [m_cocoaNSScrollView release];
436 }
437
438 void wxWindowCocoaScrollView::ClientSizeToSize(int &width, int &height)
439 {
440     NSSize frameSize = [NSScrollView
441         frameSizeForContentSize: NSMakeSize(width,height)
442         hasHorizontalScroller: [m_cocoaNSScrollView hasHorizontalScroller]
443         hasVerticalScroller: [m_cocoaNSScrollView hasVerticalScroller]
444         borderType: [m_cocoaNSScrollView borderType]];
445     width = (int)frameSize.width;
446     height = (int)frameSize.height;
447 }
448
449 void wxWindowCocoaScrollView::DoGetClientSize(int *x, int *y) const
450 {
451     NSSize nssize = [m_cocoaNSScrollView contentSize];
452     if(x)
453         *x = (int)nssize.width;
454     if(y)
455         *y = (int)nssize.height;
456 }
457
458 void wxWindowCocoaScrollView::Cocoa_FrameChanged(void)
459 {
460     wxLogTrace(wxTRACE_COCOA,wxT("Cocoa_FrameChanged"));
461     wxSizeEvent event(m_owner->GetSize(), m_owner->GetId());
462     event.SetEventObject(m_owner);
463     m_owner->GetEventHandler()->ProcessEvent(event);
464 }
465
466 // ========================================================================
467 // wxWindowCocoa
468 // ========================================================================
469 // normally the base classes aren't included, but wxWindow is special
470 #ifdef __WXUNIVERSAL__
471 IMPLEMENT_ABSTRACT_CLASS(wxWindowCocoa, wxWindowBase)
472 #else
473 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
474 #endif
475
476 BEGIN_EVENT_TABLE(wxWindowCocoa, wxWindowBase)
477 END_EVENT_TABLE()
478
479 wxWindow *wxWindowCocoa::sm_capturedWindow = NULL;
480
481 // Constructor
482 void wxWindowCocoa::Init()
483 {
484     m_cocoaNSView = NULL;
485     m_cocoaHider = NULL;
486     m_wxCocoaScrollView = NULL;
487     m_isBeingDeleted = false;
488     m_isInPaint = false;
489     m_visibleTrackingRectManager = NULL;
490 }
491
492 // Constructor
493 bool wxWindow::Create(wxWindow *parent, wxWindowID winid,
494            const wxPoint& pos,
495            const wxSize& size,
496            long style,
497            const wxString& name)
498 {
499     if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
500         return false;
501
502     // TODO: create the window
503     m_cocoaNSView = NULL;
504     SetNSView([[WX_GET_OBJC_CLASS(WXNSView) alloc] initWithFrame: MakeDefaultNSRect(size)]);
505     [m_cocoaNSView release];
506
507     if (m_parent)
508     {
509         m_parent->AddChild(this);
510         m_parent->CocoaAddChild(this);
511         SetInitialFrameRect(pos,size);
512     }
513
514     return true;
515 }
516
517 // Destructor
518 wxWindow::~wxWindow()
519 {
520     wxAutoNSAutoreleasePool pool;
521     DestroyChildren();
522
523     // Make sure our parent (in the wxWidgets sense) is our superview
524     // before we go removing from it.
525     if(m_parent && m_parent->GetNSView()==[GetNSViewForSuperview() superview])
526         CocoaRemoveFromParent();
527     delete m_cocoaHider;
528     delete m_wxCocoaScrollView;
529     if(m_cocoaNSView)
530         SendDestroyEvent();
531     SetNSView(NULL);
532 }
533
534 void wxWindowCocoa::CocoaAddChild(wxWindowCocoa *child)
535 {
536     // Pool here due to lack of one during wx init phase
537     wxAutoNSAutoreleasePool pool;
538
539     NSView *childView = child->GetNSViewForSuperview();
540
541     wxASSERT(childView);
542     [m_cocoaNSView addSubview: childView];
543 }
544
545 void wxWindowCocoa::CocoaRemoveFromParent(void)
546 {
547     [GetNSViewForSuperview() removeFromSuperview];
548 }
549
550 void wxWindowCocoa::SetNSView(WX_NSView cocoaNSView)
551 {
552     // Clear the visible area tracking rect if we have one.
553     delete m_visibleTrackingRectManager;
554     m_visibleTrackingRectManager = NULL;
555
556     bool need_debug = cocoaNSView || m_cocoaNSView;
557     if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [m_cocoaNSView=%p retainCount]=%d"),this,m_cocoaNSView,[m_cocoaNSView retainCount]);
558     DisassociateNSView(m_cocoaNSView);
559     [cocoaNSView retain];
560     [m_cocoaNSView release];
561     m_cocoaNSView = cocoaNSView;
562     AssociateNSView(m_cocoaNSView);
563     if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [cocoaNSView=%p retainCount]=%d"),this,cocoaNSView,[cocoaNSView retainCount]);
564 }
565
566 WX_NSView wxWindowCocoa::GetNSViewForSuperview() const
567 {
568     return m_cocoaHider
569         ?   m_cocoaHider->GetNSView()
570         :   m_wxCocoaScrollView
571             ?   m_wxCocoaScrollView->GetNSScrollView()
572             :   m_cocoaNSView;
573 }
574
575 WX_NSView wxWindowCocoa::GetNSViewForHiding() const
576 {
577     return m_wxCocoaScrollView
578         ?   m_wxCocoaScrollView->GetNSScrollView()
579         :   m_cocoaNSView;
580 }
581
582 NSPoint wxWindowCocoa::CocoaTransformBoundsToWx(NSPoint pointBounds)
583 {
584     // TODO: Handle scrolling offset
585     return CocoaTransformNSViewBoundsToWx(GetNSView(), pointBounds);
586 }
587
588 NSRect wxWindowCocoa::CocoaTransformBoundsToWx(NSRect rectBounds)
589 {
590     // TODO: Handle scrolling offset
591     return CocoaTransformNSViewBoundsToWx(GetNSView(), rectBounds);
592 }
593
594 NSPoint wxWindowCocoa::CocoaTransformWxToBounds(NSPoint pointWx)
595 {
596     // TODO: Handle scrolling offset
597     return CocoaTransformNSViewWxToBounds(GetNSView(), pointWx);
598 }
599
600 NSRect wxWindowCocoa::CocoaTransformWxToBounds(NSRect rectWx)
601 {
602     // TODO: Handle scrolling offset
603     return CocoaTransformNSViewWxToBounds(GetNSView(), rectWx);
604 }
605
606 WX_NSAffineTransform wxWindowCocoa::CocoaGetWxToBoundsTransform()
607 {
608     // TODO: Handle scrolling offset
609     NSAffineTransform *transform = wxDC::CocoaGetWxToBoundsTransform([GetNSView() isFlipped], [GetNSView() bounds].size.height);
610     return transform;
611 }
612
613 bool wxWindowCocoa::Cocoa_drawRect(const NSRect &rect)
614 {
615     wxLogTrace(wxTRACE_COCOA,wxT("Cocoa_drawRect"));
616     // Recursion can happen if the event loop runs from within the paint
617     // handler.  For instance, if an assertion dialog is shown.
618     // FIXME: This seems less than ideal.
619     if(m_isInPaint)
620     {
621         wxLogDebug(wxT("Paint event recursion!"));
622         return false;
623     }
624     m_isInPaint = true;
625
626     // Set m_updateRegion
627     const NSRect *rects = &rect; // The bounding box of the region
628     NSInteger countRects = 1;
629     // Try replacing the larger rectangle with a list of smaller ones:
630     if ([GetNSView() respondsToSelector:@selector(getRectsBeingDrawn:count:)])
631         [GetNSView() getRectsBeingDrawn:&rects count:&countRects];
632
633     NSRect *transformedRects = (NSRect*)malloc(sizeof(NSRect)*countRects);
634     for(int i=0; i<countRects; i++)
635     {
636         transformedRects[i] = CocoaTransformBoundsToWx(rects[i]);
637     }
638     m_updateRegion = wxRegion(transformedRects,countRects);
639     free(transformedRects);
640
641     wxPaintEvent event(m_windowId);
642     event.SetEventObject(this);
643     bool ret = GetEventHandler()->ProcessEvent(event);
644     m_isInPaint = false;
645     return ret;
646 }
647
648 void wxWindowCocoa::InitMouseEvent(wxMouseEvent& event, WX_NSEvent cocoaEvent)
649 {
650     wxASSERT_MSG([m_cocoaNSView window]==[cocoaEvent window],wxT("Mouse event for different NSWindow"));
651     // Mouse events happen at the NSWindow level so we need to convert
652     // into our bounds coordinates then convert to wx coordinates.
653     NSPoint cocoaPoint = [m_cocoaNSView convertPoint:[(NSEvent*)cocoaEvent locationInWindow] fromView:nil];
654     NSPoint pointWx = CocoaTransformBoundsToWx(cocoaPoint);
655     // FIXME: Should we be adjusting for client area origin?
656     const wxPoint &clientorigin = GetClientAreaOrigin();
657     event.m_x = (wxCoord)pointWx.x - clientorigin.x;
658     event.m_y = (wxCoord)pointWx.y - clientorigin.y;
659
660     event.m_shiftDown = [cocoaEvent modifierFlags] & NSShiftKeyMask;
661     event.m_controlDown = [cocoaEvent modifierFlags] & NSControlKeyMask;
662     event.m_altDown = [cocoaEvent modifierFlags] & NSAlternateKeyMask;
663     event.m_metaDown = [cocoaEvent modifierFlags] & NSCommandKeyMask;
664
665     // TODO: set timestamp?
666     event.SetEventObject(this);
667     event.SetId(GetId());
668 }
669
670 bool wxWindowCocoa::Cocoa_mouseMoved(WX_NSEvent theEvent)
671 {
672     wxMouseEvent event(wxEVT_MOTION);
673     InitMouseEvent(event,theEvent);
674     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_mouseMoved @%d,%d"),this,event.m_x,event.m_y);
675     return GetEventHandler()->ProcessEvent(event);
676 }
677
678 void wxWindowCocoa::Cocoa_synthesizeMouseMoved()
679 {
680     wxMouseEvent event(wxEVT_MOTION);
681     NSWindow *window = [GetNSView() window];
682     NSPoint locationInWindow = [window mouseLocationOutsideOfEventStream];
683     NSPoint cocoaPoint = [m_cocoaNSView convertPoint:locationInWindow fromView:nil];
684
685     NSPoint pointWx = CocoaTransformBoundsToWx(cocoaPoint);
686     // FIXME: Should we be adjusting for client area origin?
687     const wxPoint &clientorigin = GetClientAreaOrigin();
688     event.m_x = (wxCoord)pointWx.x - clientorigin.x;
689     event.m_y = (wxCoord)pointWx.y - clientorigin.y;
690
691     // TODO: Handle shift, control, alt, meta flags
692     event.SetEventObject(this);
693     event.SetId(GetId());
694
695     wxLogTrace(wxTRACE_COCOA,wxT("wxwin=%p Synthesized Mouse Moved @%d,%d"),this,event.m_x,event.m_y);
696     GetEventHandler()->ProcessEvent(event);
697 }
698
699 bool wxWindowCocoa::Cocoa_mouseEntered(WX_NSEvent theEvent)
700 {
701     if(m_visibleTrackingRectManager != NULL && m_visibleTrackingRectManager->IsOwnerOfEvent(theEvent))
702     {
703         m_visibleTrackingRectManager->BeginSynthesizingEvents();
704
705         // Although we synthesize the mouse moved events we don't poll for them but rather send them only when
706         // some other event comes in.  That other event is (guess what) mouse moved events that will be sent
707         // to the NSWindow which will forward them on to the first responder.  We are not likely to be the
708         // first responder, so the mouseMoved: events are effectively discarded.
709         [[GetNSView() window] setAcceptsMouseMovedEvents:YES];
710
711         wxMouseEvent event(wxEVT_ENTER_WINDOW);
712         InitMouseEvent(event,theEvent);
713         wxLogTrace(wxTRACE_COCOA_TrackingRect,wxT("wxwin=%p Mouse Entered TR#%d @%d,%d"),this,[theEvent trackingNumber], event.m_x,event.m_y);
714         return GetEventHandler()->ProcessEvent(event);
715     }
716     else
717         return false;
718 }
719
720 bool wxWindowCocoa::Cocoa_mouseExited(WX_NSEvent theEvent)
721 {
722     if(m_visibleTrackingRectManager != NULL && m_visibleTrackingRectManager->IsOwnerOfEvent(theEvent))
723     {
724         m_visibleTrackingRectManager->StopSynthesizingEvents();
725
726         wxMouseEvent event(wxEVT_LEAVE_WINDOW);
727         InitMouseEvent(event,theEvent);
728         wxLogTrace(wxTRACE_COCOA_TrackingRect,wxT("wxwin=%p Mouse Exited TR#%d @%d,%d"),this,[theEvent trackingNumber],event.m_x,event.m_y);
729         return GetEventHandler()->ProcessEvent(event);
730     }
731     else
732         return false;
733 }
734
735 bool wxWindowCocoa::Cocoa_mouseDown(WX_NSEvent theEvent)
736 {
737     wxMouseEvent event([theEvent clickCount]<2?wxEVT_LEFT_DOWN:wxEVT_LEFT_DCLICK);
738     InitMouseEvent(event,theEvent);
739     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]);
740     return GetEventHandler()->ProcessEvent(event);
741 }
742
743 bool wxWindowCocoa::Cocoa_mouseDragged(WX_NSEvent theEvent)
744 {
745     wxMouseEvent event(wxEVT_MOTION);
746     InitMouseEvent(event,theEvent);
747     event.m_leftDown = true;
748     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
749     return GetEventHandler()->ProcessEvent(event);
750 }
751
752 bool wxWindowCocoa::Cocoa_mouseUp(WX_NSEvent theEvent)
753 {
754     wxMouseEvent event(wxEVT_LEFT_UP);
755     InitMouseEvent(event,theEvent);
756     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Up @%d,%d"),event.m_x,event.m_y);
757     return GetEventHandler()->ProcessEvent(event);
758 }
759
760 bool wxWindowCocoa::Cocoa_rightMouseDown(WX_NSEvent theEvent)
761 {
762     wxMouseEvent event([theEvent clickCount]<2?wxEVT_RIGHT_DOWN:wxEVT_RIGHT_DCLICK);
763     InitMouseEvent(event,theEvent);
764     wxLogDebug(wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]);
765     return GetEventHandler()->ProcessEvent(event);
766 }
767
768 bool wxWindowCocoa::Cocoa_rightMouseDragged(WX_NSEvent theEvent)
769 {
770     wxMouseEvent event(wxEVT_MOTION);
771     InitMouseEvent(event,theEvent);
772     event.m_rightDown = true;
773     wxLogDebug(wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
774     return GetEventHandler()->ProcessEvent(event);
775 }
776
777 bool wxWindowCocoa::Cocoa_rightMouseUp(WX_NSEvent theEvent)
778 {
779     wxMouseEvent event(wxEVT_RIGHT_UP);
780     InitMouseEvent(event,theEvent);
781     wxLogDebug(wxT("Mouse Up @%d,%d"),event.m_x,event.m_y);
782     return GetEventHandler()->ProcessEvent(event);
783 }
784
785 bool wxWindowCocoa::Cocoa_otherMouseDown(WX_NSEvent theEvent)
786 {
787     return false;
788 }
789
790 bool wxWindowCocoa::Cocoa_otherMouseDragged(WX_NSEvent theEvent)
791 {
792     return false;
793 }
794
795 bool wxWindowCocoa::Cocoa_otherMouseUp(WX_NSEvent theEvent)
796 {
797     return false;
798 }
799
800 void wxWindowCocoa::Cocoa_FrameChanged(void)
801 {
802     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_FrameChanged"),this);
803     if(m_visibleTrackingRectManager != NULL)
804         m_visibleTrackingRectManager->RebuildTrackingRect();
805     wxSizeEvent event(GetSize(), m_windowId);
806     event.SetEventObject(this);
807     GetEventHandler()->ProcessEvent(event);
808 }
809
810 bool wxWindowCocoa::Cocoa_resetCursorRects()
811 {
812     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_resetCursorRects"),this);
813
814     // When we are called there may be a queued tracking rect event (mouse entered or exited) and
815     // we won't know it.  A specific example is wxGenericHyperlinkCtrl changing the cursor from its
816     // mouse exited event.  If the control happens to share the edge with its parent window which is
817     // also tracking mouse events then Cocoa receives two mouse exited events from the window server.
818     // The first one will cause wxGenericHyperlinkCtrl to call wxWindow::SetCursor which will
819     // invaildate the cursor rect causing Cocoa to schedule cursor rect reset with the run loop
820     // which willl in turn call us before exiting for the next user event.
821
822     // If we are the parent window then rebuilding our tracking rectangle will cause us to miss
823     // our mouse exited event because the already queued event will have the old tracking rect
824     // tag.  The simple solution is to only rebuild our tracking rect if we need to.
825
826     if(m_visibleTrackingRectManager != NULL)
827         m_visibleTrackingRectManager->RebuildTrackingRectIfNeeded();
828
829     if(!m_cursor.GetNSCursor())
830         return false;
831
832     [GetNSView() addCursorRect: [GetNSView() visibleRect]  cursor: m_cursor.GetNSCursor()];
833
834     return true;
835 }
836
837 bool wxWindowCocoa::SetCursor(const wxCursor &cursor)
838 {
839     if(!wxWindowBase::SetCursor(cursor))
840         return false;
841
842     // Set up the cursor rect so that invalidateCursorRectsForView: will destroy it.
843     // If we don't do this then Cocoa thinks (rightly) that we don't have any cursor
844     // rects and thus won't ever call resetCursorRects.
845     [GetNSView() addCursorRect: [GetNSView() visibleRect]  cursor: m_cursor.GetNSCursor()];
846
847     // Invalidate the cursor rects so the cursor will change
848     // Note that it is not enough to remove the old one (if any) and add the new one.
849     // For the rects to work properly, Cocoa itself must call resetCursorRects.
850     [[GetNSView() window] invalidateCursorRectsForView:GetNSView()];
851     return true;
852 }
853
854 bool wxWindowCocoa::Cocoa_viewDidMoveToWindow()
855 {
856     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::viewDidMoveToWindow"),this);
857     // Set up new tracking rects.  I am reasonably sure the new window must be set before doing this.
858     if(m_visibleTrackingRectManager != NULL)
859         m_visibleTrackingRectManager->BuildTrackingRect();
860     return false;
861 }
862
863 bool wxWindowCocoa::Cocoa_viewWillMoveToWindow(WX_NSWindow newWindow)
864 {
865     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::viewWillMoveToWindow:%p"),this, newWindow);
866     // Clear tracking rects.  It is imperative this be done before the new window is set.
867     if(m_visibleTrackingRectManager != NULL)
868         m_visibleTrackingRectManager->ClearTrackingRect();
869     return false;
870 }
871
872 bool wxWindow::Close(bool force)
873 {
874     // The only reason this function exists is that it is virtual and
875     // wxTopLevelWindowCocoa will override it.
876     return wxWindowBase::Close(force);
877 }
878
879 void wxWindow::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
880 {
881     [[oldView superview] replaceSubview:oldView with:newView];
882 }
883
884 void wxWindow::DoEnable(bool enable)
885 {
886         CocoaSetEnabled(enable);
887 }
888
889 bool wxWindow::Show(bool show)
890 {
891     wxAutoNSAutoreleasePool pool;
892     // If the window is marked as visible, then it shouldn't have a dummy view
893     // If the window is marked hidden, then it should have a dummy view
894     // wxSpinCtrl (generic) abuses m_isShown, don't use it for any logic
895 //    wxASSERT_MSG( (m_isShown && !m_dummyNSView) || (!m_isShown && m_dummyNSView),wxT("wxWindow: m_isShown does not agree with m_dummyNSView"));
896     // Return false if there isn't a window to show or hide
897     NSView *cocoaView = GetNSViewForHiding();
898     if(!cocoaView)
899         return false;
900     if(show)
901     {
902         // If state isn't changing, return false
903         if(!m_cocoaHider)
904             return false;
905         CocoaReplaceView(m_cocoaHider->GetNSView(), cocoaView);
906         wxASSERT(![m_cocoaHider->GetNSView() superview]);
907         delete m_cocoaHider;
908         m_cocoaHider = NULL;
909         wxASSERT([cocoaView superview]);
910     }
911     else
912     {
913         // If state isn't changing, return false
914         if(m_cocoaHider)
915             return false;
916         m_cocoaHider = new wxWindowCocoaHider(this);
917         // NOTE: replaceSubview:with will cause m_cocaNSView to be
918         // (auto)released which balances out addSubview
919         CocoaReplaceView(cocoaView, m_cocoaHider->GetNSView());
920         // m_coocaNSView is now only retained by us
921         wxASSERT([m_cocoaHider->GetNSView() superview]);
922         wxASSERT(![cocoaView superview]);
923     }
924     m_isShown = show;
925     return true;
926 }
927
928 void wxWindowCocoa::DoSetSize(int x, int y, int width, int height, int sizeFlags)
929 {
930     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":".");
931     int currentX, currentY;
932     int currentW, currentH;
933     DoGetPosition(&currentX, &currentY);
934     DoGetSize(&currentW, &currentH);
935     if((x==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
936         x=currentX;
937     if((y==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
938         y=currentY;
939
940     AdjustForParentClientOrigin(x,y,sizeFlags);
941
942     wxSize size(wxDefaultSize);
943
944     if((width==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
945     {
946         if(sizeFlags&wxSIZE_AUTO_WIDTH)
947         {
948             size=DoGetBestSize();
949             width=size.x;
950         }
951         else
952             width=currentW;
953     }
954     if((height==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
955     {
956         if(sizeFlags&wxSIZE_AUTO_HEIGHT)
957         {
958             if(size.x==-1)
959                 size=DoGetBestSize();
960             height=size.y;
961         }
962         else
963             height=currentH;
964     }
965     DoMoveWindow(x,y,width,height);
966 }
967
968 #if wxUSE_TOOLTIPS
969
970 void wxWindowCocoa::DoSetToolTip( wxToolTip *tip )
971 {
972     wxWindowBase::DoSetToolTip(tip);
973
974     if ( m_tooltip )
975     {
976         m_tooltip->SetWindow((wxWindow *)this);
977     }
978 }
979
980 #endif
981
982 void wxWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
983 {
984     wxAutoNSAutoreleasePool pool;
985     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoMoveWindow(%d,%d,%d,%d)"),this,x,y,width,height);
986
987     NSView *nsview = GetNSViewForSuperview();
988     NSView *superview = [nsview superview];
989
990     wxCHECK_RET(GetParent(), wxT("Window can only be placed correctly when it has a parent"));
991
992     NSRect oldFrameRect = [nsview frame];
993     NSRect newFrameRect = GetParent()->CocoaTransformWxToBounds(NSMakeRect(x,y,width,height));
994     [nsview setFrame:newFrameRect];
995     // Be sure to redraw the parent to reflect the changed position
996     [superview setNeedsDisplayInRect:oldFrameRect];
997     [superview setNeedsDisplayInRect:newFrameRect];
998 }
999
1000 void wxWindowCocoa::SetInitialFrameRect(const wxPoint& pos, const wxSize& size)
1001 {
1002     NSView *nsview = GetNSViewForSuperview();
1003     NSView *superview = [nsview superview];
1004     wxCHECK_RET(superview,wxT("NSView does not have a superview"));
1005     wxCHECK_RET(GetParent(), wxT("Window can only be placed correctly when it has a parent"));
1006     NSRect frameRect = [nsview frame];
1007     if(size.x!=-1)
1008         frameRect.size.width = size.x;
1009     if(size.y!=-1)
1010         frameRect.size.height = size.y;
1011     frameRect.origin.x = pos.x;
1012     frameRect.origin.y = pos.y;
1013     // Tell Cocoa to change the margin between the bottom of the superview
1014     // and the bottom of the control.  Keeps the control pinned to the top
1015     // of its superview so that its position in the wxWidgets coordinate
1016     // system doesn't change.
1017     if(![superview isFlipped])
1018         [nsview setAutoresizingMask: NSViewMinYMargin];
1019     // MUST set the mask before setFrame: which can generate a size event
1020     // and cause a scroller to be added!
1021     frameRect = GetParent()->CocoaTransformWxToBounds(frameRect);
1022     [nsview setFrame: frameRect];
1023 }
1024
1025 // Get total size
1026 void wxWindow::DoGetSize(int *w, int *h) const
1027 {
1028     NSRect cocoaRect = [GetNSViewForSuperview() frame];
1029     if(w)
1030         *w=(int)cocoaRect.size.width;
1031     if(h)
1032         *h=(int)cocoaRect.size.height;
1033     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoGetSize = (%d,%d)"),this,(int)cocoaRect.size.width,(int)cocoaRect.size.height);
1034 }
1035
1036 void wxWindow::DoGetPosition(int *x, int *y) const
1037 {
1038     NSView *nsview = GetNSViewForSuperview();
1039
1040     NSRect cocoaRect = [nsview frame];
1041     NSRect rectWx = GetParent()->CocoaTransformBoundsToWx(cocoaRect);
1042     if(x)
1043         *x=(int)rectWx.origin.x;
1044     if(y)
1045         *y=(int)rectWx.origin.y;
1046     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoGetPosition = (%d,%d)"),this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);
1047 }
1048
1049 WXWidget wxWindow::GetHandle() const
1050 {
1051     return m_cocoaNSView;
1052 }
1053
1054 wxWindow* wxWindow::GetWxWindow() const
1055 {
1056     return (wxWindow*) this;
1057 }
1058
1059 void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
1060 {
1061     [m_cocoaNSView setNeedsDisplay:YES];
1062 }
1063
1064 void wxWindow::SetFocus()
1065 {
1066     if([GetNSView() acceptsFirstResponder])
1067         [[GetNSView() window] makeFirstResponder: GetNSView()];
1068 }
1069
1070 void wxWindow::DoCaptureMouse()
1071 {
1072     // TODO
1073     sm_capturedWindow = this;
1074 }
1075
1076 void wxWindow::DoReleaseMouse()
1077 {
1078     // TODO
1079     sm_capturedWindow = NULL;
1080 }
1081
1082 void wxWindow::DoScreenToClient(int *x, int *y) const
1083 {
1084     // Point in cocoa screen coordinates:
1085     NSPoint cocoaScreenPoint = OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x!=NULL?*x:0, y!=NULL?*y:0, 0, 0, false);
1086     NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
1087     NSWindow *theWindow = [clientView window];
1088
1089     // Point in window's base coordinate system:
1090     NSPoint windowPoint = [theWindow convertScreenToBase:cocoaScreenPoint];
1091     // Point in view's bounds coordinate system
1092     NSPoint boundsPoint = [clientView convertPoint:windowPoint fromView:nil];
1093     // Point in wx client coordinates:
1094     NSPoint theWxClientPoint = CocoaTransformNSViewBoundsToWx(clientView, boundsPoint);
1095     if(x!=NULL)
1096         *x = theWxClientPoint.x;
1097     if(y!=NULL)
1098         *y = theWxClientPoint.y;
1099 }
1100
1101 void wxWindow::DoClientToScreen(int *x, int *y) const
1102 {
1103     // Point in wx client coordinates
1104     NSPoint theWxClientPoint = NSMakePoint(x!=NULL?*x:0, y!=NULL?*y:0);
1105
1106     NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
1107
1108     // Point in the view's bounds coordinate system
1109     NSPoint boundsPoint = CocoaTransformNSViewWxToBounds(clientView, theWxClientPoint);
1110
1111     // Point in the window's base coordinate system
1112     NSPoint windowPoint = [clientView convertPoint:boundsPoint toView:nil];
1113
1114     NSWindow *theWindow = [clientView window];
1115     // Point in Cocoa's screen coordinates
1116     NSPoint screenPoint = [theWindow convertBaseToScreen:windowPoint];
1117
1118     // Act as though this was the origin of a 0x0 rectangle
1119     NSRect screenPointRect = NSMakeRect(screenPoint.x, screenPoint.y, 0, 0);
1120
1121     // Convert that rectangle to wx coordinates
1122     wxPoint theWxScreenPoint = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(screenPointRect);
1123     if(*x)
1124         *x = theWxScreenPoint.x;
1125     if(*y)
1126         *y = theWxScreenPoint.y;
1127 }
1128
1129 // Get size *available for subwindows* i.e. excluding menu bar etc.
1130 void wxWindow::DoGetClientSize(int *x, int *y) const
1131 {
1132     wxLogTrace(wxTRACE_COCOA,wxT("DoGetClientSize:"));
1133     if(m_wxCocoaScrollView)
1134         m_wxCocoaScrollView->DoGetClientSize(x,y);
1135     else
1136         wxWindowCocoa::DoGetSize(x,y);
1137 }
1138
1139 void wxWindow::DoSetClientSize(int width, int height)
1140 {
1141     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("DoSetClientSize=(%d,%d)"),width,height);
1142     if(m_wxCocoaScrollView)
1143         m_wxCocoaScrollView->ClientSizeToSize(width,height);
1144     CocoaSetWxWindowSize(width,height);
1145 }
1146
1147 void wxWindow::CocoaSetWxWindowSize(int width, int height)
1148 {
1149     wxWindowCocoa::DoSetSize(wxDefaultCoord,wxDefaultCoord,width,height,wxSIZE_USE_EXISTING);
1150 }
1151
1152 void wxWindow::SetLabel(const wxString& WXUNUSED(label))
1153 {
1154     // Intentional no-op.
1155 }
1156
1157 wxString wxWindow::GetLabel() const
1158 {
1159     // General Get/Set of labels is implemented in wxControlBase
1160     wxLogDebug(wxT("wxWindow::GetLabel: Should be overridden if needed."));
1161     return wxEmptyString;
1162 }
1163
1164 int wxWindow::GetCharHeight() const
1165 {
1166     // TODO
1167     return 10;
1168 }
1169
1170 int wxWindow::GetCharWidth() const
1171 {
1172     // TODO
1173     return 5;
1174 }
1175
1176 void wxWindow::GetTextExtent(const wxString& string, int *outX, int *outY,
1177         int *outDescent, int *outExternalLeading, const wxFont *inFont) const
1178 {
1179     // FIXME: This obviously ignores the window's font (if any) along with any size
1180     // transformations.  However, it's better than nothing.
1181     // We don't create a wxClientDC because we don't want to accidently be able to use
1182     // it for drawing.
1183     wxDC tmpdc;
1184     return tmpdc.GetTextExtent(string, outX, outY, outDescent, outExternalLeading, inFont);
1185 }
1186
1187 // Coordinates relative to the window
1188 void wxWindow::WarpPointer (int x_pos, int y_pos)
1189 {
1190     // TODO
1191 }
1192
1193 int wxWindow::GetScrollPos(int orient) const
1194 {
1195     // TODO
1196     return 0;
1197 }
1198
1199 // This now returns the whole range, not just the number
1200 // of positions that we can scroll.
1201 int wxWindow::GetScrollRange(int orient) const
1202 {
1203     // TODO
1204     return 0;
1205 }
1206
1207 int wxWindow::GetScrollThumb(int orient) const
1208 {
1209     // TODO
1210     return 0;
1211 }
1212
1213 void wxWindow::SetScrollPos(int orient, int pos, bool refresh)
1214 {
1215     // TODO
1216 }
1217
1218 void wxWindow::CocoaCreateNSScrollView()
1219 {
1220     if(!m_wxCocoaScrollView)
1221     {
1222         m_wxCocoaScrollView = new wxWindowCocoaScrollView(this);
1223     }
1224 }
1225
1226 // New function that will replace some of the above.
1227 void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible,
1228     int range, bool refresh)
1229 {
1230     CocoaCreateNSScrollView();
1231     // TODO
1232 }
1233
1234 // Does a physical scroll
1235 void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
1236 {
1237     // TODO
1238 }
1239
1240 static inline int _DoFixupDistance(int vDistance, int cDistance)
1241 {
1242     // If the virtual distance is wxDefaultCoord, set it to the client distance
1243     // This definitely has to be done or else we literally get views with a -1 size component!
1244     if(vDistance == wxDefaultCoord)
1245         vDistance = cDistance;
1246     // NOTE: Since cDistance should always be >= 0 and since wxDefaultCoord is -1, the above
1247     // test is more or less useless because it gets covered by the next one.  However, just in
1248     // case anyone decides that the next test is not correct, I want them to be aware that
1249     // the above test would still be needed.
1250
1251     // I am not entirely sure about this next one but I believe it makes sense because
1252     // otherwise the virtual view (which is the m_cocoaNSView that got wrapped by the scrolling
1253     // machinery) can be smaller than the NSClipView (the client area) which
1254     // means that, for instance, mouse clicks inside the client area as wx sees it but outside
1255     // the virtual area as wx sees it won't be seen by the m_cocoaNSView.
1256     // We make the assumption that if a virtual distance is less than the client distance that
1257     // the real view must already be or will soon be positioned at coordinate 0  within the
1258     // NSClipView that represents the client area.  This way, when we increase the distance to
1259     // be the client distance, the real view will exactly fit in the clip view.
1260     else if(vDistance < cDistance)
1261         vDistance = cDistance;
1262     return vDistance;
1263 }
1264
1265 void wxWindow::DoSetVirtualSize( int x, int y )
1266 {
1267     // Call wxWindowBase method which will set m_virtualSize to the appropriate value,
1268     // possibly not what the caller passed in.  For example, the current implementation
1269     // clamps the width and height to within the min/max virtual ranges.
1270     // wxDefaultCoord is passed through unchanged which means we need to handle it ourselves
1271     // which we do by using the _DoFixupDistance helper method.
1272     wxWindowBase::DoSetVirtualSize(x,y);
1273     // Create the scroll view if it hasn't been already.
1274     CocoaCreateNSScrollView();
1275     // Now use fixed-up distances when setting the frame size
1276     wxSize clientSize = GetClientSize();
1277     [m_cocoaNSView setFrameSize:NSMakeSize(_DoFixupDistance(m_virtualSize.x, clientSize.x), _DoFixupDistance(m_virtualSize.y, clientSize.y))];
1278 }
1279
1280 bool wxWindow::SetFont(const wxFont& font)
1281 {
1282     // FIXME: We may need to handle wx font inheritance.
1283     return wxWindowBase::SetFont(font);
1284 }
1285
1286 #if 0 // these are used when debugging the algorithm.
1287 static char const * const comparisonresultStrings[] =
1288 {   "<"
1289 ,   "=="
1290 ,   ">"
1291 };
1292 #endif
1293
1294 class CocoaWindowCompareContext
1295 {
1296     DECLARE_NO_COPY_CLASS(CocoaWindowCompareContext)
1297 public:
1298     CocoaWindowCompareContext(); // Not implemented
1299     CocoaWindowCompareContext(NSView *target, NSArray *subviews)
1300     {
1301         m_target = target;
1302         // Cocoa sorts subviews in-place.. make a copy
1303         m_subviews = [subviews copy];
1304     }
1305     ~CocoaWindowCompareContext()
1306     {   // release the copy
1307         [m_subviews release];
1308     }
1309     NSView* target()
1310     {   return m_target; }
1311     NSArray* subviews()
1312     {   return m_subviews; }
1313     /* Helper function that returns the comparison based off of the original ordering */
1314     CocoaWindowCompareFunctionResult CompareUsingOriginalOrdering(id first, id second)
1315     {
1316         NSUInteger firstI = [m_subviews indexOfObjectIdenticalTo:first];
1317         NSUInteger secondI = [m_subviews indexOfObjectIdenticalTo:second];
1318         // NOTE: If either firstI or secondI is NSNotFound then it will be NSIntegerMax and thus will
1319         // likely compare higher than the other view which is reasonable considering the only way that
1320         // can happen is if the subview was added after our call to subviews but before the call to
1321         // sortSubviewsUsingFunction:context:.  Thus we don't bother checking.  Particularly because
1322         // that case should never occur anyway because that would imply a multi-threaded GUI call
1323         // which is a big no-no with Cocoa.
1324
1325         // Subviews are ordered from back to front meaning one that is already lower will have an lower index.
1326         NSComparisonResult result = (firstI < secondI)
1327             ?   NSOrderedAscending /* -1 */
1328             :   (firstI > secondI)
1329                 ?   NSOrderedDescending /* 1 */
1330                 :   NSOrderedSame /* 0 */;
1331
1332 #if 0 // Enable this if you need to debug the algorithm.
1333         NSLog(@"%@ [%d] %s %@ [%d]\n", first, firstI, comparisonresultStrings[result+1], second, secondI);
1334 #endif
1335         return result;
1336     }
1337 private:
1338     /* The subview we are trying to Raise or Lower */
1339     NSView *m_target;
1340     /* A copy of the original array of subviews */
1341     NSArray *m_subviews;
1342 };
1343
1344 /* Causes Cocoa to raise the target view to the top of the Z-Order by telling the sort function that
1345  * the target view is always higher than every other view.  When comparing two views neither of
1346  * which is the target, it returns the correct response based on the original ordering
1347  */
1348 static CocoaWindowCompareFunctionResult CocoaRaiseWindowCompareFunction(id first, id second, void *ctx)
1349 {
1350     CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
1351     // first should be ordered higher
1352     if(first==compareContext->target())
1353         return NSOrderedDescending;
1354     // second should be ordered higher
1355     if(second==compareContext->target())
1356         return NSOrderedAscending;
1357     return compareContext->CompareUsingOriginalOrdering(first,second);
1358 }
1359
1360 // Raise the window to the top of the Z order
1361 void wxWindow::Raise()
1362 {
1363 //    wxAutoNSAutoreleasePool pool;
1364     NSView *nsview = GetNSViewForSuperview();
1365     NSView *superview = [nsview superview];
1366     CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1367
1368     [superview sortSubviewsUsingFunction:
1369             CocoaRaiseWindowCompareFunction
1370         context: &compareContext];
1371 }
1372
1373 /* Causes Cocoa to lower the target view to the bottom of the Z-Order by telling the sort function that
1374  * the target view is always lower than every other view.  When comparing two views neither of
1375  * which is the target, it returns the correct response based on the original ordering
1376  */
1377 static CocoaWindowCompareFunctionResult CocoaLowerWindowCompareFunction(id first, id second, void *ctx)
1378 {
1379     CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
1380     // first should be ordered lower
1381     if(first==compareContext->target())
1382         return NSOrderedAscending;
1383     // second should be ordered lower
1384     if(second==compareContext->target())
1385         return NSOrderedDescending;
1386     return compareContext->CompareUsingOriginalOrdering(first,second);
1387 }
1388
1389 // Lower the window to the bottom of the Z order
1390 void wxWindow::Lower()
1391 {
1392     NSView *nsview = GetNSViewForSuperview();
1393     NSView *superview = [nsview superview];
1394     CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1395
1396 #if 0
1397     NSLog(@"Target:\n%@\n", nsview);
1398     NSLog(@"Before:\n%@\n", compareContext.subviews());
1399 #endif
1400     [superview sortSubviewsUsingFunction:
1401             CocoaLowerWindowCompareFunction
1402         context: &compareContext];
1403 #if 0
1404     NSLog(@"After:\n%@\n", [superview subviews]);
1405 #endif
1406 }
1407
1408 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
1409 {
1410     return false;
1411 }
1412
1413 // Get the window with the focus
1414 wxWindow *wxWindowBase::DoFindFocus()
1415 {
1416     // Basically we are somewhat emulating the responder chain here except
1417     // we are only loking for the first responder in the key window or
1418     // upon failing to find one if the main window is different we look
1419     // for the first responder in the main window.
1420
1421     // Note that the firstResponder doesn't necessarily have to be an
1422     // NSView but wxCocoaNSView::GetFromCocoa() will simply return
1423     // NULL unless it finds its argument in its hash map.
1424
1425     wxCocoaNSView *win;
1426
1427     NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
1428     win = wxCocoaNSView::GetFromCocoa(static_cast<NSView*>([keyWindow firstResponder]));
1429     if(win)
1430         return win->GetWxWindow();
1431
1432     NSWindow *mainWindow = [[NSApplication sharedApplication] keyWindow];
1433     if(mainWindow == keyWindow)
1434         return NULL;
1435     win = wxCocoaNSView::GetFromCocoa(static_cast<NSView*>([mainWindow firstResponder]));
1436     if(win)
1437         return win->GetWxWindow();
1438
1439     return NULL;
1440 }
1441
1442 /* static */ wxWindow *wxWindowBase::GetCapture()
1443 {
1444     // TODO
1445     return wxWindowCocoa::sm_capturedWindow;
1446 }
1447
1448 wxWindow *wxGetActiveWindow()
1449 {
1450     // TODO
1451     return NULL;
1452 }
1453
1454 wxPoint wxGetMousePosition()
1455 {
1456     // TODO
1457     return wxDefaultPosition;
1458 }
1459
1460 wxMouseState wxGetMouseState()
1461 {
1462     wxMouseState ms;
1463     // TODO
1464     return ms;
1465 }
1466
1467 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1468 {
1469     pt = wxGetMousePosition();
1470     return NULL;
1471 }
1472
1473 // ========================================================================
1474 // wxCocoaMouseMovedEventSynthesizer
1475 // ========================================================================
1476
1477 #define wxTRACE_COCOA_MouseMovedSynthesizer wxT("COCOA_MouseMovedSynthesizer")
1478
1479 /* This class registers one run loop observer to cover all windows registered with it.
1480  *  It will register the observer when the first view is registerd and unregister the
1481  * observer when the last view is unregistered.
1482  * It is instantiated as a static s_mouseMovedSynthesizer in this file although there
1483  * is no reason it couldn't be instantiated multiple times.
1484  */
1485 class wxCocoaMouseMovedEventSynthesizer
1486 {
1487     DECLARE_NO_COPY_CLASS(wxCocoaMouseMovedEventSynthesizer)
1488 public:
1489     wxCocoaMouseMovedEventSynthesizer()
1490     {   m_lastScreenMouseLocation = NSZeroPoint;
1491     }
1492     ~wxCocoaMouseMovedEventSynthesizer();
1493     void RegisterWxCocoaView(wxCocoaNSView *aView);
1494     void UnregisterWxCocoaView(wxCocoaNSView *aView);
1495     void SynthesizeMouseMovedEvent();
1496     
1497 protected:
1498     void AddRunLoopObserver();
1499     void RemoveRunLoopObserver();
1500     wxCFRef<CFRunLoopObserverRef> m_runLoopObserver;
1501     std::list<wxCocoaNSView*> m_registeredViews;
1502     NSPoint m_lastScreenMouseLocation;
1503     static void SynthesizeMouseMovedEvent(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
1504 };
1505
1506 void wxCocoaMouseMovedEventSynthesizer::RegisterWxCocoaView(wxCocoaNSView *aView)
1507 {
1508     m_registeredViews.push_back(aView);
1509     wxLogTrace(wxTRACE_COCOA_MouseMovedSynthesizer, wxT("Registered wxCocoaNSView=%p"), aView);
1510
1511     if(!m_registeredViews.empty() && m_runLoopObserver == NULL)
1512     {
1513         AddRunLoopObserver();
1514     }
1515 }
1516
1517 void wxCocoaMouseMovedEventSynthesizer::UnregisterWxCocoaView(wxCocoaNSView *aView)
1518 {
1519     m_registeredViews.remove(aView);
1520     wxLogTrace(wxTRACE_COCOA_MouseMovedSynthesizer, wxT("Unregistered wxCocoaNSView=%p"), aView);
1521     if(m_registeredViews.empty() && m_runLoopObserver != NULL)
1522     {
1523         RemoveRunLoopObserver();
1524     }
1525 }
1526
1527 wxCocoaMouseMovedEventSynthesizer::~wxCocoaMouseMovedEventSynthesizer()
1528 {
1529     if(!m_registeredViews.empty())
1530     {
1531         // This means failure to clean up so we report on it as a debug message.
1532         wxLogDebug(wxT("There are still %d wxCocoaNSView registered to receive mouse moved events at static destruction time"), m_registeredViews.size());
1533         m_registeredViews.clear();
1534     }
1535     if(m_runLoopObserver != NULL)
1536     {
1537         // This should not occur unless m_registeredViews was not empty since the last object unregistered should have done this.
1538         wxLogDebug(wxT("Removing run loop observer during static destruction time."));
1539         RemoveRunLoopObserver();
1540     }
1541 }
1542
1543 void wxCocoaMouseMovedEventSynthesizer::SynthesizeMouseMovedEvent(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
1544 {
1545     reinterpret_cast<wxCocoaMouseMovedEventSynthesizer*>(info)->SynthesizeMouseMovedEvent();
1546 }
1547
1548 void wxCocoaMouseMovedEventSynthesizer::AddRunLoopObserver()
1549 {
1550     CFRunLoopObserverContext observerContext =
1551     {   0
1552     ,   this
1553     ,   NULL
1554     ,   NULL
1555     ,   NULL
1556     };
1557
1558     // The kCFRunLoopExit observation point is used such that we hook the run loop after it has already decided that
1559     // it is going to exit which is generally for the purpose of letting the event loop process the next Cocoa event.
1560
1561     // Executing our procedure within the run loop (e.g. kCFRunLoopBeforeWaiting which was used before) results
1562     // in our observer procedure being called before the run loop has decided that it is going to return control to
1563     // the Cocoa event loop.  One major problem is uncovered by the wxGenericHyperlinkCtrl (consider this to be "user
1564     // code") which changes the window's cursor and thus causes the cursor rectangle's to be invalidated.
1565
1566     // Cocoa implements this invalidation using a delayed notification scheme whereby the resetCursorRects method
1567     // won't be called until the CFRunLoop gets around to it.  If the CFRunLoop has not yet exited then it will get
1568     // around to it before letting the event loop do its work.  This has some very odd effects on the way the
1569     // newly created tracking rects function.  In particular, we will often miss the mouseExited: message if the
1570     // user flicks the mouse quickly enough such that the mouse is already outside of the tracking rect by the
1571     // time the new one is built.
1572
1573     // Observing from the kCFRunLoopExit point gives Cocoa's event loop an opportunity to chew some events before it cedes
1574     // control back to the CFRunLoop, thus causing the delayed notifications to fire at an appropriate time and
1575     // the mouseExited: message to be sent properly.
1576
1577     m_runLoopObserver.reset(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopExit, TRUE, 0, SynthesizeMouseMovedEvent, &observerContext));
1578     CFRunLoopAddObserver([[NSRunLoop currentRunLoop] getCFRunLoop], m_runLoopObserver, kCFRunLoopCommonModes);
1579     wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Added tracking rect run loop observer"));
1580 }
1581
1582 void wxCocoaMouseMovedEventSynthesizer::RemoveRunLoopObserver()
1583 {
1584     CFRunLoopRemoveObserver([[NSRunLoop currentRunLoop] getCFRunLoop], m_runLoopObserver, kCFRunLoopCommonModes);
1585     m_runLoopObserver.reset();
1586     wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Removed tracking rect run loop observer"));
1587 }
1588
1589 void wxCocoaMouseMovedEventSynthesizer::SynthesizeMouseMovedEvent()
1590 {
1591     NSPoint screenMouseLocation = [NSEvent mouseLocation];
1592     // Checking the last mouse location is done for a few reasons:
1593     // 1. We are observing every iteration of the event loop so we'd be sending out a lot of extraneous events
1594     //    telling the app the mouse moved when the user hit a key for instance.
1595     // 2. When handling the mouse moved event, user code can do something to the view which will cause Cocoa to
1596     //    call resetCursorRects.  Cocoa does this by using a delayed notification which means the event loop gets
1597     //    pumped once which would mean that if we didn't check the mouse location we'd get into a never-ending
1598     //    loop causing the tracking rectangles to constantly be reset.
1599     if(screenMouseLocation.x != m_lastScreenMouseLocation.x || screenMouseLocation.y != m_lastScreenMouseLocation.y)
1600     {
1601         m_lastScreenMouseLocation = screenMouseLocation;
1602         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Synthesizing mouse moved at screen (%f,%f)"), screenMouseLocation.x, screenMouseLocation.y);
1603         for(std::list<wxCocoaNSView*>::iterator i = m_registeredViews.begin(); i != m_registeredViews.end(); ++i)
1604         {
1605             (*i)->Cocoa_synthesizeMouseMoved();
1606         }
1607     }
1608 }
1609
1610 // Singleton used for all views:
1611 static wxCocoaMouseMovedEventSynthesizer s_mouseMovedSynthesizer;
1612
1613 // ========================================================================
1614 // wxCocoaTrackingRectManager
1615 // ========================================================================
1616
1617 wxCocoaTrackingRectManager::wxCocoaTrackingRectManager(wxWindow *window)
1618 :   m_window(window)
1619 {
1620     m_isTrackingRectActive = false;
1621     BuildTrackingRect();
1622 }
1623
1624 void wxCocoaTrackingRectManager::ClearTrackingRect()
1625 {
1626     if(m_isTrackingRectActive)
1627     {
1628         [m_window->GetNSView() removeTrackingRect:m_trackingRectTag];
1629         m_isTrackingRectActive = false;
1630         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("%s@%p: Removed tracking rect #%d"), m_window->GetClassInfo()->GetClassName(), m_window, m_trackingRectTag);
1631     }
1632     // If we were doing periodic events we need to clear those too
1633     StopSynthesizingEvents();
1634 }
1635
1636 void wxCocoaTrackingRectManager::StopSynthesizingEvents()
1637 {
1638     s_mouseMovedSynthesizer.UnregisterWxCocoaView(m_window);
1639 }
1640
1641 void wxCocoaTrackingRectManager::BuildTrackingRect()
1642 {
1643     // Pool here due to lack of one during wx init phase
1644     wxAutoNSAutoreleasePool pool;
1645
1646     wxASSERT_MSG(!m_isTrackingRectActive, wxT("Tracking rect was not cleared"));
1647
1648     NSView *theView = m_window->GetNSView();
1649
1650     if([theView window] != nil)
1651     {
1652         NSRect visibleRect = [theView visibleRect];
1653
1654         m_trackingRectTag = [theView addTrackingRect:visibleRect owner:theView userData:NULL assumeInside:NO];
1655         m_trackingRectInWindowCoordinates = [theView convertRect:visibleRect toView:nil];
1656         m_isTrackingRectActive = true;
1657
1658         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("%s@%p: Added tracking rect #%d"), m_window->GetClassInfo()->GetClassName(), m_window, m_trackingRectTag);
1659     }
1660 }
1661
1662 void wxCocoaTrackingRectManager::BeginSynthesizingEvents()
1663 {
1664     s_mouseMovedSynthesizer.RegisterWxCocoaView(m_window);
1665 }
1666
1667 void wxCocoaTrackingRectManager::RebuildTrackingRectIfNeeded()
1668 {
1669     if(m_isTrackingRectActive)
1670     {
1671         NSView *theView = m_window->GetNSView();
1672         NSRect currentRect = [theView convertRect:[theView visibleRect] toView:nil];
1673         if(NSEqualRects(m_trackingRectInWindowCoordinates,currentRect))
1674         {
1675             wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Ignored request to rebuild TR#%d"), m_trackingRectTag);
1676             return;
1677         }
1678     }
1679     RebuildTrackingRect();
1680 }
1681
1682 void wxCocoaTrackingRectManager::RebuildTrackingRect()
1683 {
1684     ClearTrackingRect();
1685     BuildTrackingRect();
1686 }
1687
1688 wxCocoaTrackingRectManager::~wxCocoaTrackingRectManager()
1689 {
1690     ClearTrackingRect();
1691 }
1692
1693 bool wxCocoaTrackingRectManager::IsOwnerOfEvent(NSEvent *anEvent)
1694 {
1695     return m_isTrackingRectActive && (m_trackingRectTag == [anEvent trackingNumber]);
1696 }
1697