X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/618d53b890bfcdc2daf0856fe4a72c69318bf479..04ce16a8707de253826da7b46d03896307a51625:/src/cocoa/window.mm?ds=sidebyside diff --git a/src/cocoa/window.mm b/src/cocoa/window.mm index 22228ee52c..fe1ea122e1 100644 --- a/src/cocoa/window.mm +++ b/src/cocoa/window.mm @@ -15,15 +15,19 @@ #include "wx/log.h" #include "wx/window.h" #include "wx/dc.h" + #include "wx/dcclient.h" #include "wx/utils.h" #endif //WX_PRECOMP #include "wx/tooltip.h" +#include "wx/cocoa/dc.h" #include "wx/cocoa/autorelease.h" #include "wx/cocoa/string.h" #include "wx/cocoa/trackingrectmanager.h" -#include "wx/mac/corefoundation/cfref.h" +#include "wx/cocoa/private/scrollview.h" +#include "wx/osx/core/cfref.h" +#include "wx/cocoa/ObjcRef.h" #import #import @@ -148,7 +152,7 @@ namespace { // file namespace class wxCocoaPrivateScreenCoordinateTransformer { - DECLARE_NO_COPY_CLASS(wxCocoaPrivateScreenCoordinateTransformer) + wxDECLARE_NO_COPY_CLASS(wxCocoaPrivateScreenCoordinateTransformer); public: wxCocoaPrivateScreenCoordinateTransformer(); ~wxCocoaPrivateScreenCoordinateTransformer(); @@ -269,7 +273,7 @@ NSPoint wxWindowCocoa::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinat // ======================================================================== class wxWindowCocoaHider: protected wxCocoaNSView { - DECLARE_NO_COPY_CLASS(wxWindowCocoaHider) + wxDECLARE_NO_COPY_CLASS(wxWindowCocoaHider); public: wxWindowCocoaHider(wxWindow *owner); virtual ~wxWindowCocoaHider(); @@ -286,118 +290,6 @@ private: wxWindowCocoaHider(); }; -// ======================================================================== -// wxWindowCocoaScrollView -// ======================================================================== -class wxWindowCocoaScrollView: protected wxCocoaNSView -{ - DECLARE_NO_COPY_CLASS(wxWindowCocoaScrollView) -public: - wxWindowCocoaScrollView(wxWindow *owner); - virtual ~wxWindowCocoaScrollView(); - inline WX_NSScrollView GetNSScrollView() { return m_cocoaNSScrollView; } - void ClientSizeToSize(int &width, int &height); - void DoGetClientSize(int *x, int *y) const; - void Encapsulate(); - void Unencapsulate(); - - // wxWindow calls this to do the work. Note that we don't have the refresh parameter - // because wxWindow handles that itself. - void SetScrollbar(int orientation, int position, int thumbSize, int range); - int GetScrollPos(wxOrientation orient); - void SetScrollPos(wxOrientation orient, int position); - int GetScrollRange(wxOrientation orient); - int GetScrollThumb(wxOrientation orient); - void ScrollWindow(int dx, int dy, const wxRect*); - void UpdateSizes(); - - void _wx_doScroller(NSScroller *sender); - -protected: - wxWindowCocoa *m_owner; - WX_NSScrollView m_cocoaNSScrollView; - virtual void Cocoa_FrameChanged(void); - virtual void Cocoa_synthesizeMouseMoved(void) {} - /*! - Flag as to whether we're scrolling for a native view or a custom - wxWindow. This controls the scrolling behavior. When providing - scrolling for a native view we don't catch scroller action messages - and thus don't send scroll events and we don't actually scroll the - window when the application calls ScrollWindow. - - When providing scrolling for a custom wxWindow, we make the NSScroller - send their action messages to us which we in turn package as wx window - scrolling events. At this point, the window will not physically be - scrolled. The application will most likely handle the event by calling - ScrollWindow which will do the real scrolling. On the other hand, - the application may instead not call ScrollWindow until some threshold - is reached. This causes the window to only scroll in steps which is - what, for instance, wxScrolledWindow does. - */ - bool m_isNativeView; - /*! - The range as the application code wishes to see it. That is, the - range from the last SetScrollbar call for the appropriate dimension. - The horizontal dimension is the first [0] element and the vertical - dimension the second [1] element. - - In wxMSW, a SCROLLINFO with nMin=0 and nMax=range-1 is used which - gives exactly range possible positions so long as nPage (which is - the thumb size) is less than or equal to 1. - */ - int m_scrollRange[2]; - /*! - The thumb size is intended to reflect the size of the visible portion - of the scrolled document. As the document size increases, the thumb - visible thumb size decreases. As document size decreases, the visible - thumb size increases. However, the thumb size on wx is defined in - terms of scroll units (which are effectively defined by the scroll - range) and so increasing the number of scroll units to reflect increased - document size will have the effect of decreasing the visible thumb - size even though the number doesn't change. - - It's also important to note that subtracting the thumb size from the - full range gives you the real range that can be used. Microsoft - defines nPos (the current scrolling position) to be within the range - from nMin to nMax - max(nPage - 1, 0). We know that wxMSW code always - sets nMin = 0 and nMax = range -1. So let's algebraically reduce the - definition of the maximum allowed position: - - Begin: - = nMax - max(nPage - 1, 0) - Substitute (range - 1) for nMax and thumbSize for nPage: - = range - 1 - max(thumbSize - 1, 0) - Add one inside the max conditional and subtract one outside of it: - = range - 1 - (max(thumbSize - 1 + 1, 1) - 1) - Reduce some constants: - = range - 1 - (max(thumbSize, 1) - 1) - Distribute the negative across the parenthesis: - = range - 1 - max(thumbSize, 1) + 1 - Reduce the constants: - = range - max(thumbSize, 1) - - Also keep in mind that thumbSize may never be greater than range but - can be equal to it. Thus for the smallest possible thumbSize there - are exactly range possible scroll positions (numbered from 0 to - range - 1) and for the largest possible thumbSize there is exactly - one possible scroll position (numbered 0). - */ - int m_scrollThumb[2]; - - /*! - The origin of the virtual coordinate space expressed in terms of client - coordinates. Starts at (0,0) and each call to ScrollWindow accumulates - into it. Thus if the user scrolls the window right (thus causing the - contents to move left with respect to the client origin, the - application code (typically wxScrolledWindow) will be called with - dx of -something, for example -20. This is added to m_virtualOrigin - and thus m_virtualOrigin will be (-20,0) in this example. - */ - wxPoint m_virtualOrigin; -private: - wxWindowCocoaScrollView(); -}; - // ======================================================================== // wxDummyNSView // ======================================================================== @@ -417,6 +309,12 @@ WX_IMPLEMENT_GET_OBJC_CLASS(wxDummyNSView,NSView) // ======================================================================== // wxWindowCocoaHider +// NOTE: This class and method of hiding predates setHidden: support in +// the toolkit. The hack used here is to replace the view with a stand-in +// that will be subject to the usual Cocoa resizing rules. +// When possible (i.e. when running on 10.3 or higher) we make it hidden +// mostly as an optimization so Cocoa doesn't have to consider it when +// drawing or finding key views. // ======================================================================== wxWindowCocoaHider::wxWindowCocoaHider(wxWindow *owner) : m_owner(owner) @@ -427,6 +325,9 @@ wxWindowCocoaHider::wxWindowCocoaHider(wxWindow *owner) initWithFrame:[owner->GetNSViewForHiding() frame]]; [m_dummyNSView setAutoresizingMask: [owner->GetNSViewForHiding() autoresizingMask]]; AssociateNSView(m_dummyNSView); + + if([m_dummyNSView respondsToSelector:@selector(setHidden:)]) + [m_dummyNSView setHidden:YES]; } wxWindowCocoaHider::~wxWindowCocoaHider() @@ -985,7 +886,7 @@ void wxWindowCocoaScrollView::_wx_doScroller(NSScroller *sender) } wxScrollWinEvent event(commandType, scrollpos, orientation); event.SetEventObject(m_owner); - m_owner->GetEventHandler()->ProcessEvent(event); + m_owner->HandleWindowEvent(event); } void wxWindowCocoaScrollView::UpdateSizes() @@ -1010,8 +911,15 @@ void wxWindowCocoaScrollView::Cocoa_FrameChanged(void) wxLogTrace(wxTRACE_COCOA,wxT("wxWindowCocoaScrollView=%p::Cocoa_FrameChanged for wxWindow %p"), this, m_owner); wxSizeEvent event(m_owner->GetSize(), m_owner->GetId()); event.SetEventObject(m_owner); - m_owner->GetEventHandler()->ProcessEvent(event); - UpdateSizes(); + m_owner->HandleWindowEvent(event); + + /* If the view is not a native one then it's being managed by wx. In this case the control + may decide to change its virtual size and we must update the document view's size to + match. For native views the virtual size will never have been set so we do not want + to use it at all. + */ + if(!m_isNativeView) + UpdateSizes(); } // ======================================================================== @@ -1035,7 +943,6 @@ void wxWindowCocoa::Init() m_cocoaNSView = NULL; m_cocoaHider = NULL; m_wxCocoaScrollView = NULL; - m_isBeingDeleted = false; m_isInPaint = false; m_visibleTrackingRectManager = NULL; } @@ -1107,8 +1014,8 @@ void wxWindowCocoa::SetNSView(WX_NSView cocoaNSView) bool need_debug = cocoaNSView || m_cocoaNSView; if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [m_cocoaNSView=%p retainCount]=%d"),this,m_cocoaNSView,[m_cocoaNSView retainCount]); DisassociateNSView(m_cocoaNSView); - [cocoaNSView retain]; - [m_cocoaNSView release]; + wxGCSafeRetain(cocoaNSView); + wxGCSafeRelease(m_cocoaNSView); m_cocoaNSView = cocoaNSView; AssociateNSView(m_cocoaNSView); if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxWindowCocoa=%p::SetNSView [cocoaNSView=%p retainCount]=%d"),this,cocoaNSView,[cocoaNSView retainCount]); @@ -1157,7 +1064,7 @@ NSRect wxWindowCocoa::CocoaTransformWxToBounds(NSRect rectWx) WX_NSAffineTransform wxWindowCocoa::CocoaGetWxToBoundsTransform() { // TODO: Handle scrolling offset - NSAffineTransform *transform = wxDC::CocoaGetWxToBoundsTransform([GetNSView() isFlipped], [GetNSView() bounds].size.height); + NSAffineTransform *transform = wxCocoaDCImpl::CocoaGetWxToBoundsTransform([GetNSView() isFlipped], [GetNSView() bounds].size.height); return transform; } @@ -1191,7 +1098,7 @@ bool wxWindowCocoa::Cocoa_drawRect(const NSRect &rect) wxPaintEvent event(m_windowId); event.SetEventObject(this); - bool ret = GetEventHandler()->ProcessEvent(event); + bool ret = HandleWindowEvent(event); m_isInPaint = false; return ret; } @@ -1202,6 +1109,44 @@ void wxWindowCocoa::InitMouseEvent(wxMouseEvent& event, WX_NSEvent cocoaEvent) // Mouse events happen at the NSWindow level so we need to convert // into our bounds coordinates then convert to wx coordinates. NSPoint cocoaPoint = [m_cocoaNSView convertPoint:[(NSEvent*)cocoaEvent locationInWindow] fromView:nil]; + if( m_wxCocoaScrollView != NULL) + { + // This gets the wx client area (i.e. the visible portion of the content) in + // the coordinate system of our (the doucment) view. + NSRect documentVisibleRect = [[m_wxCocoaScrollView->GetNSScrollView() contentView] documentVisibleRect]; + // For horizontal, simply subtract the origin. + // e.g. if the origin is at 123 and the user clicks as far left as possible then + // the coordinate that wx wants is 0. + cocoaPoint.x -= documentVisibleRect.origin.x; + if([m_cocoaNSView isFlipped]) + { + // In the flipped view case this works exactly like horizontal. + cocoaPoint.y -= documentVisibleRect.origin.y; + } + // For vertical we have to mind non-flipped (e.g. y=0 at bottom) views. + // We also need to mind the fact that we're still in Cocoa coordinates + // and not wx coordinates. The wx coordinate translation will still occur + // and that is going to be wxY = boundsH - cocoaY for non-flipped views. + + // When we consider scrolling we are truly interested in how far the top + // edge of the bounds rectangle is scrolled off the screen. + // Assuming the bounds origin is 0 (which is an assumption we make in + // wxCocoa since wxWidgets has no analog to it) then the top edge of + // the bounds rectangle is simply its height. The top edge of the + // documentVisibleRect (e.g. the client area) is its height plus + // its origin. + // Thus, we simply need add the distance between the bounds top + // and the client (docuemntVisibleRect) top. + // Or putting it another way, we subtract the distance between the + // client top and the bounds top. + else + { + NSRect bounds = [m_cocoaNSView bounds]; + CGFloat scrollYOrigin = (bounds.size.height - (documentVisibleRect.origin.y + documentVisibleRect.size.height)); + cocoaPoint.y += scrollYOrigin; + } + } + NSPoint pointWx = CocoaTransformBoundsToWx(cocoaPoint); // FIXME: Should we be adjusting for client area origin? const wxPoint &clientorigin = GetClientAreaOrigin(); @@ -1223,7 +1168,7 @@ bool wxWindowCocoa::Cocoa_mouseMoved(WX_NSEvent theEvent) wxMouseEvent event(wxEVT_MOTION); InitMouseEvent(event,theEvent); wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::Cocoa_mouseMoved @%d,%d"),this,event.m_x,event.m_y); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } void wxWindowCocoa::Cocoa_synthesizeMouseMoved() @@ -1244,7 +1189,7 @@ void wxWindowCocoa::Cocoa_synthesizeMouseMoved() event.SetId(GetId()); wxLogTrace(wxTRACE_COCOA,wxT("wxwin=%p Synthesized Mouse Moved @%d,%d"),this,event.m_x,event.m_y); - GetEventHandler()->ProcessEvent(event); + HandleWindowEvent(event); } bool wxWindowCocoa::Cocoa_mouseEntered(WX_NSEvent theEvent) @@ -1262,7 +1207,7 @@ bool wxWindowCocoa::Cocoa_mouseEntered(WX_NSEvent theEvent) wxMouseEvent event(wxEVT_ENTER_WINDOW); InitMouseEvent(event,theEvent); wxLogTrace(wxTRACE_COCOA_TrackingRect,wxT("wxwin=%p Mouse Entered TR#%d @%d,%d"),this,[theEvent trackingNumber], event.m_x,event.m_y); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } else return false; @@ -1277,7 +1222,7 @@ bool wxWindowCocoa::Cocoa_mouseExited(WX_NSEvent theEvent) wxMouseEvent event(wxEVT_LEAVE_WINDOW); InitMouseEvent(event,theEvent); wxLogTrace(wxTRACE_COCOA_TrackingRect,wxT("wxwin=%p Mouse Exited TR#%d @%d,%d"),this,[theEvent trackingNumber],event.m_x,event.m_y); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } else return false; @@ -1288,7 +1233,7 @@ bool wxWindowCocoa::Cocoa_mouseDown(WX_NSEvent theEvent) wxMouseEvent event([theEvent clickCount]<2?wxEVT_LEFT_DOWN:wxEVT_LEFT_DCLICK); InitMouseEvent(event,theEvent); wxLogTrace(wxTRACE_COCOA,wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowCocoa::Cocoa_mouseDragged(WX_NSEvent theEvent) @@ -1297,7 +1242,7 @@ bool wxWindowCocoa::Cocoa_mouseDragged(WX_NSEvent theEvent) InitMouseEvent(event,theEvent); event.m_leftDown = true; wxLogTrace(wxTRACE_COCOA,wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowCocoa::Cocoa_mouseUp(WX_NSEvent theEvent) @@ -1305,7 +1250,7 @@ bool wxWindowCocoa::Cocoa_mouseUp(WX_NSEvent theEvent) wxMouseEvent event(wxEVT_LEFT_UP); InitMouseEvent(event,theEvent); wxLogTrace(wxTRACE_COCOA,wxT("Mouse Up @%d,%d"),event.m_x,event.m_y); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowCocoa::Cocoa_rightMouseDown(WX_NSEvent theEvent) @@ -1313,7 +1258,7 @@ bool wxWindowCocoa::Cocoa_rightMouseDown(WX_NSEvent theEvent) wxMouseEvent event([theEvent clickCount]<2?wxEVT_RIGHT_DOWN:wxEVT_RIGHT_DCLICK); InitMouseEvent(event,theEvent); wxLogDebug(wxT("Mouse Down @%d,%d num clicks=%d"),event.m_x,event.m_y,[theEvent clickCount]); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowCocoa::Cocoa_rightMouseDragged(WX_NSEvent theEvent) @@ -1322,7 +1267,7 @@ bool wxWindowCocoa::Cocoa_rightMouseDragged(WX_NSEvent theEvent) InitMouseEvent(event,theEvent); event.m_rightDown = true; wxLogDebug(wxT("Mouse Drag @%d,%d"),event.m_x,event.m_y); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowCocoa::Cocoa_rightMouseUp(WX_NSEvent theEvent) @@ -1330,7 +1275,7 @@ bool wxWindowCocoa::Cocoa_rightMouseUp(WX_NSEvent theEvent) wxMouseEvent event(wxEVT_RIGHT_UP); InitMouseEvent(event,theEvent); wxLogDebug(wxT("Mouse Up @%d,%d"),event.m_x,event.m_y); - return GetEventHandler()->ProcessEvent(event); + return HandleWindowEvent(event); } bool wxWindowCocoa::Cocoa_otherMouseDown(WX_NSEvent theEvent) @@ -1363,7 +1308,7 @@ void wxWindowCocoa::Cocoa_FrameChanged(void) m_visibleTrackingRectManager->RebuildTrackingRect(); wxSizeEvent event(GetSize(), m_windowId); event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + HandleWindowEvent(event); } else { @@ -1466,17 +1411,48 @@ bool wxWindow::Show(bool show) // If state isn't changing, return false if(!m_cocoaHider) return false; + + // Replace the stand-in view with the real one and destroy the dummy view CocoaReplaceView(m_cocoaHider->GetNSView(), cocoaView); wxASSERT(![m_cocoaHider->GetNSView() superview]); delete m_cocoaHider; m_cocoaHider = NULL; wxASSERT([cocoaView superview]); + + // Schedule an update of the key view loop (NOTE: 10.4+ only.. argh) + NSWindow *window = [cocoaView window]; + if(window != nil) + { + // Delay this until returning to the event loop for a couple of reasons: + // 1. If a lot of stuff is shown/hidden we avoid recalculating needlessly + // 2. NSWindow does not seem to see the newly shown views if we do it right now. + if([window respondsToSelector:@selector(recalculateKeyViewLoop)]) + [window performSelector:@selector(recalculateKeyViewLoop) withObject:nil afterDelay:0.0]; + } } else { // If state isn't changing, return false if(m_cocoaHider) return false; + + // Handle the first responder + NSWindow *window = [cocoaView window]; + if(window != nil) + { + NSResponder *firstResponder = [window firstResponder]; + if([firstResponder isKindOfClass:[NSView class]] && [(NSView*)firstResponder isDescendantOf:cocoaView]) + { + BOOL didResign = [window makeFirstResponder:nil]; + // If the current first responder (one of our subviews) refuses to give + // up its status, then fail now and don't hide this view + if(didResign == NO) + return false; + } + } + + // Create a new view to stand in for the real one (via wxWindowCocoaHider) and replace + // the real one with the stand in. m_cocoaHider = new wxWindowCocoaHider(this); // NOTE: replaceSubview:with will cause m_cocaNSView to be // (auto)released which balances out addSubview @@ -1744,7 +1720,7 @@ void wxWindow::GetTextExtent(const wxString& string, int *outX, int *outY, // transformations. However, it's better than nothing. // We don't create a wxClientDC because we don't want to accidently be able to use // it for drawing. - wxDC tmpdc; + wxClientDC tmpdc(const_cast(this)); return tmpdc.GetTextExtent(string, outX, outY, outDescent, outExternalLeading, inFont); } @@ -1841,7 +1817,7 @@ static char const * const comparisonresultStrings[] = class CocoaWindowCompareContext { - DECLARE_NO_COPY_CLASS(CocoaWindowCompareContext) + wxDECLARE_NO_COPY_CLASS(CocoaWindowCompareContext); public: CocoaWindowCompareContext(); // Not implemented CocoaWindowCompareContext(NSView *target, NSArray *subviews) @@ -2032,7 +2008,7 @@ wxWindow* wxFindWindowAtPointer(wxPoint& pt) */ class wxCocoaMouseMovedEventSynthesizer { - DECLARE_NO_COPY_CLASS(wxCocoaMouseMovedEventSynthesizer) + wxDECLARE_NO_COPY_CLASS(wxCocoaMouseMovedEventSynthesizer); public: wxCocoaMouseMovedEventSynthesizer() { m_lastScreenMouseLocation = NSZeroPoint;