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