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