X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a4ee505901f1e38b3673f7f4b608f98d45f07445..a2e50fc2abd2d544ca2d2a884067bcd2e3b4b35b:/src/cocoa/window.mm diff --git a/src/cocoa/window.mm b/src/cocoa/window.mm index 0412529830..5b54eb71a4 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 @@ -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(); } // ======================================================================== @@ -1107,8 +1015,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 +1065,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 +1099,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; } @@ -1261,7 +1169,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() @@ -1282,7 +1190,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) @@ -1300,7 +1208,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; @@ -1315,7 +1223,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; @@ -1326,7 +1234,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) @@ -1335,7 +1243,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) @@ -1343,7 +1251,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) @@ -1351,7 +1259,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) @@ -1360,7 +1268,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) @@ -1368,7 +1276,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) @@ -1401,7 +1309,7 @@ void wxWindowCocoa::Cocoa_FrameChanged(void) m_visibleTrackingRectManager->RebuildTrackingRect(); wxSizeEvent event(GetSize(), m_windowId); event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + HandleWindowEvent(event); } else { @@ -1504,17 +1412,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 @@ -1782,7 +1721,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); }