]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/cocoa/window.mm
Added a proper log frame to the propgrid sample
[wxWidgets.git] / src / osx / cocoa / window.mm
index 274eb120992e17021bf206e762ef2dd3fd918a7a..a90434a622b368a67d6039223a86f1213d1a019f 100644 (file)
@@ -21,7 +21,7 @@
     #include "wx/osx/private.h"
 #endif
 
-#include "wx/hashmap.h"
+#include "wx/evtloop.h"
 
 #if wxUSE_CARET
     #include "wx/caret.h"
 
 #include <objc/objc-runtime.h>
 
-namespace
-{
-
-// stop animation of this window if one is in progress
-void StopAnimation(wxWindow *win);
-
-} // anonymous namespace
-
-
 // Get the window with the focus
 
 NSView* GetViewFromResponder( NSResponder* responder )
@@ -1180,8 +1171,6 @@ void wxWidgetCocoaImpl::Init()
 
 wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
 {
-    StopAnimation(m_wxPeer);
-
     RemoveAssociations( this );
 
     if ( !IsRootControl() )
@@ -1209,72 +1198,40 @@ void wxWidgetCocoaImpl::SetVisibility( bool visible )
 // window animation stuff
 // ----------------------------------------------------------------------------
 
-namespace
-{
-
-WX_DECLARE_VOIDPTR_HASH_MAP(NSViewAnimation *, wxNSViewAnimations);
-
-// all currently active animations
-//
-// this is MT-safe because windows can only be animated from the main
-// thread anyhow
-wxNSViewAnimations gs_activeAnimations;
-
-void StopAnimation(wxWindow *win)
-{
-    wxNSViewAnimations::iterator it = gs_activeAnimations.find(win);
-    if ( it != gs_activeAnimations.end() )
-    {
-        [it->second stopAnimation];
-    }
-}
-
-} // anonymous namespace
-
-// define a delegate used to detect the end of the window animation
-@interface wxNSAnimationDelegate : NSObject
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-                                   <NSAnimationDelegate>
-#endif
+// define a delegate used to refresh the window during animation
+@interface wxNSAnimationDelegate : NSObject wxOSX_10_6_AND_LATER(<NSAnimationDelegate>)
 {
-    // can't use wxRect here as it has a user-defined ctor and so can't be used
-    // as an Objective-C field
-    struct
-    {
-        int x, y, w, h;
-    } m_origRect;
     wxWindow *m_win;
-    bool m_show;
+    bool m_isDone;
 }
 
-- (id)initWithWindow:(wxWindow *)win show:(bool)show;
+- (id)init:(wxWindow *)win;
+
+- (bool)isDone;
 
 // NSAnimationDelegate methods
+- (void)animationDidEnd:(NSAnimation*)animation;
 - (void)animation:(NSAnimation*)animation
         didReachProgressMark:(NSAnimationProgress)progress;
-- (void)animationDidStop:(NSAnimation *)animation;
-- (void)animationDidEnd:(NSAnimation *)animation;
-
-// private helpers
-- (void)finishAnimation:(NSAnimation *)animation;
 @end
 
 @implementation wxNSAnimationDelegate
 
-- (id)initWithWindow:(wxWindow *)win show:(bool)show
+- (id)init:(wxWindow *)win
 {
     [super init];
 
     m_win = win;
-    m_show = show;
-    if ( !show )
-    {
-        m_win->GetPosition(&m_origRect.x, &m_origRect.y);
-        m_win->GetSize(&m_origRect.w, &m_origRect.h);
-    }
+    m_isDone = false;
+
     return self;
 }
 
+- (bool)isDone
+{
+    return m_isDone;
+}
+
 - (void)animation:(NSAnimation*)animation
         didReachProgressMark:(NSAnimationProgress)progress
 {
@@ -1284,49 +1241,9 @@ void StopAnimation(wxWindow *win)
     m_win->SendSizeEvent();
 }
 
-- (void)animationDidStop:(NSAnimation *)animation
-{
-    [self finishAnimation:animation];
-}
-
-- (void)animationDidEnd:(NSAnimation *)animation
+- (void)animationDidEnd:(NSAnimation*)animation
 {
-    [self finishAnimation:animation];
-}
-
-- (void)finishAnimation:(NSAnimation *)animation
-{
-    if ( m_show )
-    {
-        // the window expects to be sent a size event when it is shown normally
-        // and so it should also get one when it is shown with effect
-        m_win->SendSizeEvent();
-    }
-    else // window was being hidden
-    {
-        // NSViewAnimation is smart enough to hide the NSView itself but we
-        // also need to ensure that it's considered to be hidden at wx level
-        m_win->Hide();
-
-        // and we also need to restore its original size which was changed by
-        // the animation
-        m_win->SetSize(m_origRect.x, m_origRect.y, m_origRect.w, m_origRect.h);
-    }
-
-    wxNSViewAnimations::iterator it = gs_activeAnimations.find(m_win);
-    wxASSERT_MSG( it != gs_activeAnimations.end() && it->second == animation,
-                  "corrupted active animations list?" );
-
-    gs_activeAnimations.erase(it);
-
-    // we don't dare to release it immediately as we're called from its code
-    // but schedule the animation itself for deletion soon
-    [animation autorelease];
-
-    // ensure that this delegate is definitely not needed any more before
-    // destroying it
-    [animation setDelegate:nil];
-    [self release];
+    m_isDone = true;
 }
 
 @end
@@ -1338,13 +1255,6 @@ wxWidgetCocoaImpl::ShowViewOrWindowWithEffect(wxWindow *win,
                                               wxShowEffect effect,
                                               unsigned timeout)
 {
-    // first of all, check if this window is not being already animated and
-    // cancel the previous animation if it is as performing more than one
-    // animation on the same window at the same time results in some really
-    // unexpected effects
-    StopAnimation(win);
-
-
     // create the dictionary describing the animation to perform on this view
     NSObject * const
         viewOrWin = static_cast<NSObject *>(win->OSXGetViewOrWindow());
@@ -1353,10 +1263,11 @@ wxWidgetCocoaImpl::ShowViewOrWindowWithEffect(wxWindow *win,
     [dict setObject:viewOrWin forKey:NSViewAnimationTargetKey];
 
     // determine the start and end rectangles assuming we're hiding the window
+    const wxRect rectOrig = win->GetRect();
     wxRect rectStart,
            rectEnd;
     rectStart =
-    rectEnd = win->GetRect();
+    rectEnd = rectOrig;
 
     if ( show )
     {
@@ -1431,7 +1342,7 @@ wxWidgetCocoaImpl::ShowViewOrWindowWithEffect(wxWindow *win,
         // animation to be visible at all (but don't restore it at its full
         // rectangle as it shouldn't appear immediately)
         win->SetSize(rectStart);
-        win->Show(true);
+        win->Show();
     }
 
     NSView * const parentView = [viewOrWin isKindOfClass:[NSView class]]
@@ -1446,13 +1357,9 @@ wxWidgetCocoaImpl::ShowViewOrWindowWithEffect(wxWindow *win,
           forKey:NSViewAnimationEndFrameKey];
 
     // create an animation using the values in the above dictionary
-    //
-    // notice that it will be released when it is removed from
-    // gs_activeAnimations
     NSViewAnimation * const
         anim = [[NSViewAnimation alloc]
                 initWithViewAnimations:[NSArray arrayWithObject:dict]];
-    gs_activeAnimations[win] = anim;
 
     if ( !timeout )
     {
@@ -1472,9 +1379,47 @@ wxWidgetCocoaImpl::ShowViewOrWindowWithEffect(wxWindow *win,
     for ( float f = 1./NUM_LAYOUTS; f < 1.; f += 1./NUM_LAYOUTS )
         [anim addProgressMark:f];
 
-    [anim setDelegate:[[wxNSAnimationDelegate alloc] initWithWindow:win show:show]];
+    wxNSAnimationDelegate * const
+        animDelegate = [[wxNSAnimationDelegate alloc] init:win];
+    [anim setDelegate:animDelegate];
     [anim startAnimation];
 
+    // Cocoa is capable of doing animation asynchronously or even from separate
+    // thread but wx API doesn't provide any way to be notified about the
+    // animation end and without this we really must ensure that the window has
+    // the expected (i.e. the same as if a simple Show() had been used) size
+    // when we return, so block here until the animation finishes
+    //
+    // notice that because the default animation mode is NSAnimationBlocking,
+    // no user input events ought to be processed from here
+    {
+        wxEventLoopGuarantor ensureEventLoopExistence;
+        wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
+        while ( ![animDelegate isDone] )
+            loop->Dispatch();
+    }
+
+    if ( !show )
+    {
+        // NSViewAnimation is smart enough to hide the NSView being animated at
+        // the end but we also must ensure that it's hidden for wx too
+        win->Hide();
+
+        // and we must also restore its size because it isn't expected to
+        // change just because the window was hidden
+        win->SetSize(rectOrig);
+    }
+    else
+    {
+        // refresh it once again after the end to ensure that everything is in
+        // place
+        win->SendSizeEvent();
+    }
+
+    [anim setDelegate:nil];
+    [animDelegate release];
+    [anim release];
+
     return true;
 }
 
@@ -1735,6 +1680,7 @@ void wxWidgetCocoaImpl::SetBitmap( const wxBitmap& bitmap )
     if (  [m_osxView respondsToSelector:@selector(setImage:)] )
     {
         [m_osxView setImage:bitmap.GetNSImage()];
+        [m_osxView setNeedsDisplay:YES];
     }
 }