2.5.3 - cleanups, fixes, etc. etc. -
[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 #ifndef WX_PRECOMP
14     #include "wx/log.h"
15     #include "wx/tooltip.h"
16     #include "wx/window.h"
17 #endif //WX_PRECOMP
18
19 #include "wx/cocoa/autorelease.h"
20 #include "wx/cocoa/string.h"
21
22 #import <AppKit/NSView.h>
23 #import <AppKit/NSEvent.h>
24 #import <AppKit/NSScrollView.h>
25 #import <AppKit/NSColor.h>
26 #import <AppKit/NSClipView.h>
27 #import <Foundation/NSException.h>
28 #import <Foundation/NSString.h>
29
30 #include <objc/objc-runtime.h>
31
32 // Turn this on to paint green over the dummy views for debugging
33 #undef WXCOCOA_FILL_DUMMY_VIEW
34
35 #ifdef WXCOCOA_FILL_DUMMY_VIEW
36 #import <AppKit/NSBezierPath.h>
37 #endif //def WXCOCOA_FILL_DUMMY_VIEW
38
39 // ========================================================================
40 // wxWindowCocoaHider
41 // ========================================================================
42 class wxWindowCocoaHider: protected wxCocoaNSView
43 {
44     DECLARE_NO_COPY_CLASS(wxWindowCocoaHider)
45 public:
46     wxWindowCocoaHider(wxWindow *owner);
47     virtual ~wxWindowCocoaHider();
48     inline WX_NSView GetNSView() { return m_dummyNSView; }
49 protected:
50     wxWindowCocoa *m_owner;
51     WX_NSView m_dummyNSView;
52     virtual void Cocoa_FrameChanged(void);
53 #ifdef WXCOCOA_FILL_DUMMY_VIEW
54     virtual bool Cocoa_drawRect(const NSRect& rect);
55 #endif //def WXCOCOA_FILL_DUMMY_VIEW
56 private:
57     wxWindowCocoaHider();
58 };
59
60 // ========================================================================
61 // wxWindowCocoaScroller
62 // ========================================================================
63 class wxWindowCocoaScroller: protected wxCocoaNSView
64 {
65     DECLARE_NO_COPY_CLASS(wxWindowCocoaScroller)
66 public:
67     wxWindowCocoaScroller(wxWindow *owner);
68     virtual ~wxWindowCocoaScroller();
69     inline WX_NSScrollView GetNSScrollView() { return m_cocoaNSScrollView; }
70     void ClientSizeToSize(int &width, int &height);
71     void DoGetClientSize(int *x, int *y) const;
72     void Encapsulate();
73     void Unencapsulate();
74 protected:
75     wxWindowCocoa *m_owner;
76     WX_NSScrollView m_cocoaNSScrollView;
77     virtual void Cocoa_FrameChanged(void);
78 private:
79     wxWindowCocoaScroller();
80 };
81
82 // ========================================================================
83 // wxDummyNSView
84 // ========================================================================
85 @interface wxDummyNSView : NSView
86 - (NSView *)hitTest:(NSPoint)aPoint;
87 @end
88
89 @implementation wxDummyNSView : NSView
90 - (NSView *)hitTest:(NSPoint)aPoint
91 {
92     return nil;
93 }
94
95 @end
96
97 // ========================================================================
98 // wxWindowCocoaHider
99 // ========================================================================
100 wxWindowCocoaHider::wxWindowCocoaHider(wxWindow *owner)
101 :   m_owner(owner)
102 {
103     wxASSERT(owner);
104     wxASSERT(owner->GetNSViewForHiding());
105     m_dummyNSView = [[wxDummyNSView alloc]
106         initWithFrame:[owner->GetNSViewForHiding() frame]];
107     [m_dummyNSView setAutoresizingMask: [owner->GetNSViewForHiding() autoresizingMask]];
108     AssociateNSView(m_dummyNSView);
109 }
110
111 wxWindowCocoaHider::~wxWindowCocoaHider()
112 {
113     DisassociateNSView(m_dummyNSView);
114     [m_dummyNSView release];
115 }
116
117 void wxWindowCocoaHider::Cocoa_FrameChanged(void)
118 {
119     // Keep the real window in synch with the dummy
120     wxASSERT(m_dummyNSView);
121     [m_owner->GetNSViewForHiding() setFrame:[m_dummyNSView frame]];
122 }
123
124
125 #ifdef WXCOCOA_FILL_DUMMY_VIEW
126 bool wxWindowCocoaHider::Cocoa_drawRect(const NSRect& rect)
127 {
128     NSBezierPath *bezpath = [NSBezierPath bezierPathWithRect:rect];
129     [[NSColor greenColor] set];
130     [bezpath stroke];
131     [bezpath fill];
132     return true;
133 }
134 #endif //def WXCOCOA_FILL_DUMMY_VIEW
135
136 // ========================================================================
137 // wxFlippedNSClipView
138 // ========================================================================
139 @interface wxFlippedNSClipView : NSClipView
140 - (BOOL)isFlipped;
141 @end
142
143 @implementation wxFlippedNSClipView : NSClipView
144 - (BOOL)isFlipped
145 {
146     return YES;
147 }
148
149 @end
150
151 // ========================================================================
152 // wxWindowCocoaScroller
153 // ========================================================================
154 wxWindowCocoaScroller::wxWindowCocoaScroller(wxWindow *owner)
155 :   m_owner(owner)
156 {
157     wxAutoNSAutoreleasePool pool;
158     wxASSERT(owner);
159     wxASSERT(owner->GetNSView());
160     m_cocoaNSScrollView = [[NSScrollView alloc]
161         initWithFrame:[owner->GetNSView() frame]];
162     AssociateNSView(m_cocoaNSScrollView);
163
164     /* Replace the default NSClipView with a flipped one.  This ensures
165        scrolling is "pinned" to the top-left instead of bottom-right. */
166     NSClipView *flippedClip = [[wxFlippedNSClipView alloc]
167         initWithFrame: [[m_cocoaNSScrollView contentView] frame]];
168     [m_cocoaNSScrollView setContentView:flippedClip];
169     [flippedClip release];
170
171     [m_cocoaNSScrollView setBackgroundColor: [NSColor windowBackgroundColor]];
172     [m_cocoaNSScrollView setHasHorizontalScroller: YES];
173     [m_cocoaNSScrollView setHasVerticalScroller: YES];
174     Encapsulate();
175 }
176
177 void wxWindowCocoaScroller::Encapsulate()
178 {
179     // Set the scroll view autoresizingMask to match the current NSView
180     [m_cocoaNSScrollView setAutoresizingMask: [m_owner->GetNSView() autoresizingMask]];
181     [m_owner->GetNSView() setAutoresizingMask: NSViewNotSizable];
182     // NOTE: replaceSubView will cause m_cocaNSView to be released
183     // except when it hasn't been added into an NSView hierarchy in which
184     // case it doesn't need to be and this should work out to a no-op
185     m_owner->CocoaReplaceView(m_owner->GetNSView(), m_cocoaNSScrollView);
186     // The NSView is still retained by owner
187     [m_cocoaNSScrollView setDocumentView: m_owner->GetNSView()];
188     // Now it's also retained by the NSScrollView
189 }
190
191 void wxWindowCocoaScroller::Unencapsulate()
192 {
193     [m_cocoaNSScrollView setDocumentView: nil];
194     m_owner->CocoaReplaceView(m_cocoaNSScrollView, m_owner->GetNSView());
195     if(![[m_owner->GetNSView() superview] isFlipped])
196         [m_owner->GetNSView() setAutoresizingMask: NSViewMinYMargin];
197 }
198
199 wxWindowCocoaScroller::~wxWindowCocoaScroller()
200 {
201     DisassociateNSView(m_cocoaNSScrollView);
202     [m_cocoaNSScrollView release];
203 }
204
205 void wxWindowCocoaScroller::ClientSizeToSize(int &width, int &height)
206 {
207     NSSize frameSize = [NSScrollView
208         frameSizeForContentSize: NSMakeSize(width,height)
209         hasHorizontalScroller: [m_cocoaNSScrollView hasHorizontalScroller]
210         hasVerticalScroller: [m_cocoaNSScrollView hasVerticalScroller]
211         borderType: [m_cocoaNSScrollView borderType]];
212     width = (int)frameSize.width;
213     height = (int)frameSize.height;
214 }
215
216 void wxWindowCocoaScroller::DoGetClientSize(int *x, int *y) const
217 {
218     NSSize nssize = [m_cocoaNSScrollView contentSize];
219     if(x)
220         *x = (int)nssize.width;
221     if(y)
222         *y = (int)nssize.height;
223 }
224
225 void wxWindowCocoaScroller::Cocoa_FrameChanged(void)
226 {
227     wxLogTrace(wxTRACE_COCOA,wxT("Cocoa_FrameChanged"));
228     wxSizeEvent event(m_owner->GetSize(), m_owner->GetId());
229     event.SetEventObject(m_owner);
230     m_owner->GetEventHandler()->ProcessEvent(event);
231 }
232
233 // ========================================================================
234 // wxWindowCocoa
235 // ========================================================================
236 // normally the base classes aren't included, but wxWindow is special
237 #ifdef __WXUNIVERSAL__
238 IMPLEMENT_ABSTRACT_CLASS(wxWindowCocoa, wxWindowBase)
239 #else
240 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
241 #endif
242
243 BEGIN_EVENT_TABLE(wxWindowCocoa, wxWindowBase)
244 END_EVENT_TABLE()
245
246 wxWindow *wxWindowCocoa::sm_capturedWindow = NULL;
247
248 // Constructor
249 void wxWindowCocoa::Init()
250 {
251     m_cocoaNSView = NULL;
252     m_cocoaHider = NULL;
253     m_cocoaScroller = NULL;
254     m_isBeingDeleted = FALSE;
255     m_isInPaint = FALSE;
256     m_shouldBeEnabled = true;
257 }
258
259 // Constructor
260 bool wxWindow::Create(wxWindow *parent, wxWindowID winid,
261            const wxPoint& pos,
262            const wxSize& size,
263            long style,
264            const wxString& name)
265 {
266     if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
267         return false;
268
269     // TODO: create the window
270     m_cocoaNSView = NULL;
271     SetNSView([[NSView alloc] initWithFrame: MakeDefaultNSRect(size)]);
272     [m_cocoaNSView release];
273
274     if (m_parent)
275     {
276         m_parent->AddChild(this);
277         m_parent->CocoaAddChild(this);
278         SetInitialFrameRect(pos,size);
279     }
280
281     return TRUE;
282 }
283
284 // Destructor
285 wxWindow::~wxWindow()
286 {
287     wxAutoNSAutoreleasePool pool;
288     DestroyChildren();
289
290     // Make sure our parent (in the wxWidgets sense) is our superview
291     // before we go removing from it.
292     if(m_parent && m_parent->GetNSView()==[GetNSViewForSuperview() superview])
293         CocoaRemoveFromParent();
294     delete m_cocoaHider;
295     delete m_cocoaScroller;
296     if(m_cocoaNSView)
297         SendDestroyEvent();
298     SetNSView(NULL);
299 }
300
301 void wxWindowCocoa::CocoaAddChild(wxWindowCocoa *child)
302 {
303     NSView *childView = child->GetNSViewForSuperview();
304
305     wxASSERT(childView);
306     [m_cocoaNSView addSubview: childView];
307     child->m_isShown = !m_cocoaHider;
308 }
309
310 void wxWindowCocoa::CocoaRemoveFromParent(void)
311 {
312     [GetNSViewForSuperview() removeFromSuperview];
313 }
314
315 void wxWindowCocoa::SetNSView(WX_NSView cocoaNSView)
316 {
317     bool need_debug = cocoaNSView || m_cocoaNSView;
318     if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [m_cocoaNSView=%p retainCount]=%d"),this,m_cocoaNSView,[m_cocoaNSView retainCount]);
319     DisassociateNSView(m_cocoaNSView);
320     [cocoaNSView retain];
321     [m_cocoaNSView release];
322     m_cocoaNSView = cocoaNSView;
323     AssociateNSView(m_cocoaNSView);
324     if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [cocoaNSView=%p retainCount]=%d"),this,cocoaNSView,[cocoaNSView retainCount]);
325 }
326
327 WX_NSView wxWindowCocoa::GetNSViewForSuperview() const
328 {
329     return m_cocoaHider
330         ?   m_cocoaHider->GetNSView()
331         :   m_cocoaScroller
332             ?   m_cocoaScroller->GetNSScrollView()
333             :   m_cocoaNSView;
334 }
335
336 WX_NSView wxWindowCocoa::GetNSViewForHiding() const
337 {
338     return m_cocoaScroller
339         ?   m_cocoaScroller->GetNSScrollView()
340         :   m_cocoaNSView;
341 }
342
343 bool wxWindowCocoa::Cocoa_drawRect(const NSRect &rect)
344 {
345     wxLogTrace(wxTRACE_COCOA,wxT("Cocoa_drawRect"));
346     // Recursion can happen if the event loop runs from within the paint
347     // handler.  For instance, if an assertion dialog is shown.
348     // FIXME: This seems less than ideal.
349     if(m_isInPaint)
350     {
351         wxLogDebug(wxT("Paint event recursion!"));
352         return false;
353     }
354     m_isInPaint = TRUE;
355
356     // Set m_updateRegion
357     const NSRect *rects = &rect; // The bounding box of the region
358     int countRects = 1;
359     // Try replacing the larger rectangle with a list of smaller ones:
360 NS_DURING
361     //getRectsBeingDrawn:count: is a optimization that is only available on
362     //Panthar (10.3) and higher.  Check to see if it supports it -
363     if ( [GetNSView() respondsToSelector:@selector(getRectsBeingDrawn:count:)] )    objc_msgSend(GetNSView(),@selector(getRectsBeingDrawn:count:),&rects,&countRects);
364 NS_HANDLER
365 NS_ENDHANDLER
366     m_updateRegion = wxRegion(rects,countRects);
367
368     wxPaintEvent event(m_windowId);
369     event.SetEventObject(this);
370     bool ret = GetEventHandler()->ProcessEvent(event);
371     m_isInPaint = FALSE;
372     return ret;
373 }
374
375 void wxWindowCocoa::InitMouseEvent(wxMouseEvent& event, WX_NSEvent cocoaEvent)
376 {
377     wxASSERT_MSG([m_cocoaNSView window]==[cocoaEvent window],wxT("Mouse event for different NSWindow"));
378     NSPoint cocoaPoint = [m_cocoaNSView convertPoint:[(NSEvent*)cocoaEvent locationInWindow] fromView:nil];
379     NSRect cocoaRect = [m_cocoaNSView frame];
380     const wxPoint &clientorigin = GetClientAreaOrigin();
381     event.m_x = (wxCoord)cocoaPoint.x - clientorigin.x;
382     event.m_y = (wxCoord)(cocoaRect.size.height - cocoaPoint.y) - clientorigin.y;
383
384     event.m_shiftDown = [cocoaEvent modifierFlags] & NSShiftKeyMask;
385     event.m_controlDown = [cocoaEvent modifierFlags] & NSControlKeyMask;
386     event.m_altDown = [cocoaEvent modifierFlags] & NSAlternateKeyMask;
387     event.m_metaDown = [cocoaEvent modifierFlags] & NSCommandKeyMask;
388
389     // TODO: set timestamp?
390     event.SetEventObject(this);
391     event.SetId(GetId());
392 }
393
394 bool wxWindowCocoa::Cocoa_mouseMoved(WX_NSEvent theEvent)
395 {
396     wxMouseEvent event(wxEVT_MOTION);
397     InitMouseEvent(event,theEvent);
398     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
399     return GetEventHandler()->ProcessEvent(event);
400 }
401
402 bool wxWindowCocoa::Cocoa_mouseEntered(WX_NSEvent theEvent)
403 {
404     return false;
405 }
406
407 bool wxWindowCocoa::Cocoa_mouseExited(WX_NSEvent theEvent)
408 {
409     return false;
410 }
411
412 bool wxWindowCocoa::Cocoa_mouseDown(WX_NSEvent theEvent)
413 {
414     wxMouseEvent event([theEvent clickCount]<2?wxEVT_LEFT_DOWN:wxEVT_LEFT_DCLICK);
415     InitMouseEvent(event,theEvent);
416     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]);
417     return GetEventHandler()->ProcessEvent(event);
418 }
419
420 bool wxWindowCocoa::Cocoa_mouseDragged(WX_NSEvent theEvent)
421 {
422     wxMouseEvent event(wxEVT_MOTION);
423     InitMouseEvent(event,theEvent);
424     event.m_leftDown = true;
425     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
426     return GetEventHandler()->ProcessEvent(event);
427 }
428
429 bool wxWindowCocoa::Cocoa_mouseUp(WX_NSEvent theEvent)
430 {
431     wxMouseEvent event(wxEVT_LEFT_UP);
432     InitMouseEvent(event,theEvent);
433     wxLogTrace(wxTRACE_COCOA,wxT("Mouse Up @%d,%d"),event.m_x,event.m_y);
434     return GetEventHandler()->ProcessEvent(event);
435 }
436
437 bool wxWindowCocoa::Cocoa_rightMouseDown(WX_NSEvent theEvent)
438 {
439     wxMouseEvent event([theEvent clickCount]<2?wxEVT_RIGHT_DOWN:wxEVT_RIGHT_DCLICK);
440     InitMouseEvent(event,theEvent);
441     wxLogDebug(wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]);
442     return GetEventHandler()->ProcessEvent(event);
443 }
444
445 bool wxWindowCocoa::Cocoa_rightMouseDragged(WX_NSEvent theEvent)
446 {
447     wxMouseEvent event(wxEVT_MOTION);
448     InitMouseEvent(event,theEvent);
449     event.m_rightDown = true;
450     wxLogDebug(wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y);
451     return GetEventHandler()->ProcessEvent(event);
452 }
453
454 bool wxWindowCocoa::Cocoa_rightMouseUp(WX_NSEvent theEvent)
455 {
456     wxMouseEvent event(wxEVT_RIGHT_UP);
457     InitMouseEvent(event,theEvent);
458     wxLogDebug(wxT("Mouse Up @%d,%d"),event.m_x,event.m_y);
459     return GetEventHandler()->ProcessEvent(event);
460 }
461
462 bool wxWindowCocoa::Cocoa_otherMouseDown(WX_NSEvent theEvent)
463 {
464     return false;
465 }
466
467 bool wxWindowCocoa::Cocoa_otherMouseDragged(WX_NSEvent theEvent)
468 {
469     return false;
470 }
471
472 bool wxWindowCocoa::Cocoa_otherMouseUp(WX_NSEvent theEvent)
473 {
474     return false;
475 }
476
477 void wxWindowCocoa::Cocoa_FrameChanged(void)
478 {
479     wxLogTrace(wxTRACE_COCOA,wxT("Cocoa_FrameChanged"));
480     wxSizeEvent event(GetSize(), m_windowId);
481     event.SetEventObject(this);
482     GetEventHandler()->ProcessEvent(event);
483 }
484
485 bool wxWindowCocoa::Cocoa_resetCursorRects()
486 {
487     if(!m_cursor.GetNSCursor())
488         return false;
489     
490     [GetNSView() addCursorRect: [GetNSView() visibleRect]  cursor: m_cursor.GetNSCursor()];    
491         
492     return true;
493 }
494
495 bool wxWindow::Close(bool force)
496 {
497     // The only reason this function exists is that it is virtual and
498     // wxTopLevelWindowCocoa will override it.
499     return wxWindowBase::Close(force);
500 }
501
502 void wxWindow::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
503 {
504     [[oldView superview] replaceSubview:oldView with:newView];
505 }
506
507 bool wxWindow::EnableSelfAndChildren(bool enable)
508 {
509     // If the state isn't changing, don't do anything
510     if(!wxWindowBase::Enable(enable && m_shouldBeEnabled))
511         return false;
512     // Set the state of the Cocoa window
513     CocoaSetEnabled(m_isEnabled);
514     // Disable all children or (if enabling) return them to their proper state
515     for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
516         node; node = node->GetNext())
517     {
518         node->GetData()->EnableSelfAndChildren(enable);
519     }
520     return true;
521 }
522
523 bool wxWindow::Enable(bool enable)
524 {
525     // Keep track of what the window SHOULD be doing
526     m_shouldBeEnabled = enable;
527     // If the parent is disabled for any reason, then this window will be too.
528     if(!IsTopLevel() && GetParent())
529     {
530         enable = enable && GetParent()->IsEnabled();
531     }
532     return EnableSelfAndChildren(enable);
533 }
534
535 bool wxWindow::Show(bool show)
536 {
537     wxAutoNSAutoreleasePool pool;
538     // If the window is marked as visible, then it shouldn't have a dummy view
539     // If the window is marked hidden, then it should have a dummy view
540     // wxSpinCtrl (generic) abuses m_isShown, don't use it for any logic
541 //    wxASSERT_MSG( (m_isShown && !m_dummyNSView) || (!m_isShown && m_dummyNSView),wxT("wxWindow: m_isShown does not agree with m_dummyNSView"));
542     // Return false if there isn't a window to show or hide
543     NSView *cocoaView = GetNSViewForHiding();
544     if(!cocoaView)
545         return false;
546     if(show)
547     {
548         // If state isn't changing, return false
549         if(!m_cocoaHider)
550             return false;
551         CocoaReplaceView(m_cocoaHider->GetNSView(), cocoaView);
552         wxASSERT(![m_cocoaHider->GetNSView() superview]);
553         delete m_cocoaHider;
554         m_cocoaHider = NULL;
555         wxASSERT([cocoaView superview]);
556     }
557     else
558     {
559         // If state isn't changing, return false
560         if(m_cocoaHider)
561             return false;
562         m_cocoaHider = new wxWindowCocoaHider(this);
563         // NOTE: replaceSubview:with will cause m_cocaNSView to be
564         // (auto)released which balances out addSubview
565         CocoaReplaceView(cocoaView, m_cocoaHider->GetNSView());
566         // m_coocaNSView is now only retained by us
567         wxASSERT([m_cocoaHider->GetNSView() superview]);
568         wxASSERT(![cocoaView superview]);
569     }
570     m_isShown = show;
571     return true;
572 }
573
574 void wxWindowCocoa::DoSetSize(int x, int y, int width, int height, int sizeFlags)
575 {
576     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":".");
577     int currentX, currentY;
578     int currentW, currentH;
579     DoGetPosition(&currentX, &currentY);
580     DoGetSize(&currentW, &currentH);
581     if((x==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
582         x=currentX;
583     if((y==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
584         y=currentY;
585
586     AdjustForParentClientOrigin(x,y,sizeFlags);
587
588     wxSize size(-1,-1);
589
590     if((width==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
591     {
592         if(sizeFlags&wxSIZE_AUTO_WIDTH)
593         {
594             size=DoGetBestSize();
595             width=size.x;
596         }
597         else
598             width=currentW;
599     }
600     if((height==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
601     {
602         if(sizeFlags&wxSIZE_AUTO_HEIGHT)
603         {
604             if(size.x==-1)
605                 size=DoGetBestSize();
606             height=size.y;
607         }
608         else
609             height=currentH;
610     }
611     DoMoveWindow(x,y,width,height);
612 }
613
614 //We should really get rid of wxToolTip :)
615 IMPLEMENT_ABSTRACT_CLASS(wxToolTip, wxObject)
616
617 void wxWindowCocoa::DoSetToolTip( wxToolTip *tip )
618 {
619     wxWindowBase::DoSetToolTip(tip);
620
621     wxAutoNSAutoreleasePool pool;
622
623     if ( m_tooltip )
624     {
625         m_tooltip->SetWindow((wxWindow *)this);
626         [GetNSView() setToolTip:wxNSStringWithWxString(m_tooltip->GetTip())];
627     }
628 }
629
630 void wxWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
631 {
632     wxAutoNSAutoreleasePool pool;
633     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoMoveWindow(%d,%d,%d,%d)"),this,x,y,width,height);
634
635     NSView *nsview = GetNSViewForSuperview();
636     NSView *superview = [nsview superview];
637     wxCHECK_RET(superview,wxT("NSView does not have a superview"));
638     NSRect parentRect = [superview bounds];
639
640     NSRect cocoaRect = NSMakeRect(x,parentRect.size.height-(y+height),width,height);
641     [nsview setFrame: cocoaRect];
642     // Be sure to redraw the parent to reflect the changed position
643     [superview setNeedsDisplay:YES];
644 }
645
646 void wxWindowCocoa::SetInitialFrameRect(const wxPoint& pos, const wxSize& size)
647 {
648     NSView *nsview = GetNSViewForSuperview();
649     NSView *superview = [nsview superview];
650     wxCHECK_RET(superview,wxT("NSView does not have a superview"));
651     NSRect parentRect = [superview bounds];
652     NSRect frameRect = [nsview frame];
653     if(size.x!=-1)
654         frameRect.size.width = size.x;
655     if(size.y!=-1)
656         frameRect.size.height = size.y;
657     frameRect.origin.x = pos.x;
658     frameRect.origin.y = parentRect.size.height-(pos.y+frameRect.size.height);
659     // Tell Cocoa to change the margin between the bottom of the superview
660     // and the bottom of the control.  Keeps the control pinned to the top
661     // of its superview so that its position in the wxWidgets coordinate
662     // system doesn't change.
663     if(![superview isFlipped])
664         [nsview setAutoresizingMask: NSViewMinYMargin];
665     // MUST set the mask before setFrame: which can generate a size event
666     // and cause a scroller to be added!
667     [nsview setFrame: frameRect];
668 }
669
670 // Get total size
671 void wxWindow::DoGetSize(int *w, int *h) const
672 {
673     NSRect cocoaRect = [GetNSViewForSuperview() frame];
674     if(w)
675         *w=(int)cocoaRect.size.width;
676     if(h)
677         *h=(int)cocoaRect.size.height;
678     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoGetSize = (%d,%d)"),this,(int)cocoaRect.size.width,(int)cocoaRect.size.height);
679 }
680
681 void wxWindow::DoGetPosition(int *x, int *y) const
682 {
683     NSView *nsview = GetNSViewForSuperview();
684     NSView *superview = [nsview superview];
685     wxCHECK_RET(superview,wxT("NSView does not have a superview"));
686     NSRect parentRect = [superview bounds];
687
688     NSRect cocoaRect = [nsview frame];
689     if(x)
690         *x=(int)cocoaRect.origin.x;
691     if(y)
692         *y=(int)(parentRect.size.height-(cocoaRect.origin.y+cocoaRect.size.height));
693     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoGetPosition = (%d,%d)"),this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);
694 }
695
696 WXWidget wxWindow::GetHandle() const
697 {
698     return m_cocoaNSView;
699 }
700
701 void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
702 {
703     [m_cocoaNSView setNeedsDisplay:YES];
704 }
705
706 void wxWindow::SetFocus()
707 {
708     // TODO
709 }
710
711 void wxWindow::DoCaptureMouse()
712 {
713     // TODO
714     sm_capturedWindow = this;
715 }
716
717 void wxWindow::DoReleaseMouse()
718 {
719     // TODO
720     sm_capturedWindow = NULL;
721 }
722
723 void wxWindow::DoScreenToClient(int *x, int *y) const
724 {
725     // TODO
726 }
727
728 void wxWindow::DoClientToScreen(int *x, int *y) const
729 {
730     // TODO
731 }
732
733 // Get size *available for subwindows* i.e. excluding menu bar etc.
734 void wxWindow::DoGetClientSize(int *x, int *y) const
735 {
736     wxLogTrace(wxTRACE_COCOA,wxT("DoGetClientSize:"));
737     if(m_cocoaScroller)
738         m_cocoaScroller->DoGetClientSize(x,y);
739     else
740         wxWindowCocoa::DoGetSize(x,y);
741 }
742
743 void wxWindow::DoSetClientSize(int width, int height)
744 {
745     wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("DoSetClientSize=(%d,%d)"),width,height);
746     if(m_cocoaScroller)
747         m_cocoaScroller->ClientSizeToSize(width,height);
748     CocoaSetWxWindowSize(width,height);
749 }
750
751 void wxWindow::CocoaSetWxWindowSize(int width, int height)
752 {
753     wxWindowCocoa::DoSetSize(-1,-1,width,height,wxSIZE_USE_EXISTING);
754 }
755
756 int wxWindow::GetCharHeight() const
757 {
758     // TODO
759     return 0;
760 }
761
762 int wxWindow::GetCharWidth() const
763 {
764     // TODO
765     return 0;
766 }
767
768 void wxWindow::GetTextExtent(const wxString& string, int *x, int *y,
769         int *descent, int *externalLeading, const wxFont *theFont) const
770 {
771     // TODO
772 }
773
774 // Coordinates relative to the window
775 void wxWindow::WarpPointer (int x_pos, int y_pos)
776 {
777     // TODO
778 }
779
780 int wxWindow::GetScrollPos(int orient) const
781 {
782     // TODO
783     return 0;
784 }
785
786 // This now returns the whole range, not just the number
787 // of positions that we can scroll.
788 int wxWindow::GetScrollRange(int orient) const
789 {
790     // TODO
791     return 0;
792 }
793
794 int wxWindow::GetScrollThumb(int orient) const
795 {
796     // TODO
797     return 0;
798 }
799
800 void wxWindow::SetScrollPos(int orient, int pos, bool refresh)
801 {
802     // TODO
803 }
804
805 void wxWindow::CocoaCreateNSScrollView()
806 {
807     if(!m_cocoaScroller)
808     {
809         m_cocoaScroller = new wxWindowCocoaScroller(this);
810     }
811 }
812
813 // New function that will replace some of the above.
814 void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible,
815     int range, bool refresh)
816 {
817     CocoaCreateNSScrollView();
818     // TODO
819 }
820
821 // Does a physical scroll
822 void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
823 {
824     // TODO
825 }
826
827 void wxWindow::DoSetVirtualSize( int x, int y )
828 {
829     wxWindowBase::DoSetVirtualSize(x,y);
830     CocoaCreateNSScrollView();
831     [m_cocoaNSView setFrameSize:NSMakeSize(m_virtualSize.x,m_virtualSize.y)];
832 }
833
834 bool wxWindow::SetFont(const wxFont& font)
835 {
836     // TODO
837     return TRUE;
838 }
839
840 static int CocoaRaiseWindowCompareFunction(id first, id second, void *target)
841 {
842     // first should be ordered higher
843     if(first==target)
844         return NSOrderedDescending;
845     // second should be ordered higher
846     if(second==target)
847         return NSOrderedAscending;
848     return NSOrderedSame;
849 }
850
851 // Raise the window to the top of the Z order
852 void wxWindow::Raise()
853 {
854 //    wxAutoNSAutoreleasePool pool;
855     NSView *nsview = GetNSViewForSuperview();
856     [[nsview superview] sortSubviewsUsingFunction:
857             CocoaRaiseWindowCompareFunction
858         context: nsview];
859 }
860
861 static int CocoaLowerWindowCompareFunction(id first, id second, void *target)
862 {
863     // first should be ordered lower
864     if(first==target)
865         return NSOrderedAscending;
866     // second should be ordered lower
867     if(second==target)
868         return NSOrderedDescending;
869     return NSOrderedSame;
870 }
871
872 // Lower the window to the bottom of the Z order
873 void wxWindow::Lower()
874 {
875     NSView *nsview = GetNSViewForSuperview();
876     [[nsview superview] sortSubviewsUsingFunction:
877             CocoaLowerWindowCompareFunction
878         context: nsview];
879 }
880
881 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
882 {
883     return FALSE;
884 }
885
886 // Get the window with the focus
887 wxWindow *wxWindowBase::DoFindFocus()
888 {
889     // TODO
890     return NULL;
891 }
892
893 /* static */ wxWindow *wxWindowBase::GetCapture()
894 {
895     // TODO
896     return wxWindowCocoa::sm_capturedWindow;
897 }
898
899 wxWindow *wxGetActiveWindow()
900 {
901     // TODO
902     return NULL;
903 }
904
905 wxPoint wxGetMousePosition()
906 {
907     // TODO
908     return wxDefaultPosition;
909 }
910
911 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
912 {
913     pt = wxGetMousePosition();
914     return NULL;
915 }
916