1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/cocoa/window.mm
3 // Purpose: wxWindowCocoa
4 // Author: David Elliott
8 // Copyright: (c) 2002 David Elliott
9 // Licence: wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
16 #include "wx/window.h"
21 #include "wx/tooltip.h"
23 #include "wx/cocoa/autorelease.h"
24 #include "wx/cocoa/string.h"
25 #include "wx/cocoa/trackingrectmanager.h"
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>
39 // Turn this on to paint green over the dummy views for debugging
40 #undef WXCOCOA_FILL_DUMMY_VIEW
42 #ifdef WXCOCOA_FILL_DUMMY_VIEW
43 #import <AppKit/NSBezierPath.h>
44 #endif //def WXCOCOA_FILL_DUMMY_VIEW
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.
52 #if defined(NSINTEGER_DEFINED)
53 typedef NSComparisonResult CocoaWindowCompareFunctionResult;
55 typedef int CocoaWindowCompareFunctionResult;
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;
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)
69 wxCHECK_MSG(nsview, pointBounds, wxT("Need to have a Cocoa view to do translation"));
70 if([nsview isFlipped])
72 NSRect ourBounds = [nsview bounds];
75 , ourBounds.size.height - pointBounds.y
79 NSRect CocoaTransformNSViewBoundsToWx(NSView *nsview, NSRect rectBounds)
81 wxCHECK_MSG(nsview, rectBounds, wxT("Need to have a Cocoa view to do translation"));
82 if([nsview isFlipped])
84 NSRect ourBounds = [nsview bounds];
87 , ourBounds.size.height - (rectBounds.origin.y + rectBounds.size.height)
88 , rectBounds.size.width
89 , rectBounds.size.height
93 NSPoint CocoaTransformNSViewWxToBounds(NSView *nsview, NSPoint pointWx)
95 wxCHECK_MSG(nsview, pointWx, wxT("Need to have a Cocoa view to do translation"));
96 if([nsview isFlipped])
98 NSRect ourBounds = [nsview bounds];
101 , ourBounds.size.height - pointWx.y
105 NSRect CocoaTransformNSViewWxToBounds(NSView *nsview, NSRect rectWx)
107 wxCHECK_MSG(nsview, rectWx, wxT("Need to have a Cocoa view to do translation"));
108 if([nsview isFlipped])
110 NSRect ourBounds = [nsview bounds];
113 , ourBounds.size.height - (rectWx.origin.y + rectWx.size.height)
119 // ============================================================================
120 // Screen coordinate helpers
121 // ============================================================================
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.
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.
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.
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.
142 namespace { // file namespace
144 class wxCocoaPrivateScreenCoordinateTransformer
146 DECLARE_NO_COPY_CLASS(wxCocoaPrivateScreenCoordinateTransformer)
148 wxCocoaPrivateScreenCoordinateTransformer();
149 ~wxCocoaPrivateScreenCoordinateTransformer();
150 wxPoint OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame);
151 NSPoint OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible);
154 NSScreen *m_screenZero;
155 NSRect m_screenZeroFrame;
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
161 inline wxCocoaPrivateScreenCoordinateTransformer::wxCocoaPrivateScreenCoordinateTransformer()
163 NSArray *screens = [NSScreen screens];
168 if(screens != nil && [screens count] > 0)
169 m_screenZero = [[screens objectAtIndex:0] retain];
173 if(m_screenZero != nil)
174 m_screenZeroFrame = [m_screenZero frame];
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);
185 inline wxCocoaPrivateScreenCoordinateTransformer::~wxCocoaPrivateScreenCoordinateTransformer()
187 [m_screenZero release];
191 inline wxPoint wxCocoaPrivateScreenCoordinateTransformer::OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame)
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.
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;
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.
208 theWxOrigin.y = (m_screenZeroFrame.origin.y + m_screenZeroFrame.size.height) - (windowFrame.origin.y + windowFrame.size.height);
213 inline NSPoint wxCocoaPrivateScreenCoordinateTransformer::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible)
215 NSPoint theCocoaOrigin;
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)
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))
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)
232 if(y >= 0 && y < visibleOrigin.y)
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;
245 return theCocoaOrigin;
250 wxPoint wxWindowCocoa::OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame)
252 wxCocoaPrivateScreenCoordinateTransformer transformer;
253 return transformer.OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(windowFrame);
256 NSPoint wxWindowCocoa::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible)
258 wxCocoaPrivateScreenCoordinateTransformer transformer;
259 return transformer.OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x,y,width,height,keepOriginVisible);
262 // ========================================================================
263 // wxWindowCocoaHider
264 // ========================================================================
265 class wxWindowCocoaHider: protected wxCocoaNSView
267 DECLARE_NO_COPY_CLASS(wxWindowCocoaHider)
269 wxWindowCocoaHider(wxWindow *owner);
270 virtual ~wxWindowCocoaHider();
271 inline WX_NSView GetNSView() { return m_dummyNSView; }
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
281 wxWindowCocoaHider();
284 // ========================================================================
285 // wxWindowCocoaScrollView
286 // ========================================================================
287 class wxWindowCocoaScrollView: protected wxCocoaNSView
289 DECLARE_NO_COPY_CLASS(wxWindowCocoaScrollView)
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;
297 void Unencapsulate();
299 wxWindowCocoa *m_owner;
300 WX_NSScrollView m_cocoaNSScrollView;
301 virtual void Cocoa_FrameChanged(void);
302 virtual void Cocoa_synthesizeMouseMoved(void) {}
304 wxWindowCocoaScrollView();
307 // ========================================================================
309 // ========================================================================
310 @interface wxDummyNSView : NSView
311 - (NSView *)hitTest:(NSPoint)aPoint;
313 WX_DECLARE_GET_OBJC_CLASS(wxDummyNSView,NSView)
315 @implementation wxDummyNSView : NSView
316 - (NSView *)hitTest:(NSPoint)aPoint
322 WX_IMPLEMENT_GET_OBJC_CLASS(wxDummyNSView,NSView)
324 // ========================================================================
325 // wxWindowCocoaHider
326 // ========================================================================
327 wxWindowCocoaHider::wxWindowCocoaHider(wxWindow *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);
338 wxWindowCocoaHider::~wxWindowCocoaHider()
340 DisassociateNSView(m_dummyNSView);
341 [m_dummyNSView release];
344 void wxWindowCocoaHider::Cocoa_FrameChanged(void)
346 // Keep the real window in synch with the dummy
347 wxASSERT(m_dummyNSView);
348 [m_owner->GetNSViewForHiding() setFrame:[m_dummyNSView frame]];
352 #ifdef WXCOCOA_FILL_DUMMY_VIEW
353 bool wxWindowCocoaHider::Cocoa_drawRect(const NSRect& rect)
355 NSBezierPath *bezpath = [NSBezierPath bezierPathWithRect:rect];
356 [[NSColor greenColor] set];
361 #endif //def WXCOCOA_FILL_DUMMY_VIEW
363 // ========================================================================
364 // wxFlippedNSClipView
365 // ========================================================================
366 @interface wxFlippedNSClipView : NSClipView
369 WX_DECLARE_GET_OBJC_CLASS(wxFlippedNSClipView,NSClipView)
371 @implementation wxFlippedNSClipView : NSClipView
378 WX_IMPLEMENT_GET_OBJC_CLASS(wxFlippedNSClipView,NSClipView)
380 // ========================================================================
381 // wxWindowCocoaScrollView
382 // ========================================================================
383 wxWindowCocoaScrollView::wxWindowCocoaScrollView(wxWindow *owner)
386 wxAutoNSAutoreleasePool pool;
388 wxASSERT(owner->GetNSView());
389 m_cocoaNSScrollView = [[NSScrollView alloc]
390 initWithFrame:[owner->GetNSView() frame]];
391 AssociateNSView(m_cocoaNSScrollView);
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];
400 [m_cocoaNSScrollView setBackgroundColor: [NSColor windowBackgroundColor]];
401 [m_cocoaNSScrollView setHasHorizontalScroller: YES];
402 [m_cocoaNSScrollView setHasVerticalScroller: YES];
406 void wxWindowCocoaScrollView::Encapsulate()
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
420 void wxWindowCocoaScrollView::Unencapsulate()
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];
428 wxWindowCocoaScrollView::~wxWindowCocoaScrollView()
430 DisassociateNSView(m_cocoaNSScrollView);
431 [m_cocoaNSScrollView release];
434 void wxWindowCocoaScrollView::ClientSizeToSize(int &width, int &height)
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;
445 void wxWindowCocoaScrollView::DoGetClientSize(int *x, int *y) const
447 NSSize nssize = [m_cocoaNSScrollView contentSize];
449 *x = (int)nssize.width;
451 *y = (int)nssize.height;
454 void wxWindowCocoaScrollView::Cocoa_FrameChanged(void)
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);
462 // ========================================================================
464 // ========================================================================
465 // normally the base classes aren't included, but wxWindow is special
466 #ifdef __WXUNIVERSAL__
467 IMPLEMENT_ABSTRACT_CLASS(wxWindowCocoa, wxWindowBase)
469 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
472 BEGIN_EVENT_TABLE(wxWindowCocoa, wxWindowBase)
475 wxWindow *wxWindowCocoa::sm_capturedWindow = NULL;
478 void wxWindowCocoa::Init()
480 m_cocoaNSView = NULL;
482 m_wxCocoaScrollView = NULL;
483 m_isBeingDeleted = false;
485 m_visibleTrackingRectManager = NULL;
489 bool wxWindow::Create(wxWindow *parent, wxWindowID winid,
493 const wxString& name)
495 if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
498 // TODO: create the window
499 m_cocoaNSView = NULL;
500 SetNSView([[WX_GET_OBJC_CLASS(WXNSView) alloc] initWithFrame: MakeDefaultNSRect(size)]);
501 [m_cocoaNSView release];
505 m_parent->AddChild(this);
506 m_parent->CocoaAddChild(this);
507 SetInitialFrameRect(pos,size);
514 wxWindow::~wxWindow()
516 wxAutoNSAutoreleasePool pool;
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();
524 delete m_wxCocoaScrollView;
530 void wxWindowCocoa::CocoaAddChild(wxWindowCocoa *child)
532 // Pool here due to lack of one during wx init phase
533 wxAutoNSAutoreleasePool pool;
535 NSView *childView = child->GetNSViewForSuperview();
538 [m_cocoaNSView addSubview: childView];
539 child->m_isShown = !m_cocoaHider;
542 void wxWindowCocoa::CocoaRemoveFromParent(void)
544 [GetNSViewForSuperview() removeFromSuperview];
547 void wxWindowCocoa::SetNSView(WX_NSView cocoaNSView)
549 // Clear the visible area tracking rect if we have one.
550 delete m_visibleTrackingRectManager;
551 m_visibleTrackingRectManager = NULL;
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]);
563 WX_NSView wxWindowCocoa::GetNSViewForSuperview() const
566 ? m_cocoaHider->GetNSView()
567 : m_wxCocoaScrollView
568 ? m_wxCocoaScrollView->GetNSScrollView()
572 WX_NSView wxWindowCocoa::GetNSViewForHiding() const
574 return m_wxCocoaScrollView
575 ? m_wxCocoaScrollView->GetNSScrollView()
579 NSPoint wxWindowCocoa::CocoaTransformBoundsToWx(NSPoint pointBounds)
581 // TODO: Handle scrolling offset
582 return CocoaTransformNSViewBoundsToWx(GetNSView(), pointBounds);
585 NSRect wxWindowCocoa::CocoaTransformBoundsToWx(NSRect rectBounds)
587 // TODO: Handle scrolling offset
588 return CocoaTransformNSViewBoundsToWx(GetNSView(), rectBounds);
591 NSPoint wxWindowCocoa::CocoaTransformWxToBounds(NSPoint pointWx)
593 // TODO: Handle scrolling offset
594 return CocoaTransformNSViewWxToBounds(GetNSView(), pointWx);
597 NSRect wxWindowCocoa::CocoaTransformWxToBounds(NSRect rectWx)
599 // TODO: Handle scrolling offset
600 return CocoaTransformNSViewWxToBounds(GetNSView(), rectWx);
603 WX_NSAffineTransform wxWindowCocoa::CocoaGetWxToBoundsTransform()
605 // TODO: Handle scrolling offset
606 NSAffineTransform *transform = wxDC::CocoaGetWxToBoundsTransform([GetNSView() isFlipped], [GetNSView() bounds].size.height);
610 bool wxWindowCocoa::Cocoa_drawRect(const NSRect &rect)
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.
618 wxLogDebug(wxT("Paint event recursion!"));
623 // Set m_updateRegion
624 const NSRect *rects = ▭ // 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];
630 NSRect *transformedRects = (NSRect*)malloc(sizeof(NSRect)*countRects);
631 for(int i=0; i<countRects; i++)
633 transformedRects[i] = CocoaTransformBoundsToWx(rects[i]);
635 m_updateRegion = wxRegion(transformedRects,countRects);
636 free(transformedRects);
638 wxPaintEvent event(m_windowId);
639 event.SetEventObject(this);
640 bool ret = GetEventHandler()->ProcessEvent(event);
645 void wxWindowCocoa::InitMouseEvent(wxMouseEvent& event, WX_NSEvent cocoaEvent)
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;
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;
662 // TODO: set timestamp?
663 event.SetEventObject(this);
664 event.SetId(GetId());
667 bool wxWindowCocoa::Cocoa_mouseMoved(WX_NSEvent theEvent)
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);
675 void wxWindowCocoa::Cocoa_synthesizeMouseMoved()
677 wxMouseEvent event(wxEVT_MOTION);
678 NSWindow *window = [GetNSView() window];
679 NSPoint locationInWindow = [window mouseLocationOutsideOfEventStream];
680 NSPoint cocoaPoint = [m_cocoaNSView convertPoint:locationInWindow fromView:nil];
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;
688 // TODO: Handle shift, control, alt, meta flags
689 event.SetEventObject(this);
690 event.SetId(GetId());
692 wxLogTrace(wxTRACE_COCOA,wxT("wxwin=%p Synthesized Mouse Moved @%d,%d"),this,event.m_x,event.m_y);
693 GetEventHandler()->ProcessEvent(event);
696 bool wxWindowCocoa::Cocoa_mouseEntered(WX_NSEvent theEvent)
698 if(m_visibleTrackingRectManager != NULL && m_visibleTrackingRectManager->IsOwnerOfEvent(theEvent))
700 m_visibleTrackingRectManager->BeginSynthesizingEvents();
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];
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);
717 bool wxWindowCocoa::Cocoa_mouseExited(WX_NSEvent theEvent)
719 if(m_visibleTrackingRectManager != NULL && m_visibleTrackingRectManager->IsOwnerOfEvent(theEvent))
721 m_visibleTrackingRectManager->StopSynthesizingEvents();
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);
732 bool wxWindowCocoa::Cocoa_mouseDown(WX_NSEvent theEvent)
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);
740 bool wxWindowCocoa::Cocoa_mouseDragged(WX_NSEvent theEvent)
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);
749 bool wxWindowCocoa::Cocoa_mouseUp(WX_NSEvent theEvent)
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);
757 bool wxWindowCocoa::Cocoa_rightMouseDown(WX_NSEvent theEvent)
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);
765 bool wxWindowCocoa::Cocoa_rightMouseDragged(WX_NSEvent theEvent)
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);
774 bool wxWindowCocoa::Cocoa_rightMouseUp(WX_NSEvent theEvent)
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);
782 bool wxWindowCocoa::Cocoa_otherMouseDown(WX_NSEvent theEvent)
787 bool wxWindowCocoa::Cocoa_otherMouseDragged(WX_NSEvent theEvent)
792 bool wxWindowCocoa::Cocoa_otherMouseUp(WX_NSEvent theEvent)
797 void wxWindowCocoa::Cocoa_FrameChanged(void)
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);
807 bool wxWindowCocoa::Cocoa_resetCursorRects()
809 wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_resetCursorRects"),this);
810 if(m_visibleTrackingRectManager != NULL)
811 m_visibleTrackingRectManager->RebuildTrackingRect();
813 if(!m_cursor.GetNSCursor())
816 [GetNSView() addCursorRect: [GetNSView() visibleRect] cursor: m_cursor.GetNSCursor()];
821 bool wxWindowCocoa::SetCursor(const wxCursor &cursor)
823 if(!wxWindowBase::SetCursor(cursor))
825 // Invalidate the cursor rects so the cursor will change
826 [[GetNSView() window] invalidateCursorRectsForView:GetNSView()];
830 bool wxWindowCocoa::Cocoa_viewDidMoveToWindow()
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();
839 bool wxWindowCocoa::Cocoa_viewWillMoveToWindow(WX_NSWindow newWindow)
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();
848 bool wxWindow::Close(bool force)
850 // The only reason this function exists is that it is virtual and
851 // wxTopLevelWindowCocoa will override it.
852 return wxWindowBase::Close(force);
855 void wxWindow::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
857 [[oldView superview] replaceSubview:oldView with:newView];
860 void wxWindow::DoEnable(bool enable)
862 CocoaSetEnabled(enable);
865 bool wxWindow::Show(bool show)
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();
878 // If state isn't changing, return false
881 CocoaReplaceView(m_cocoaHider->GetNSView(), cocoaView);
882 wxASSERT(![m_cocoaHider->GetNSView() superview]);
885 wxASSERT([cocoaView superview]);
889 // If state isn't changing, 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]);
904 void wxWindowCocoa::DoSetSize(int x, int y, int width, int height, int sizeFlags)
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(¤tX, ¤tY);
910 DoGetSize(¤tW, ¤tH);
911 if((x==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
913 if((y==-1) && !(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
916 AdjustForParentClientOrigin(x,y,sizeFlags);
918 wxSize size(wxDefaultSize);
920 if((width==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
922 if(sizeFlags&wxSIZE_AUTO_WIDTH)
924 size=DoGetBestSize();
930 if((height==-1)&&!(sizeFlags&wxSIZE_ALLOW_MINUS_ONE))
932 if(sizeFlags&wxSIZE_AUTO_HEIGHT)
935 size=DoGetBestSize();
941 DoMoveWindow(x,y,width,height);
946 void wxWindowCocoa::DoSetToolTip( wxToolTip *tip )
948 wxWindowBase::DoSetToolTip(tip);
952 m_tooltip->SetWindow((wxWindow *)this);
958 void wxWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
960 wxAutoNSAutoreleasePool pool;
961 wxLogTrace(wxTRACE_COCOA_Window_Size,wxT("wxWindow=%p::DoMoveWindow(%d,%d,%d,%d)"),this,x,y,width,height);
963 NSView *nsview = GetNSViewForSuperview();
964 NSView *superview = [nsview superview];
966 wxCHECK_RET(GetParent(), wxT("Window can only be placed correctly when it has a parent"));
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];
976 void wxWindowCocoa::SetInitialFrameRect(const wxPoint& pos, const wxSize& size)
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];
984 frameRect.size.width = size.x;
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];
1002 void wxWindow::DoGetSize(int *w, int *h) const
1004 NSRect cocoaRect = [GetNSViewForSuperview() frame];
1006 *w=(int)cocoaRect.size.width;
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);
1012 void wxWindow::DoGetPosition(int *x, int *y) const
1014 NSView *nsview = GetNSViewForSuperview();
1016 NSRect cocoaRect = [nsview frame];
1017 NSRect rectWx = GetParent()->CocoaTransformBoundsToWx(cocoaRect);
1019 *x=(int)rectWx.origin.x;
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);
1025 WXWidget wxWindow::GetHandle() const
1027 return m_cocoaNSView;
1030 wxWindow* wxWindow::GetWxWindow() const
1032 return (wxWindow*) this;
1035 void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
1037 [m_cocoaNSView setNeedsDisplay:YES];
1040 void wxWindow::SetFocus()
1042 if([GetNSView() acceptsFirstResponder])
1043 [[GetNSView() window] makeFirstResponder: GetNSView()];
1046 void wxWindow::DoCaptureMouse()
1049 sm_capturedWindow = this;
1052 void wxWindow::DoReleaseMouse()
1055 sm_capturedWindow = NULL;
1058 void wxWindow::DoScreenToClient(int *x, int *y) const
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];
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);
1072 *x = theWxClientPoint.x;
1074 *y = theWxClientPoint.y;
1077 void wxWindow::DoClientToScreen(int *x, int *y) const
1079 // Point in wx client coordinates
1080 NSPoint theWxClientPoint = NSMakePoint(x!=NULL?*x:0, y!=NULL?*y:0);
1082 NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
1084 // Point in the view's bounds coordinate system
1085 NSPoint boundsPoint = CocoaTransformNSViewWxToBounds(clientView, theWxClientPoint);
1087 // Point in the window's base coordinate system
1088 NSPoint windowPoint = [clientView convertPoint:boundsPoint toView:nil];
1090 NSWindow *theWindow = [clientView window];
1091 // Point in Cocoa's screen coordinates
1092 NSPoint screenPoint = [theWindow convertBaseToScreen:windowPoint];
1094 // Act as though this was the origin of a 0x0 rectangle
1095 NSRect screenPointRect = NSMakeRect(screenPoint.x, screenPoint.y, 0, 0);
1097 // Convert that rectangle to wx coordinates
1098 wxPoint theWxScreenPoint = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(screenPointRect);
1100 *x = theWxScreenPoint.x;
1102 *y = theWxScreenPoint.y;
1105 // Get size *available for subwindows* i.e. excluding menu bar etc.
1106 void wxWindow::DoGetClientSize(int *x, int *y) const
1108 wxLogTrace(wxTRACE_COCOA,wxT("DoGetClientSize:"));
1109 if(m_wxCocoaScrollView)
1110 m_wxCocoaScrollView->DoGetClientSize(x,y);
1112 wxWindowCocoa::DoGetSize(x,y);
1115 void wxWindow::DoSetClientSize(int width, int height)
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);
1123 void wxWindow::CocoaSetWxWindowSize(int width, int height)
1125 wxWindowCocoa::DoSetSize(wxDefaultCoord,wxDefaultCoord,width,height,wxSIZE_USE_EXISTING);
1128 void wxWindow::SetLabel(const wxString& WXUNUSED(label))
1130 // Intentional no-op.
1133 wxString wxWindow::GetLabel() const
1135 // General Get/Set of labels is implemented in wxControlBase
1136 wxLogDebug(wxT("wxWindow::GetLabel: Should be overridden if needed."));
1137 return wxEmptyString;
1140 int wxWindow::GetCharHeight() const
1146 int wxWindow::GetCharWidth() const
1152 void wxWindow::GetTextExtent(const wxString& string, int *x, int *y,
1153 int *descent, int *externalLeading, const wxFont *theFont) const
1158 // Coordinates relative to the window
1159 void wxWindow::WarpPointer (int x_pos, int y_pos)
1164 int wxWindow::GetScrollPos(int orient) const
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
1178 int wxWindow::GetScrollThumb(int orient) const
1184 void wxWindow::SetScrollPos(int orient, int pos, bool refresh)
1189 void wxWindow::CocoaCreateNSScrollView()
1191 if(!m_wxCocoaScrollView)
1193 m_wxCocoaScrollView = new wxWindowCocoaScrollView(this);
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)
1201 CocoaCreateNSScrollView();
1205 // Does a physical scroll
1206 void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
1211 void wxWindow::DoSetVirtualSize( int x, int y )
1213 wxWindowBase::DoSetVirtualSize(x,y);
1214 CocoaCreateNSScrollView();
1215 [m_cocoaNSView setFrameSize:NSMakeSize(m_virtualSize.x,m_virtualSize.y)];
1218 bool wxWindow::SetFont(const wxFont& font)
1220 // FIXME: We may need to handle wx font inheritance.
1221 return wxWindowBase::SetFont(font);
1224 #if 0 // these are used when debugging the algorithm.
1225 static char const * const comparisonresultStrings[] =
1232 class CocoaWindowCompareContext
1234 DECLARE_NO_COPY_CLASS(CocoaWindowCompareContext)
1236 CocoaWindowCompareContext(); // Not implemented
1237 CocoaWindowCompareContext(NSView *target, NSArray *subviews)
1240 // Cocoa sorts subviews in-place.. make a copy
1241 m_subviews = [subviews copy];
1243 ~CocoaWindowCompareContext()
1244 { // release the copy
1245 [m_subviews release];
1248 { return m_target; }
1250 { return m_subviews; }
1251 /* Helper function that returns the comparison based off of the original ordering */
1252 CocoaWindowCompareFunctionResult CompareUsingOriginalOrdering(id first, id second)
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.
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 */;
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);
1276 /* The subview we are trying to Raise or Lower */
1278 /* A copy of the original array of subviews */
1279 NSArray *m_subviews;
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
1286 static CocoaWindowCompareFunctionResult CocoaRaiseWindowCompareFunction(id first, id second, void *ctx)
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);
1298 // Raise the window to the top of the Z order
1299 void wxWindow::Raise()
1301 // wxAutoNSAutoreleasePool pool;
1302 NSView *nsview = GetNSViewForSuperview();
1303 NSView *superview = [nsview superview];
1304 CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1306 [superview sortSubviewsUsingFunction:
1307 CocoaRaiseWindowCompareFunction
1308 context: &compareContext];
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
1315 static CocoaWindowCompareFunctionResult CocoaLowerWindowCompareFunction(id first, id second, void *ctx)
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);
1327 // Lower the window to the bottom of the Z order
1328 void wxWindow::Lower()
1330 NSView *nsview = GetNSViewForSuperview();
1331 NSView *superview = [nsview superview];
1332 CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
1335 NSLog(@"Target:\n%@\n", nsview);
1336 NSLog(@"Before:\n%@\n", compareContext.subviews());
1338 [superview sortSubviewsUsingFunction:
1339 CocoaLowerWindowCompareFunction
1340 context: &compareContext];
1342 NSLog(@"After:\n%@\n", [superview subviews]);
1346 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
1351 // Get the window with the focus
1352 wxWindow *wxWindowBase::DoFindFocus()
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.
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.
1365 NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
1366 win = wxCocoaNSView::GetFromCocoa(static_cast<NSView*>([keyWindow firstResponder]));
1368 return win->GetWxWindow();
1370 NSWindow *mainWindow = [[NSApplication sharedApplication] keyWindow];
1371 if(mainWindow == keyWindow)
1373 win = wxCocoaNSView::GetFromCocoa(static_cast<NSView*>([mainWindow firstResponder]));
1375 return win->GetWxWindow();
1380 /* static */ wxWindow *wxWindowBase::GetCapture()
1383 return wxWindowCocoa::sm_capturedWindow;
1386 wxWindow *wxGetActiveWindow()
1392 wxPoint wxGetMousePosition()
1395 return wxDefaultPosition;
1398 wxMouseState wxGetMouseState()
1405 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1407 pt = wxGetMousePosition();
1412 // ========================================================================
1413 // wxCocoaTrackingRectManager
1414 // ========================================================================
1416 wxCocoaTrackingRectManager::wxCocoaTrackingRectManager(wxWindow *window)
1419 m_isTrackingRectActive = false;
1420 m_runLoopObserver = NULL;
1421 BuildTrackingRect();
1424 void wxCocoaTrackingRectManager::ClearTrackingRect()
1426 if(m_isTrackingRectActive)
1428 [m_window->GetNSView() removeTrackingRect:m_trackingRectTag];
1429 m_isTrackingRectActive = false;
1431 // If we were doing periodic events we need to clear those too
1432 StopSynthesizingEvents();
1435 void wxCocoaTrackingRectManager::StopSynthesizingEvents()
1437 if(m_runLoopObserver != NULL)
1439 CFRunLoopRemoveObserver([[NSRunLoop currentRunLoop] getCFRunLoop], m_runLoopObserver, kCFRunLoopCommonModes);
1440 CFRelease(m_runLoopObserver);
1441 m_runLoopObserver = NULL;
1445 void wxCocoaTrackingRectManager::BuildTrackingRect()
1447 // Pool here due to lack of one during wx init phase
1448 wxAutoNSAutoreleasePool pool;
1450 wxASSERT_MSG(!m_isTrackingRectActive, wxT("Tracking rect was not cleared"));
1451 if([m_window->GetNSView() window] != nil)
1453 m_trackingRectTag = [m_window->GetNSView() addTrackingRect:[m_window->GetNSView() visibleRect] owner:m_window->GetNSView() userData:NULL assumeInside:NO];
1454 m_isTrackingRectActive = true;
1458 static NSPoint s_lastScreenMouseLocation = NSZeroPoint;
1460 static void SynthesizeMouseMovedEvent(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
1462 NSPoint screenMouseLocation = [NSEvent mouseLocation];
1463 if(screenMouseLocation.x != s_lastScreenMouseLocation.x || screenMouseLocation.y != s_lastScreenMouseLocation.y)
1465 wxCocoaNSView *win = reinterpret_cast<wxCocoaNSView*>(info);
1466 win->Cocoa_synthesizeMouseMoved();
1470 void wxCocoaTrackingRectManager::BeginSynthesizingEvents()
1472 CFRunLoopObserverContext observerContext =
1474 , static_cast<wxCocoaNSView*>(m_window)
1479 m_runLoopObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, TRUE, 0, SynthesizeMouseMovedEvent, &observerContext);
1480 CFRunLoopAddObserver([[NSRunLoop currentRunLoop] getCFRunLoop], m_runLoopObserver, kCFRunLoopCommonModes);
1483 void wxCocoaTrackingRectManager::RebuildTrackingRect()
1485 ClearTrackingRect();
1486 BuildTrackingRect();
1489 wxCocoaTrackingRectManager::~wxCocoaTrackingRectManager()
1491 ClearTrackingRect();
1494 bool wxCocoaTrackingRectManager::IsOwnerOfEvent(NSEvent *anEvent)
1496 return m_isTrackingRectActive && (m_trackingRectTag == [anEvent trackingNumber]);