Implement wxWindow::GetTextExtent to use wxDC to at least return something
[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     child->m_isShown = !m_cocoaHider;
544 }
545
546 void wxWindowCocoa::CocoaRemoveFromParent(void)
547 {
548     [GetNSViewForSuperview() removeFromSuperview];
549 }
550
551 void wxWindowCocoa::SetNSView(WX_NSView cocoaNSView)
552 {
553     // Clear the visible area tracking rect if we have one.
554     delete m_visibleTrackingRectManager;
555     m_visibleTrackingRectManager = NULL;
556
557     bool need_debug = cocoaNSView || m_cocoaNSView;
558     if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [m_cocoaNSView=%p retainCount]=%d"),this,m_cocoaNSView,[m_cocoaNSView retainCount]);
559     DisassociateNSView(m_cocoaNSView);
560     [cocoaNSView retain];
561     [m_cocoaNSView release];
562     m_cocoaNSView = cocoaNSView;
563     AssociateNSView(m_cocoaNSView);
564     if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [cocoaNSView=%p retainCount]=%d"),this,cocoaNSView,[cocoaNSView retainCount]);
565 }
566
567 WX_NSView wxWindowCocoa::GetNSViewForSuperview() const
568 {
569     return m_cocoaHider
570         ?   m_cocoaHider->GetNSView()
571         :   m_wxCocoaScrollView
572             ?   m_wxCocoaScrollView->GetNSScrollView()
573             :   m_cocoaNSView;
574 }
575
576 WX_NSView wxWindowCocoa::GetNSViewForHiding() const
577 {
578     return m_wxCocoaScrollView
579         ?   m_wxCocoaScrollView->GetNSScrollView()
580         :   m_cocoaNSView;
581 }
582
583 NSPoint wxWindowCocoa::CocoaTransformBoundsToWx(NSPoint pointBounds)
584 {
585     // TODO: Handle scrolling offset
586     return CocoaTransformNSViewBoundsToWx(GetNSView(), pointBounds);
587 }
588
589 NSRect wxWindowCocoa::CocoaTransformBoundsToWx(NSRect rectBounds)
590 {
591     // TODO: Handle scrolling offset
592     return CocoaTransformNSViewBoundsToWx(GetNSView(), rectBounds);
593 }
594
595 NSPoint wxWindowCocoa::CocoaTransformWxToBounds(NSPoint pointWx)
596 {
597     // TODO: Handle scrolling offset
598     return CocoaTransformNSViewWxToBounds(GetNSView(), pointWx);
599 }
600
601 NSRect wxWindowCocoa::CocoaTransformWxToBounds(NSRect rectWx)
602 {
603     // TODO: Handle scrolling offset
604     return CocoaTransformNSViewWxToBounds(GetNSView(), rectWx);
605 }
606
607 WX_NSAffineTransform wxWindowCocoa::CocoaGetWxToBoundsTransform()
608 {
609     // TODO: Handle scrolling offset
610     NSAffineTransform *transform = wxDC::CocoaGetWxToBoundsTransform([GetNSView() isFlipped], [GetNSView() bounds].size.height);
611     return transform;
612 }
613
614 bool wxWindowCocoa::Cocoa_drawRect(const NSRect &rect)
615 {
616     wxLogTrace(wxTRACE_COCOA,wxT("Cocoa_drawRect"));
617     // Recursion can happen if the event loop runs from within the paint
618     // handler.  For instance, if an assertion dialog is shown.
619     // FIXME: This seems less than ideal.
620     if(m_isInPaint)
621     {
622         wxLogDebug(wxT("Paint event recursion!"));
623         return false;
624     }
625     m_isInPaint = true;
626
627     // Set m_updateRegion
628     const NSRect *rects = &rect; // The bounding box of the region
629     NSInteger countRects = 1;
630     // Try replacing the larger rectangle with a list of smaller ones:
631     if ([GetNSView() respondsToSelector:@selector(getRectsBeingDrawn:count:)])
632         [GetNSView() getRectsBeingDrawn:&rects count:&countRects];
633
634     NSRect *transformedRects = (NSRect*)malloc(sizeof(NSRect)*countRects);
635     for(int i=0; i<countRects; i++)
636     {
637         transformedRects[i] = CocoaTransformBoundsToWx(rects[i]);
638     }
639     m_updateRegion = wxRegion(transformedRects,countRects);
640     free(transformedRects);
641
642     wxPaintEvent event(m_windowId);
643     event.SetEventObject(this);
644     bool ret = GetEventHandler()->ProcessEvent(event);
645     m_isInPaint = false;
646     return ret;
647 }
648
649 void wxWindowCocoa::InitMouseEvent(wxMouseEvent& event, WX_NSEvent cocoaEvent)
650 {
651     wxASSERT_MSG([m_cocoaNSView window]==[cocoaEvent window],wxT("Mouse event for different NSWindow"));
652     // Mouse events happen at the NSWindow level so we need to convert
653     // into our bounds coordinates then convert to wx coordinates.
654     NSPoint cocoaPoint = [m_cocoaNSView convertPoint:[(NSEvent*)cocoaEvent locationInWindow] fromView:nil];
655     NSPoint pointWx = CocoaTransformBoundsToWx(cocoaPoint);
656     // FIXME: Should we be adjusting for client area origin?
657     const wxPoint &clientorigin = GetClientAreaOrigin();
658     event.m_x = (wxCoord)pointWx.x - clientorigin.x;
659     event.m_y = (wxCoord)pointWx.y - clientorigin.y;
660
661     event.m_shiftDown = [cocoaEvent modifierFlags] & NSShiftKeyMask;
662     event.m_controlDown = [cocoaEvent modifierFlags] & NSControlKeyMask;
663     event.m_altDown = [cocoaEvent modifierFlags] & NSAlternateKeyMask;
664     event.m_metaDown = [cocoaEvent modifierFlags] & NSCommandKeyMask;
665
666     // TODO: set timestamp?
667     event.SetEventObject(this);
668     event.SetId(GetId());
669 }
670
671 bool wxWindowCocoa::Cocoa_mouseMoved(WX_NSEvent theEvent)
672 {
673     wxMouseEvent event(wxEVT_MOTION);
674     InitMouseEvent(event,theEvent);
675     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_mouseMoved @%d,%d"),this,event.m_x,event.m_y);
676     return GetEventHandler()->ProcessEvent(event);
677 }
678
679 void wxWindowCocoa::Cocoa_synthesizeMouseMoved()
680 {
681     wxMouseEvent event(wxEVT_MOTION);
682     NSWindow *window = [GetNSView() window];
683     NSPoint locationInWindow = [window mouseLocationOutsideOfEventStream];
684     NSPoint cocoaPoint = [m_cocoaNSView convertPoint:locationInWindow fromView:nil];
685
686     NSPoint pointWx = CocoaTransformBoundsToWx(cocoaPoint);
687     // FIXME: Should we be adjusting for client area origin?
688     const wxPoint &clientorigin = GetClientAreaOrigin();
689     event.m_x = (wxCoord)pointWx.x - clientorigin.x;
690     event.m_y = (wxCoord)pointWx.y - clientorigin.y;
691
692     // TODO: Handle shift, control, alt, meta flags
693     event.SetEventObject(this);
694     event.SetId(GetId());
695
696     wxLogTrace(wxTRACE_COCOA,wxT("wxwin=%p Synthesized Mouse Moved @%d,%d"),this,event.m_x,event.m_y);
697     GetEventHandler()->ProcessEvent(event);
698 }
699
700 bool wxWindowCocoa::Cocoa_mouseEntered(WX_NSEvent theEvent)
701 {
702     if(m_visibleTrackingRectManager != NULL && m_visibleTrackingRectManager->IsOwnerOfEvent(theEvent))
703     {
704         m_visibleTrackingRectManager->BeginSynthesizingEvents();
705
706         // Although we synthesize the mouse moved events we don't poll for them but rather send them only when
707         // some other event comes in.  That other event is (guess what) mouse moved events that will be sent
708         // to the NSWindow which will forward them on to the first responder.  We are not likely to be the
709         // first responder, so the mouseMoved: events are effectively discarded.
710         [[GetNSView() window] setAcceptsMouseMovedEvents:YES];
711
712         wxMouseEvent event(wxEVT_ENTER_WINDOW);
713         InitMouseEvent(event,theEvent);
714         wxLogTrace(wxTRACE_COCOA_TrackingRect,wxT("wxwin=%p Mouse Entered TR#%d @%d,%d"),this,[theEvent trackingNumber], event.m_x,event.m_y);
715         return GetEventHandler()->ProcessEvent(event);
716     }
717     else
718         return false;
719 }
720
721 bool wxWindowCocoa::Cocoa_mouseExited(WX_NSEvent theEvent)
722 {
723     if(m_visibleTrackingRectManager != NULL && m_visibleTrackingRectManager->IsOwnerOfEvent(theEvent))
724     {
725         m_visibleTrackingRectManager->StopSynthesizingEvents();
726
727         wxMouseEvent event(wxEVT_LEAVE_WINDOW);
728         InitMouseEvent(event,theEvent);
729         wxLogTrace(wxTRACE_COCOA_TrackingRect,wxT("wxwin=%p Mouse Exited TR#%d @%d,%d"),this,[theEvent trackingNumber],event.m_x,event.m_y);
730         return GetEventHandler()->ProcessEvent(event);
731     }
732     else
733         return false;
734 }
735
736 bool wxWindowCocoa::Cocoa_mouseDown(WX_NSEvent theEvent)
737 {
738     wxMouseEvent event([theEvent clickCount]<2?wxEVT_LEFT_DOWN:wxEVT_LEFT_DCLICK);
739     InitMouseEvent(event,theEvent);
740     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]);
741     return GetEventHandler()->ProcessEvent(event);
742 }
743
744 bool wxWindowCocoa::Cocoa_mouseDragged(WX_NSEvent theEvent)
745 {
746     wxMouseEvent event(wxEVT_MOTION);
747     InitMouseEvent(event,theEvent);
748     event.m_leftDown = true;
749     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
750     return GetEventHandler()->ProcessEvent(event);
751 }
752
753 bool wxWindowCocoa::Cocoa_mouseUp(WX_NSEvent theEvent)
754 {
755     wxMouseEvent event(wxEVT_LEFT_UP);
756     InitMouseEvent(event,theEvent);
757     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Up @%d,%d"),event.m_x,event.m_y);
758     return GetEventHandler()->ProcessEvent(event);
759 }
760
761 bool wxWindowCocoa::Cocoa_rightMouseDown(WX_NSEvent theEvent)
762 {
763     wxMouseEvent event([theEvent clickCount]<2?wxEVT_RIGHT_DOWN:wxEVT_RIGHT_DCLICK);
764     InitMouseEvent(event,theEvent);
765     wxLogDebug(wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]);
766     return GetEventHandler()->ProcessEvent(event);
767 }
768
769 bool wxWindowCocoa::Cocoa_rightMouseDragged(WX_NSEvent theEvent)
770 {
771     wxMouseEvent event(wxEVT_MOTION);
772     InitMouseEvent(event,theEvent);
773     event.m_rightDown = true;
774     wxLogDebug(wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
775     return GetEventHandler()->ProcessEvent(event);
776 }
777
778 bool wxWindowCocoa::Cocoa_rightMouseUp(WX_NSEvent theEvent)
779 {
780     wxMouseEvent event(wxEVT_RIGHT_UP);
781     InitMouseEvent(event,theEvent);
782     wxLogDebug(wxT("Mouse Up @%d,%d"),event.m_x,event.m_y);
783     return GetEventHandler()->ProcessEvent(event);
784 }
785
786 bool wxWindowCocoa::Cocoa_otherMouseDown(WX_NSEvent theEvent)
787 {
788     return false;
789 }
790
791 bool wxWindowCocoa::Cocoa_otherMouseDragged(WX_NSEvent theEvent)
792 {
793     return false;
794 }
795
796 bool wxWindowCocoa::Cocoa_otherMouseUp(WX_NSEvent theEvent)
797 {
798     return false;
799 }
800
801 void wxWindowCocoa::Cocoa_FrameChanged(void)
802 {
803     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_FrameChanged"),this);
804     if(m_visibleTrackingRectManager != NULL)
805         m_visibleTrackingRectManager->RebuildTrackingRect();
806     wxSizeEvent event(GetSize(), m_windowId);
807     event.SetEventObject(this);
808     GetEventHandler()->ProcessEvent(event);
809 }
810
811 bool wxWindowCocoa::Cocoa_resetCursorRects()
812 {
813     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_resetCursorRects"),this);
814
815     // When we are called there may be a queued tracking rect event (mouse entered or exited) and
816     // we won't know it.  A specific example is wxGenericHyperlinkCtrl changing the cursor from its
817     // mouse exited event.  If the control happens to share the edge with its parent window which is
818     // also tracking mouse events then Cocoa receives two mouse exited events from the window server.
819     // The first one will cause wxGenericHyperlinkCtrl to call wxWindow::SetCursor which will
820     // invaildate the cursor rect causing Cocoa to schedule cursor rect reset with the run loop
821     // which willl in turn call us before exiting for the next user event.
822
823     // If we are the parent window then rebuilding our tracking rectangle will cause us to miss
824     // our mouse exited event because the already queued event will have the old tracking rect
825     // tag.  The simple solution is to only rebuild our tracking rect if we need to.
826
827     if(m_visibleTrackingRectManager != NULL)
828         m_visibleTrackingRectManager->RebuildTrackingRectIfNeeded();
829
830     if(!m_cursor.GetNSCursor())
831         return false;
832
833     [GetNSView() addCursorRect: [GetNSView() visibleRect]  cursor: m_cursor.GetNSCursor()];
834
835     return true;
836 }
837
838 bool wxWindowCocoa::SetCursor(const wxCursor &cursor)
839 {
840     if(!wxWindowBase::SetCursor(cursor))
841         return false;
842
843     // Set up the cursor rect so that invalidateCursorRectsForView: will destroy it.
844     // If we don't do this then Cocoa thinks (rightly) that we don't have any cursor
845     // rects and thus won't ever call resetCursorRects.
846     [GetNSView() addCursorRect: [GetNSView() visibleRect]  cursor: m_cursor.GetNSCursor()];
847
848     // Invalidate the cursor rects so the cursor will change
849     // Note that it is not enough to remove the old one (if any) and add the new one.
850     // For the rects to work properly, Cocoa itself must call resetCursorRects.
851     [[GetNSView() window] invalidateCursorRectsForView:GetNSView()];
852     return true;
853 }
854
855 bool wxWindowCocoa::Cocoa_viewDidMoveToWindow()
856 {
857     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::viewDidMoveToWindow"),this);
858     // Set up new tracking rects.  I am reasonably sure the new window must be set before doing this.
859     if(m_visibleTrackingRectManager != NULL)
860         m_visibleTrackingRectManager->BuildTrackingRect();
861     return false;
862 }
863
864 bool wxWindowCocoa::Cocoa_viewWillMoveToWindow(WX_NSWindow newWindow)
865 {
866     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::viewWillMoveToWindow:%p"),this, newWindow);
867     // Clear tracking rects.  It is imperative this be done before the new window is set.
868     if(m_visibleTrackingRectManager != NULL)
869         m_visibleTrackingRectManager->ClearTrackingRect();
870     return false;
871 }
872
873 bool wxWindow::Close(bool force)
874 {
875     // The only reason this function exists is that it is virtual and
876     // wxTopLevelWindowCocoa will override it.
877     return wxWindowBase::Close(force);
878 }
879
880 void wxWindow::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
881 {
882     [[oldView superview] replaceSubview:oldView with:newView];
883 }
884
885 void wxWindow::DoEnable(bool enable)
886 {
887         CocoaSetEnabled(enable);
888 }
889
890 bool wxWindow::Show(bool show)
891 {
892     wxAutoNSAutoreleasePool pool;
893     // If the window is marked as visible, then it shouldn't have a dummy view
894     // If the window is marked hidden, then it should have a dummy view
895     // wxSpinCtrl (generic) abuses m_isShown, don't use it for any logic
896 //    wxASSERT_MSG( (m_isShown && !m_dummyNSView) || (!m_isShown && m_dummyNSView),wxT("wxWindow: m_isShown does not agree with m_dummyNSView"));
897     // Return false if there isn't a window to show or hide
898     NSView *cocoaView = GetNSViewForHiding();
899     if(!cocoaView)
900         return false;
901     if(show)
902     {
903         // If state isn't changing, return false
904         if(!m_cocoaHider)
905             return false;
906         CocoaReplaceView(m_cocoaHider->GetNSView(), cocoaView);
907         wxASSERT(![m_cocoaHider->GetNSView() superview]);
908         delete m_cocoaHider;
909         m_cocoaHider = NULL;
910         wxASSERT([cocoaView superview]);
911     }
912     else
913     {
914         // If state isn't changing, return false
915         if(m_cocoaHider)
916             return false;
917         m_cocoaHider = new wxWindowCocoaHider(this);
918         // NOTE: replaceSubview:with will cause m_cocaNSView to be
919         // (auto)released which balances out addSubview
920         CocoaReplaceView(cocoaView, m_cocoaHider->GetNSView());
921         // m_coocaNSView is now only retained by us
922         wxASSERT([m_cocoaHider->GetNSView() superview]);
923         wxASSERT(![cocoaView superview]);
924     }
925     m_isShown = show;
926     return true;
927 }
928
929 void wxWindowCocoa::DoSetSize(int x, int y, int width, int height, int sizeFlags)
930 {
931     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":".");
932     int currentX, currentY;
933     int currentW, currentH;
934     DoGetPosition(&currentX, &currentY);
935     DoGetSize(&currentW, &currentH);
936     if((x==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
937         x=currentX;
938     if((y==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
939         y=currentY;
940
941     AdjustForParentClientOrigin(x,y,sizeFlags);
942
943     wxSize size(wxDefaultSize);
944
945     if((width==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
946     {
947         if(sizeFlags&wxSIZE_AUTO_WIDTH)
948         {
949             size=DoGetBestSize();
950             width=size.x;
951         }
952         else
953             width=currentW;
954     }
955     if((height==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
956     {
957         if(sizeFlags&wxSIZE_AUTO_HEIGHT)
958         {
959             if(size.x==-1)
960                 size=DoGetBestSize();
961             height=size.y;
962         }
963         else
964             height=currentH;
965     }
966     DoMoveWindow(x,y,width,height);
967 }
968
969 #if wxUSE_TOOLTIPS
970
971 void wxWindowCocoa::DoSetToolTip( wxToolTip *tip )
972 {
973     wxWindowBase::DoSetToolTip(tip);
974
975     if ( m_tooltip )
976     {
977         m_tooltip->SetWindow((wxWindow *)this);
978     }
979 }
980
981 #endif
982
983 void wxWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
984 {
985     wxAutoNSAutoreleasePool pool;
986     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoMoveWindow(%d,%d,%d,%d)"),this,x,y,width,height);
987
988     NSView *nsview = GetNSViewForSuperview();
989     NSView *superview = [nsview superview];
990
991     wxCHECK_RET(GetParent(), wxT("Window can only be placed correctly when it has a parent"));
992
993     NSRect oldFrameRect = [nsview frame];
994     NSRect newFrameRect = GetParent()->CocoaTransformWxToBounds(NSMakeRect(x,y,width,height));
995     [nsview setFrame:newFrameRect];
996     // Be sure to redraw the parent to reflect the changed position
997     [superview setNeedsDisplayInRect:oldFrameRect];
998     [superview setNeedsDisplayInRect:newFrameRect];
999 }
1000
1001 void wxWindowCocoa::SetInitialFrameRect(const wxPoint& pos, const wxSize& size)
1002 {
1003     NSView *nsview = GetNSViewForSuperview();
1004     NSView *superview = [nsview superview];
1005     wxCHECK_RET(superview,wxT("NSView does not have a superview"));
1006     wxCHECK_RET(GetParent(), wxT("Window can only be placed correctly when it has a parent"));
1007     NSRect frameRect = [nsview frame];
1008     if(size.x!=-1)
1009         frameRect.size.width = size.x;
1010     if(size.y!=-1)
1011         frameRect.size.height = size.y;
1012     frameRect.origin.x = pos.x;
1013     frameRect.origin.y = pos.y;
1014     // Tell Cocoa to change the margin between the bottom of the superview
1015     // and the bottom of the control.  Keeps the control pinned to the top
1016     // of its superview so that its position in the wxWidgets coordinate
1017     // system doesn't change.
1018     if(![superview isFlipped])
1019         [nsview setAutoresizingMask: NSViewMinYMargin];
1020     // MUST set the mask before setFrame: which can generate a size event
1021     // and cause a scroller to be added!
1022     frameRect = GetParent()->CocoaTransformWxToBounds(frameRect);
1023     [nsview setFrame: frameRect];
1024 }
1025
1026 // Get total size
1027 void wxWindow::DoGetSize(int *w, int *h) const
1028 {
1029     NSRect cocoaRect = [GetNSViewForSuperview() frame];
1030     if(w)
1031         *w=(int)cocoaRect.size.width;
1032     if(h)
1033         *h=(int)cocoaRect.size.height;
1034     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoGetSize = (%d,%d)"),this,(int)cocoaRect.size.width,(int)cocoaRect.size.height);
1035 }
1036
1037 void wxWindow::DoGetPosition(int *x, int *y) const
1038 {
1039     NSView *nsview = GetNSViewForSuperview();
1040
1041     NSRect cocoaRect = [nsview frame];
1042     NSRect rectWx = GetParent()->CocoaTransformBoundsToWx(cocoaRect);
1043     if(x)
1044         *x=(int)rectWx.origin.x;
1045     if(y)
1046         *y=(int)rectWx.origin.y;
1047     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoGetPosition = (%d,%d)"),this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);
1048 }
1049
1050 WXWidget wxWindow::GetHandle() const
1051 {
1052     return m_cocoaNSView;
1053 }
1054
1055 wxWindow* wxWindow::GetWxWindow() const
1056 {
1057     return (wxWindow*) this;
1058 }
1059
1060 void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
1061 {
1062     [m_cocoaNSView setNeedsDisplay:YES];
1063 }
1064
1065 void wxWindow::SetFocus()
1066 {
1067     if([GetNSView() acceptsFirstResponder])
1068         [[GetNSView() window] makeFirstResponder: GetNSView()];
1069 }
1070
1071 void wxWindow::DoCaptureMouse()
1072 {
1073     // TODO
1074     sm_capturedWindow = this;
1075 }
1076
1077 void wxWindow::DoReleaseMouse()
1078 {
1079     // TODO
1080     sm_capturedWindow = NULL;
1081 }
1082
1083 void wxWindow::DoScreenToClient(int *x, int *y) const
1084 {
1085     // Point in cocoa screen coordinates:
1086     NSPoint cocoaScreenPoint = OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x!=NULL?*x:0, y!=NULL?*y:0, 0, 0, false);
1087     NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
1088     NSWindow *theWindow = [clientView window];
1089
1090     // Point in window's base coordinate system:
1091     NSPoint windowPoint = [theWindow convertScreenToBase:cocoaScreenPoint];
1092     // Point in view's bounds coordinate system
1093     NSPoint boundsPoint = [clientView convertPoint:windowPoint fromView:nil];
1094     // Point in wx client coordinates:
1095     NSPoint theWxClientPoint = CocoaTransformNSViewBoundsToWx(clientView, boundsPoint);
1096     if(x!=NULL)
1097         *x = theWxClientPoint.x;
1098     if(y!=NULL)
1099         *y = theWxClientPoint.y;
1100 }
1101
1102 void wxWindow::DoClientToScreen(int *x, int *y) const
1103 {
1104     // Point in wx client coordinates
1105     NSPoint theWxClientPoint = NSMakePoint(x!=NULL?*x:0, y!=NULL?*y:0);
1106
1107     NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
1108
1109     // Point in the view's bounds coordinate system
1110     NSPoint boundsPoint = CocoaTransformNSViewWxToBounds(clientView, theWxClientPoint);
1111
1112     // Point in the window's base coordinate system
1113     NSPoint windowPoint = [clientView convertPoint:boundsPoint toView:nil];
1114
1115     NSWindow *theWindow = [clientView window];
1116     // Point in Cocoa's screen coordinates
1117     NSPoint screenPoint = [theWindow convertBaseToScreen:windowPoint];
1118
1119     // Act as though this was the origin of a 0x0 rectangle
1120     NSRect screenPointRect = NSMakeRect(screenPoint.x, screenPoint.y, 0, 0);
1121
1122     // Convert that rectangle to wx coordinates
1123     wxPoint theWxScreenPoint = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(screenPointRect);
1124     if(*x)
1125         *x = theWxScreenPoint.x;
1126     if(*y)
1127         *y = theWxScreenPoint.y;
1128 }
1129
1130 // Get size *available for subwindows* i.e. excluding menu bar etc.
1131 void wxWindow::DoGetClientSize(int *x, int *y) const
1132 {
1133     wxLogTrace(wxTRACE_COCOA,wxT("DoGetClientSize:"));
1134     if(m_wxCocoaScrollView)
1135         m_wxCocoaScrollView->DoGetClientSize(x,y);
1136     else
1137         wxWindowCocoa::DoGetSize(x,y);
1138 }
1139
1140 void wxWindow::DoSetClientSize(int width, int height)
1141 {
1142     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("DoSetClientSize=(%d,%d)"),width,height);
1143     if(m_wxCocoaScrollView)
1144         m_wxCocoaScrollView->ClientSizeToSize(width,height);
1145     CocoaSetWxWindowSize(width,height);
1146 }
1147
1148 void wxWindow::CocoaSetWxWindowSize(int width, int height)
1149 {
1150     wxWindowCocoa::DoSetSize(wxDefaultCoord,wxDefaultCoord,width,height,wxSIZE_USE_EXISTING);
1151 }
1152
1153 void wxWindow::SetLabel(const wxString& WXUNUSED(label))
1154 {
1155     // Intentional no-op.
1156 }
1157
1158 wxString wxWindow::GetLabel() const
1159 {
1160     // General Get/Set of labels is implemented in wxControlBase
1161     wxLogDebug(wxT("wxWindow::GetLabel: Should be overridden if needed."));
1162     return wxEmptyString;
1163 }
1164
1165 int wxWindow::GetCharHeight() const
1166 {
1167     // TODO
1168     return 10;
1169 }
1170
1171 int wxWindow::GetCharWidth() const
1172 {
1173     // TODO
1174     return 5;
1175 }
1176
1177 void wxWindow::GetTextExtent(const wxString& string, int *outX, int *outY,
1178         int *outDescent, int *outExternalLeading, const wxFont *inFont) const
1179 {
1180     // FIXME: This obviously ignores the window's font (if any) along with any size
1181     // transformations.  However, it's better than nothing.
1182     // We don't create a wxClientDC because we don't want to accidently be able to use
1183     // it for drawing.
1184     wxDC tmpdc;
1185     return tmpdc.GetTextExtent(string, outX, outY, outDescent, outExternalLeading, inFont);
1186 }
1187
1188 // Coordinates relative to the window
1189 void wxWindow::WarpPointer (int x_pos, int y_pos)
1190 {
1191     // TODO
1192 }
1193
1194 int wxWindow::GetScrollPos(int orient) const
1195 {
1196     // TODO
1197     return 0;
1198 }
1199
1200 // This now returns the whole range, not just the number
1201 // of positions that we can scroll.
1202 int wxWindow::GetScrollRange(int orient) const
1203 {
1204     // TODO
1205     return 0;
1206 }
1207
1208 int wxWindow::GetScrollThumb(int orient) const
1209 {
1210     // TODO
1211     return 0;
1212 }
1213
1214 void wxWindow::SetScrollPos(int orient, int pos, bool refresh)
1215 {
1216     // TODO
1217 }
1218
1219 void wxWindow::CocoaCreateNSScrollView()
1220 {
1221     if(!m_wxCocoaScrollView)
1222     {
1223         m_wxCocoaScrollView = new wxWindowCocoaScrollView(this);
1224     }
1225 }
1226
1227 // New function that will replace some of the above.
1228 void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible,
1229     int range, bool refresh)
1230 {
1231     CocoaCreateNSScrollView();
1232     // TODO
1233 }
1234
1235 // Does a physical scroll
1236 void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
1237 {
1238     // TODO
1239 }
1240
1241 static inline int _DoFixupDistance(int vDistance, int cDistance)
1242 {
1243     // If the virtual distance is wxDefaultCoord, set it to the client distance
1244     // This definitely has to be done or else we literally get views with a -1 size component!
1245     if(vDistance == wxDefaultCoord)
1246         vDistance = cDistance;
1247     // NOTE: Since cDistance should always be >= 0 and since wxDefaultCoord is -1, the above
1248     // test is more or less useless because it gets covered by the next one.  However, just in
1249     // case anyone decides that the next test is not correct, I want them to be aware that
1250     // the above test would still be needed.
1251
1252     // I am not entirely sure about this next one but I believe it makes sense because
1253     // otherwise the virtual view (which is the m_cocoaNSView that got wrapped by the scrolling
1254     // machinery) can be smaller than the NSClipView (the client area) which
1255     // means that, for instance, mouse clicks inside the client area as wx sees it but outside
1256     // the virtual area as wx sees it won't be seen by the m_cocoaNSView.
1257     // We make the assumption that if a virtual distance is less than the client distance that
1258     // the real view must already be or will soon be positioned at coordinate 0  within the
1259     // NSClipView that represents the client area.  This way, when we increase the distance to
1260     // be the client distance, the real view will exactly fit in the clip view.
1261     else if(vDistance < cDistance)
1262         vDistance = cDistance;
1263     return vDistance;
1264 }
1265
1266 void wxWindow::DoSetVirtualSize( int x, int y )
1267 {
1268     // Call wxWindowBase method which will set m_virtualSize to the appropriate value,
1269     // possibly not what the caller passed in.  For example, the current implementation
1270     // clamps the width and height to within the min/max virtual ranges.
1271     // wxDefaultCoord is passed through unchanged which means we need to handle it ourselves
1272     // which we do by using the _DoFixupDistance helper method.
1273     wxWindowBase::DoSetVirtualSize(x,y);
1274     // Create the scroll view if it hasn't been already.
1275     CocoaCreateNSScrollView();
1276     // Now use fixed-up distances when setting the frame size
1277     wxSize clientSize = GetClientSize();
1278     [m_cocoaNSView setFrameSize:NSMakeSize(_DoFixupDistance(m_virtualSize.x, clientSize.x), _DoFixupDistance(m_virtualSize.y, clientSize.y))];
1279 }
1280
1281 bool wxWindow::SetFont(const wxFont& font)
1282 {
1283     // FIXME: We may need to handle wx font inheritance.
1284     return wxWindowBase::SetFont(font);
1285 }
1286
1287 #if 0 // these are used when debugging the algorithm.
1288 static char const * const comparisonresultStrings[] =
1289 {   "<"
1290 ,   "=="
1291 ,   ">"
1292 };
1293 #endif
1294
1295 class CocoaWindowCompareContext
1296 {
1297     DECLARE_NO_COPY_CLASS(CocoaWindowCompareContext)
1298 public:
1299     CocoaWindowCompareContext(); // Not implemented
1300     CocoaWindowCompareContext(NSView *target, NSArray *subviews)
1301     {
1302         m_target = target;
1303         // Cocoa sorts subviews in-place.. make a copy
1304         m_subviews = [subviews copy];
1305     }
1306     ~CocoaWindowCompareContext()
1307     {   // release the copy
1308         [m_subviews release];
1309     }
1310     NSView* target()
1311     {   return m_target; }
1312     NSArray* subviews()
1313     {   return m_subviews; }
1314     /* Helper function that returns the comparison based off of the original ordering */
1315     CocoaWindowCompareFunctionResult CompareUsingOriginalOrdering(id first, id second)
1316     {
1317         NSUInteger firstI = [m_subviews indexOfObjectIdenticalTo:first];
1318         NSUInteger secondI = [m_subviews indexOfObjectIdenticalTo:second];
1319         // NOTE: If either firstI or secondI is NSNotFound then it will be NSIntegerMax and thus will
1320         // likely compare higher than the other view which is reasonable considering the only way that
1321         // can happen is if the subview was added after our call to subviews but before the call to
1322         // sortSubviewsUsingFunction:context:.  Thus we don't bother checking.  Particularly because
1323         // that case should never occur anyway because that would imply a multi-threaded GUI call
1324         // which is a big no-no with Cocoa.
1325
1326         // Subviews are ordered from back to front meaning one that is already lower will have an lower index.
1327         NSComparisonResult result = (firstI < secondI)
1328             ?   NSOrderedAscending /* -1 */
1329             :   (firstI > secondI)
1330                 ?   NSOrderedDescending /* 1 */
1331                 :   NSOrderedSame /* 0 */;
1332
1333 #if 0 // Enable this if you need to debug the algorithm.
1334         NSLog(@"%@ [%d] %s %@ [%d]\n", first, firstI, comparisonresultStrings[result+1], second, secondI);
1335 #endif
1336         return result;
1337     }
1338 private:
1339     /* The subview we are trying to Raise or Lower */
1340     NSView *m_target;
1341     /* A copy of the original array of subviews */
1342     NSArray *m_subviews;
1343 };
1344
1345 /* Causes Cocoa to raise the target view to the top of the Z-Order by telling the sort function that
1346  * the target view is always higher than every other view.  When comparing two views neither of
1347  * which is the target, it returns the correct response based on the original ordering
1348  */
1349 static CocoaWindowCompareFunctionResult CocoaRaiseWindowCompareFunction(id first, id second, void *ctx)
1350 {
1351     CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
1352     // first should be ordered higher
1353     if(first==compareContext->target())
1354         return NSOrderedDescending;
1355     // second should be ordered higher
1356     if(second==compareContext->target())
1357         return NSOrderedAscending;
1358     return compareContext->CompareUsingOriginalOrdering(first,second);
1359 }
1360
1361 // Raise the window to the top of the Z order
1362 void wxWindow::Raise()
1363 {
1364 //    wxAutoNSAutoreleasePool pool;
1365     NSView *nsview = GetNSViewForSuperview();
1366     NSView *superview = [nsview superview];
1367     CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1368
1369     [superview sortSubviewsUsingFunction:
1370             CocoaRaiseWindowCompareFunction
1371         context: &compareContext];
1372 }
1373
1374 /* Causes Cocoa to lower the target view to the bottom of the Z-Order by telling the sort function that
1375  * the target view is always lower than every other view.  When comparing two views neither of
1376  * which is the target, it returns the correct response based on the original ordering
1377  */
1378 static CocoaWindowCompareFunctionResult CocoaLowerWindowCompareFunction(id first, id second, void *ctx)
1379 {
1380     CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
1381     // first should be ordered lower
1382     if(first==compareContext->target())
1383         return NSOrderedAscending;
1384     // second should be ordered lower
1385     if(second==compareContext->target())
1386         return NSOrderedDescending;
1387     return compareContext->CompareUsingOriginalOrdering(first,second);
1388 }
1389
1390 // Lower the window to the bottom of the Z order
1391 void wxWindow::Lower()
1392 {
1393     NSView *nsview = GetNSViewForSuperview();
1394     NSView *superview = [nsview superview];
1395     CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1396
1397 #if 0
1398     NSLog(@"Target:\n%@\n", nsview);
1399     NSLog(@"Before:\n%@\n", compareContext.subviews());
1400 #endif
1401     [superview sortSubviewsUsingFunction:
1402             CocoaLowerWindowCompareFunction
1403         context: &compareContext];
1404 #if 0
1405     NSLog(@"After:\n%@\n", [superview subviews]);
1406 #endif
1407 }
1408
1409 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
1410 {
1411     return false;
1412 }
1413
1414 // Get the window with the focus
1415 wxWindow *wxWindowBase::DoFindFocus()
1416 {
1417     // Basically we are somewhat emulating the responder chain here except
1418     // we are only loking for the first responder in the key window or
1419     // upon failing to find one if the main window is different we look
1420     // for the first responder in the main window.
1421
1422     // Note that the firstResponder doesn't necessarily have to be an
1423     // NSView but wxCocoaNSView::GetFromCocoa() will simply return
1424     // NULL unless it finds its argument in its hash map.
1425
1426     wxCocoaNSView *win;
1427
1428     NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
1429     win = wxCocoaNSView::GetFromCocoa(static_cast<NSView*>([keyWindow firstResponder]));
1430     if(win)
1431         return win->GetWxWindow();
1432
1433     NSWindow *mainWindow = [[NSApplication sharedApplication] keyWindow];
1434     if(mainWindow == keyWindow)
1435         return NULL;
1436     win = wxCocoaNSView::GetFromCocoa(static_cast<NSView*>([mainWindow firstResponder]));
1437     if(win)
1438         return win->GetWxWindow();
1439
1440     return NULL;
1441 }
1442
1443 /* static */ wxWindow *wxWindowBase::GetCapture()
1444 {
1445     // TODO
1446     return wxWindowCocoa::sm_capturedWindow;
1447 }
1448
1449 wxWindow *wxGetActiveWindow()
1450 {
1451     // TODO
1452     return NULL;
1453 }
1454
1455 wxPoint wxGetMousePosition()
1456 {
1457     // TODO
1458     return wxDefaultPosition;
1459 }
1460
1461 wxMouseState wxGetMouseState()
1462 {
1463     wxMouseState ms;
1464     // TODO
1465     return ms;
1466 }
1467
1468 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1469 {
1470     pt = wxGetMousePosition();
1471     return NULL;
1472 }
1473
1474 // ========================================================================
1475 // wxCocoaMouseMovedEventSynthesizer
1476 // ========================================================================
1477
1478 #define wxTRACE_COCOA_MouseMovedSynthesizer wxT("COCOA_MouseMovedSynthesizer")
1479
1480 /* This class registers one run loop observer to cover all windows registered with it.
1481  *  It will register the observer when the first view is registerd and unregister the
1482  * observer when the last view is unregistered.
1483  * It is instantiated as a static s_mouseMovedSynthesizer in this file although there
1484  * is no reason it couldn't be instantiated multiple times.
1485  */
1486 class wxCocoaMouseMovedEventSynthesizer
1487 {
1488     DECLARE_NO_COPY_CLASS(wxCocoaMouseMovedEventSynthesizer)
1489 public:
1490     wxCocoaMouseMovedEventSynthesizer()
1491     {   m_lastScreenMouseLocation = NSZeroPoint;
1492     }
1493     ~wxCocoaMouseMovedEventSynthesizer();
1494     void RegisterWxCocoaView(wxCocoaNSView *aView);
1495     void UnregisterWxCocoaView(wxCocoaNSView *aView);
1496     void SynthesizeMouseMovedEvent();
1497     
1498 protected:
1499     void AddRunLoopObserver();
1500     void RemoveRunLoopObserver();
1501     wxCFRef<CFRunLoopObserverRef> m_runLoopObserver;
1502     std::list<wxCocoaNSView*> m_registeredViews;
1503     NSPoint m_lastScreenMouseLocation;
1504     static void SynthesizeMouseMovedEvent(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
1505 };
1506
1507 void wxCocoaMouseMovedEventSynthesizer::RegisterWxCocoaView(wxCocoaNSView *aView)
1508 {
1509     m_registeredViews.push_back(aView);
1510     wxLogTrace(wxTRACE_COCOA_MouseMovedSynthesizer, wxT("Registered wxCocoaNSView=%p"), aView);
1511
1512     if(!m_registeredViews.empty() && m_runLoopObserver == NULL)
1513     {
1514         AddRunLoopObserver();
1515     }
1516 }
1517
1518 void wxCocoaMouseMovedEventSynthesizer::UnregisterWxCocoaView(wxCocoaNSView *aView)
1519 {
1520     m_registeredViews.remove(aView);
1521     wxLogTrace(wxTRACE_COCOA_MouseMovedSynthesizer, wxT("Unregistered wxCocoaNSView=%p"), aView);
1522     if(m_registeredViews.empty() && m_runLoopObserver != NULL)
1523     {
1524         RemoveRunLoopObserver();
1525     }
1526 }
1527
1528 wxCocoaMouseMovedEventSynthesizer::~wxCocoaMouseMovedEventSynthesizer()
1529 {
1530     if(!m_registeredViews.empty())
1531     {
1532         // This means failure to clean up so we report on it as a debug message.
1533         wxLogDebug(wxT("There are still %d wxCocoaNSView registered to receive mouse moved events at static destruction time"), m_registeredViews.size());
1534         m_registeredViews.clear();
1535     }
1536     if(m_runLoopObserver != NULL)
1537     {
1538         // This should not occur unless m_registeredViews was not empty since the last object unregistered should have done this.
1539         wxLogDebug(wxT("Removing run loop observer during static destruction time."));
1540         RemoveRunLoopObserver();
1541     }
1542 }
1543
1544 void wxCocoaMouseMovedEventSynthesizer::SynthesizeMouseMovedEvent(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
1545 {
1546     reinterpret_cast<wxCocoaMouseMovedEventSynthesizer*>(info)->SynthesizeMouseMovedEvent();
1547 }
1548
1549 void wxCocoaMouseMovedEventSynthesizer::AddRunLoopObserver()
1550 {
1551     CFRunLoopObserverContext observerContext =
1552     {   0
1553     ,   this
1554     ,   NULL
1555     ,   NULL
1556     ,   NULL
1557     };
1558
1559     // The kCFRunLoopExit observation point is used such that we hook the run loop after it has already decided that
1560     // it is going to exit which is generally for the purpose of letting the event loop process the next Cocoa event.
1561
1562     // Executing our procedure within the run loop (e.g. kCFRunLoopBeforeWaiting which was used before) results
1563     // in our observer procedure being called before the run loop has decided that it is going to return control to
1564     // the Cocoa event loop.  One major problem is uncovered by the wxGenericHyperlinkCtrl (consider this to be "user
1565     // code") which changes the window's cursor and thus causes the cursor rectangle's to be invalidated.
1566
1567     // Cocoa implements this invalidation using a delayed notification scheme whereby the resetCursorRects method
1568     // won't be called until the CFRunLoop gets around to it.  If the CFRunLoop has not yet exited then it will get
1569     // around to it before letting the event loop do its work.  This has some very odd effects on the way the
1570     // newly created tracking rects function.  In particular, we will often miss the mouseExited: message if the
1571     // user flicks the mouse quickly enough such that the mouse is already outside of the tracking rect by the
1572     // time the new one is built.
1573
1574     // Observing from the kCFRunLoopExit point gives Cocoa's event loop an opportunity to chew some events before it cedes
1575     // control back to the CFRunLoop, thus causing the delayed notifications to fire at an appropriate time and
1576     // the mouseExited: message to be sent properly.
1577
1578     m_runLoopObserver.reset(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopExit, TRUE, 0, SynthesizeMouseMovedEvent, &observerContext));
1579     CFRunLoopAddObserver([[NSRunLoop currentRunLoop] getCFRunLoop], m_runLoopObserver, kCFRunLoopCommonModes);
1580     wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Added tracking rect run loop observer"));
1581 }
1582
1583 void wxCocoaMouseMovedEventSynthesizer::RemoveRunLoopObserver()
1584 {
1585     CFRunLoopRemoveObserver([[NSRunLoop currentRunLoop] getCFRunLoop], m_runLoopObserver, kCFRunLoopCommonModes);
1586     m_runLoopObserver.reset();
1587     wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Removed tracking rect run loop observer"));
1588 }
1589
1590 void wxCocoaMouseMovedEventSynthesizer::SynthesizeMouseMovedEvent()
1591 {
1592     NSPoint screenMouseLocation = [NSEvent mouseLocation];
1593     // Checking the last mouse location is done for a few reasons:
1594     // 1. We are observing every iteration of the event loop so we'd be sending out a lot of extraneous events
1595     //    telling the app the mouse moved when the user hit a key for instance.
1596     // 2. When handling the mouse moved event, user code can do something to the view which will cause Cocoa to
1597     //    call resetCursorRects.  Cocoa does this by using a delayed notification which means the event loop gets
1598     //    pumped once which would mean that if we didn't check the mouse location we'd get into a never-ending
1599     //    loop causing the tracking rectangles to constantly be reset.
1600     if(screenMouseLocation.x != m_lastScreenMouseLocation.x || screenMouseLocation.y != m_lastScreenMouseLocation.y)
1601     {
1602         m_lastScreenMouseLocation = screenMouseLocation;
1603         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Synthesizing mouse moved at screen (%f,%f)"), screenMouseLocation.x, screenMouseLocation.y);
1604         for(std::list<wxCocoaNSView*>::iterator i = m_registeredViews.begin(); i != m_registeredViews.end(); ++i)
1605         {
1606             (*i)->Cocoa_synthesizeMouseMoved();
1607         }
1608     }
1609 }
1610
1611 // Singleton used for all views:
1612 static wxCocoaMouseMovedEventSynthesizer s_mouseMovedSynthesizer;
1613
1614 // ========================================================================
1615 // wxCocoaTrackingRectManager
1616 // ========================================================================
1617
1618 wxCocoaTrackingRectManager::wxCocoaTrackingRectManager(wxWindow *window)
1619 :   m_window(window)
1620 {
1621     m_isTrackingRectActive = false;
1622     BuildTrackingRect();
1623 }
1624
1625 void wxCocoaTrackingRectManager::ClearTrackingRect()
1626 {
1627     if(m_isTrackingRectActive)
1628     {
1629         [m_window->GetNSView() removeTrackingRect:m_trackingRectTag];
1630         m_isTrackingRectActive = false;
1631         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("%s@%p: Removed tracking rect #%d"), m_window->GetClassInfo()->GetClassName(), m_window, m_trackingRectTag);
1632     }
1633     // If we were doing periodic events we need to clear those too
1634     StopSynthesizingEvents();
1635 }
1636
1637 void wxCocoaTrackingRectManager::StopSynthesizingEvents()
1638 {
1639     s_mouseMovedSynthesizer.UnregisterWxCocoaView(m_window);
1640 }
1641
1642 void wxCocoaTrackingRectManager::BuildTrackingRect()
1643 {
1644     // Pool here due to lack of one during wx init phase
1645     wxAutoNSAutoreleasePool pool;
1646
1647     wxASSERT_MSG(!m_isTrackingRectActive, wxT("Tracking rect was not cleared"));
1648
1649     NSView *theView = m_window->GetNSView();
1650
1651     if([theView window] != nil)
1652     {
1653         NSRect visibleRect = [theView visibleRect];
1654
1655         m_trackingRectTag = [theView addTrackingRect:visibleRect owner:theView userData:NULL assumeInside:NO];
1656         m_trackingRectInWindowCoordinates = [theView convertRect:visibleRect toView:nil];
1657         m_isTrackingRectActive = true;
1658
1659         wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("%s@%p: Added tracking rect #%d"), m_window->GetClassInfo()->GetClassName(), m_window, m_trackingRectTag);
1660     }
1661 }
1662
1663 void wxCocoaTrackingRectManager::BeginSynthesizingEvents()
1664 {
1665     s_mouseMovedSynthesizer.RegisterWxCocoaView(m_window);
1666 }
1667
1668 void wxCocoaTrackingRectManager::RebuildTrackingRectIfNeeded()
1669 {
1670     if(m_isTrackingRectActive)
1671     {
1672         NSView *theView = m_window->GetNSView();
1673         NSRect currentRect = [theView convertRect:[theView visibleRect] toView:nil];
1674         if(NSEqualRects(m_trackingRectInWindowCoordinates,currentRect))
1675         {
1676             wxLogTrace(wxTRACE_COCOA_TrackingRect, wxT("Ignored request to rebuild TR#%d"), m_trackingRectTag);
1677             return;
1678         }
1679     }
1680     RebuildTrackingRect();
1681 }
1682
1683 void wxCocoaTrackingRectManager::RebuildTrackingRect()
1684 {
1685     ClearTrackingRect();
1686     BuildTrackingRect();
1687 }
1688
1689 wxCocoaTrackingRectManager::~wxCocoaTrackingRectManager()
1690 {
1691     ClearTrackingRect();
1692 }
1693
1694 bool wxCocoaTrackingRectManager::IsOwnerOfEvent(NSEvent *anEvent)
1695 {
1696     return m_isTrackingRectActive && (m_trackingRectTag == [anEvent trackingNumber]);
1697 }
1698