]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/nonownedwnd_osx.cpp
Fix horizontal mouse wheel scrolling in wxGTK.
[wxWidgets.git] / src / osx / nonownedwnd_osx.cpp
index 59905b824f711bb78fcf80de334fc105648ec3fb..0828348eb19af8f04d6a300e77b674be801a8cd9 100644 (file)
@@ -3,7 +3,6 @@
 // Purpose:     implementation of wxNonOwnedWindow
 // Author:      Stefan Csomor
 // Created:     2008-03-24
-// RCS-ID:      $Id: nonownedwnd.cpp 50329 2007-11-29 17:00:58Z VS $
 // Copyright:   (c) Stefan Csomor 2008
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -13,6 +12,8 @@
 
 #ifndef WX_PRECOMP
     #include "wx/app.h"
+    #include "wx/dcmemory.h"
+    #include "wx/log.h"
 #endif // WX_PRECOMP
 
 #include "wx/hashmap.h"
@@ -37,6 +38,8 @@
 
 wxWindow* g_MacLastWindow = NULL ;
 
+clock_t wxNonOwnedWindow::s_lastFlush = 0;
+
 // unified title and toolbar constant - not in Tiger headers, so we duplicate it here
 #define kWindowUnifiedTitleAndToolbarAttribute (1 << 7)
 
@@ -44,36 +47,30 @@ wxWindow* g_MacLastWindow = NULL ;
 // wxWindowMac utility functions
 // ---------------------------------------------------------------------------
 
-// Find an item given the Macintosh Window Reference
-
-WX_DECLARE_HASH_MAP(WXWindow, wxNonOwnedWindow*, wxPointerHash, wxPointerEqual, MacWindowMap);
+WX_DECLARE_HASH_MAP(WXWindow, wxNonOwnedWindowImpl*, wxPointerHash, wxPointerEqual, MacWindowMap);
 
 static MacWindowMap wxWinMacWindowList;
 
-wxNonOwnedWindow *wxFindWindowFromWXWindow(WXWindow inWindowRef)
+wxNonOwnedWindow* wxNonOwnedWindow::GetFromWXWindow( WXWindow win )
 {
-    MacWindowMap::iterator node = wxWinMacWindowList.find(inWindowRef);
+    wxNonOwnedWindowImpl* impl = wxNonOwnedWindowImpl::FindFromWXWindow(win);
 
-    return (node == wxWinMacWindowList.end()) ? NULL : node->second;
+    return ( impl != NULL ? impl->GetWXPeer() : NULL ) ;
 }
 
-void wxAssociateWindowWithWXWindow(WXWindow inWindowRef, wxNonOwnedWindow *win) ;
-void wxAssociateWindowWithWXWindow(WXWindow inWindowRef, wxNonOwnedWindow *win)
+wxNonOwnedWindowImpl* wxNonOwnedWindowImpl::FindFromWXWindow (WXWindow window)
 {
-    // adding NULL WindowRef is (first) surely a result of an error and
-    // nothing else :-)
-    wxCHECK_RET( inWindowRef != (WXWindow) NULL, wxT("attempt to add a NULL WindowRef to window list") );
+    MacWindowMap::iterator node = wxWinMacWindowList.find(window);
 
-    wxWinMacWindowList[inWindowRef] = win;
+    return (node == wxWinMacWindowList.end()) ? NULL : node->second;
 }
 
-void wxRemoveWXWindowAssociation(wxNonOwnedWindow *win) ;
-void wxRemoveWXWindowAssociation(wxNonOwnedWindow *win)
+void wxNonOwnedWindowImpl::RemoveAssociations( wxNonOwnedWindowImpl* impl)
 {
     MacWindowMap::iterator it;
     for ( it = wxWinMacWindowList.begin(); it != wxWinMacWindowList.end(); ++it )
     {
-        if ( it->second == win )
+        if ( it->second == impl )
         {
             wxWinMacWindowList.erase(it);
             break;
@@ -81,9 +78,13 @@ void wxRemoveWXWindowAssociation(wxNonOwnedWindow *win)
     }
 }
 
-wxNonOwnedWindow* wxNonOwnedWindow::GetFromWXWindow( WXWindow win )
+void wxNonOwnedWindowImpl::Associate( WXWindow window, wxNonOwnedWindowImpl *impl )
 {
-    return wxFindWindowFromWXWindow( win );
+    // adding NULL WindowRef is (first) surely a result of an error and
+    // nothing else :-)
+    wxCHECK_RET( window != (WXWindow) NULL, wxT("attempt to add a NULL WindowRef to window list") );
+
+    wxWinMacWindowList[window] = impl;
 }
 
 // ----------------------------------------------------------------------------
@@ -97,18 +98,16 @@ wxNonOwnedWindow *wxNonOwnedWindow::s_macDeactivateWindow = NULL;
 void wxNonOwnedWindow::Init()
 {
     m_nowpeer = NULL;
+    m_isNativeWindowWrapper = false;
 }
 
 bool wxNonOwnedWindow::Create(wxWindow *parent,
                                  wxWindowID id,
-                                 const wxPoint& pos,
-                                 const wxSize& size,
+                                 const wxPoint& posOrig,
+                                 const wxSize& sizeOrig,
                                  long style,
                                  const wxString& name)
 {
-    // init our fields
-    Init();
-
     m_windowStyle = style;
 
     SetName( name );
@@ -117,24 +116,37 @@ bool wxNonOwnedWindow::Create(wxWindow *parent,
     m_windowStyle = style;
     m_isShown = false;
 
-    // create frame.
-    int x = (int)pos.x;
-    int y = (int)pos.y;
-
-    wxRect display = wxGetClientDisplayRect() ;
+    // use the appropriate defaults for the position and size if necessary
+    wxSize size(sizeOrig);
+    if ( !size.IsFullySpecified() )
+        size.SetDefaults(wxTopLevelWindow::GetDefaultSize());
 
-    if ( x == wxDefaultPosition.x )
-        x = display.x ;
+    wxPoint pos(posOrig);
+    if ( !pos.IsFullySpecified() )
+    {
+        wxRect rectWin = wxRect(size).CentreIn(wxGetClientDisplayRect());
 
-    if ( y == wxDefaultPosition.y )
-        y = display.y ;
+        // The size of the window is often not really known yet, TLWs are often
+        // created with some small initial size and later are fitted to contain
+        // their children so centering the window will show it too much to the
+        // right and bottom, adjust for it by putting it more to the left and
+        // center.
+        rectWin.x /= 2;
+        rectWin.y /= 2;
 
-    int w = WidthDefault(size.x);
-    int h = HeightDefault(size.y);
+        pos.SetDefaults(rectWin.GetPosition());
+    }
 
-    m_nowpeer = wxNonOwnedWindowImpl::CreateNonOwnedWindow(this, parent, wxPoint(x,y) , wxSize(w,h) , style , GetExtraStyle(), name );
-    wxAssociateWindowWithWXWindow( m_nowpeer->GetWXWindow() , this ) ;
-    m_peer = wxWidgetImpl::CreateContentView(this);
+    // create frame.
+    m_nowpeer = wxNonOwnedWindowImpl::CreateNonOwnedWindow
+                (
+                    this, parent,
+                    pos , size,
+                    style, GetExtraStyle(),
+                    name
+                );
+    wxNonOwnedWindowImpl::Associate( m_nowpeer->GetWXWindow() , m_nowpeer ) ;
+    SetPeer(wxWidgetImpl::CreateContentView(this));
 
     DoSetWindowVariant( m_windowVariant ) ;
 
@@ -149,47 +161,97 @@ bool wxNonOwnedWindow::Create(wxWindow *parent,
     return true;
 }
 
+bool wxNonOwnedWindow::Create(wxWindow *parent, WXWindow nativeWindow)
+{
+    if ( parent )
+        parent->AddChild(this);
+
+    SubclassWin(nativeWindow);
+
+    return true;
+}
+
+void wxNonOwnedWindow::SubclassWin(WXWindow nativeWindow)
+{
+    wxASSERT_MSG( !m_isNativeWindowWrapper, wxT("subclassing window twice?") );
+    wxASSERT_MSG( m_nowpeer == NULL, wxT("window already was created") );
+
+    m_nowpeer = wxNonOwnedWindowImpl::CreateNonOwnedWindow(this, GetParent(), nativeWindow );
+    m_isNativeWindowWrapper = true;
+    wxNonOwnedWindowImpl::Associate( m_nowpeer->GetWXWindow() , m_nowpeer ) ;
+    SetPeer(wxWidgetImpl::CreateContentView(this));
+}
+
+void wxNonOwnedWindow::UnsubclassWin()
+{
+    wxASSERT_MSG( m_isNativeWindowWrapper, wxT("window was not subclassed") );
+
+    if ( GetParent() )
+        GetParent()->RemoveChild(this);
+
+    wxNonOwnedWindowImpl::RemoveAssociations(m_nowpeer) ;
+    wxDELETE(m_nowpeer);
+    SetPeer(NULL);
+    m_isNativeWindowWrapper = false;
+}
+
+
 wxNonOwnedWindow::~wxNonOwnedWindow()
 {
-    m_isBeingDeleted = true;
-    
-    wxRemoveWXWindowAssociation( this ) ;
-    
+    SendDestroyEvent();
+
+    wxNonOwnedWindowImpl::RemoveAssociations(m_nowpeer) ;
+
     DestroyChildren();
-    
-    delete m_nowpeer;
+
+    wxDELETE(m_nowpeer);
 
     // avoid dangling refs
     if ( s_macDeactivateWindow == this )
         s_macDeactivateWindow = NULL;
 }
 
+bool wxNonOwnedWindow::Destroy()
+{
+    WillBeDestroyed();
+
+    return wxWindow::Destroy();
+}
+
+void wxNonOwnedWindow::WillBeDestroyed()
+{
+    if ( m_nowpeer )
+        m_nowpeer->WillBeDestroyed();
+}
+
 // ----------------------------------------------------------------------------
 // wxNonOwnedWindow misc
 // ----------------------------------------------------------------------------
 
-bool wxNonOwnedWindow::ShowWithEffect(wxShowEffect effect,
-                                unsigned timeout )
-{ 
-    if ( !wxWindow::Show(true) )
+bool wxNonOwnedWindow::OSXShowWithEffect(bool show,
+                                         wxShowEffect effect,
+                                         unsigned timeout)
+{
+    // Cocoa code needs to manage window visibility on its own and so calls
+    // wxWindow::Show() as needed but if we already changed the internal
+    // visibility flag here, Show() would do nothing, so avoid doing it
+#if wxOSX_USE_CARBON
+    if ( !wxWindow::Show(show) )
         return false;
+#endif // Carbon
 
-    // because apps expect a size event to occur at this moment
-    wxSizeEvent event(GetSize() , m_windowId);
-    event.SetEventObject(this);
-    HandleWindowEvent(event);
-
+    if ( effect == wxSHOW_EFFECT_NONE ||
+            !m_nowpeer || !m_nowpeer->ShowWithEffect(show, effect, timeout) )
+        return Show(show);
 
-    return m_nowpeer->ShowWithEffect(true, effect, timeout); 
-}
-
-bool wxNonOwnedWindow::HideWithEffect(wxShowEffect effect,
-                                unsigned timeout )
-{ 
-    if ( !wxWindow::Show(false) )
-        return false;
+    if ( show )
+    {
+        // as apps expect a size event to occur when the window is shown,
+        // generate one when it is shown with effect too
+        SendSizeEvent();
+    }
 
-    return m_nowpeer->ShowWithEffect(false, effect, timeout); 
+    return true;
 }
 
 wxPoint wxNonOwnedWindow::GetClientAreaOrigin() const
@@ -200,17 +262,28 @@ wxPoint wxNonOwnedWindow::GetClientAreaOrigin() const
 }
 
 bool wxNonOwnedWindow::SetBackgroundColour(const wxColour& c )
-{        
+{
     if ( !wxWindow::SetBackgroundColour(c) && m_hasBgCol )
         return false ;
-    
+
     if ( GetBackgroundStyle() != wxBG_STYLE_CUSTOM )
     {
         if ( m_nowpeer )
             return m_nowpeer->SetBackgroundColour(c);
     }
     return true;
-}    
+}
+
+void wxNonOwnedWindow::SetWindowStyleFlag(long flags)
+{
+    if (flags == GetWindowStyleFlag())
+        return;
+
+    wxWindow::SetWindowStyleFlag(flags);
+
+    if (m_nowpeer)
+        m_nowpeer->SetWindowStyleFlag(flags);
+}
 
 // Raise the window to the top of the Z order
 void wxNonOwnedWindow::Raise()
@@ -233,18 +306,15 @@ void wxNonOwnedWindow::HandleActivated( double timestampsec, bool didActivate )
     HandleWindowEvent(wxevent);
 }
 
-void wxNonOwnedWindow::HandleResized( double timestampsec )
+void wxNonOwnedWindow::HandleResized( double WXUNUSED(timestampsec) )
 {
-    wxSizeEvent wxevent( GetSize() , GetId());
-    wxevent.SetTimestamp( (int) (timestampsec * 1000) );
-    wxevent.SetEventObject( this );
-    HandleWindowEvent(wxevent);
+    SendSizeEvent();
     // we have to inform some controls that have to reset things
     // relative to the toplevel window (e.g. OpenGL buffers)
     wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
 }
 
-void wxNonOwnedWindow::HandleResizing( double timestampsec, wxRect* rect )
+void wxNonOwnedWindow::HandleResizing( double WXUNUSED(timestampsec), wxRect* rect )
 {
     wxRect r = *rect ;
 
@@ -305,15 +375,13 @@ bool wxNonOwnedWindow::Show(bool show)
 
     if ( m_nowpeer )
         m_nowpeer->Show(show);
-    
+
     if ( show )
     {
         // because apps expect a size event to occur at this moment
-        wxSizeEvent event(GetSize() , m_windowId);
-        event.SetEventObject(this);
-        HandleWindowEvent(event);
+        SendSizeEvent();
     }
-    
+
     return true ;
 }
 
@@ -344,12 +412,15 @@ bool wxNonOwnedWindow::SetBackgroundStyle(wxBackgroundStyle style)
 {
     if ( !wxWindow::SetBackgroundStyle(style) )
         return false ;
-        
-    return m_nowpeer->SetBackgroundStyle(style);
+
+    return m_nowpeer ? m_nowpeer->SetBackgroundStyle(style) : true;
 }
 
 void wxNonOwnedWindow::DoMoveWindow(int x, int y, int width, int height)
 {
+    if ( m_nowpeer == NULL )
+        return;
+
     m_cachedClippedRectValid = false ;
 
     m_nowpeer->MoveWindow(x, y, width, height);
@@ -358,6 +429,9 @@ void wxNonOwnedWindow::DoMoveWindow(int x, int y, int width, int height)
 
 void wxNonOwnedWindow::DoGetPosition( int *x, int *y ) const
 {
+    if ( m_nowpeer == NULL )
+        return;
+
     int x1,y1 ;
     m_nowpeer->GetPosition(x1, y1);
 
@@ -369,8 +443,11 @@ void wxNonOwnedWindow::DoGetPosition( int *x, int *y ) const
 
 void wxNonOwnedWindow::DoGetSize( int *width, int *height ) const
 {
+    if ( m_nowpeer == NULL )
+        return;
+
     int w,h;
-    
+
     m_nowpeer->GetSize(w, h);
 
     if (width)
@@ -381,19 +458,37 @@ void wxNonOwnedWindow::DoGetSize( int *width, int *height ) const
 
 void wxNonOwnedWindow::DoGetClientSize( int *width, int *height ) const
 {
+    if ( m_nowpeer == NULL )
+        return;
+
     int left, top, w, h;
+    // under iphone with a translucent status bar the m_nowpeer returns the
+    // inner area, while the content area extends under the translucent
+    // status bar, therefore we use the content view's area
+#ifdef __WXOSX_IPHONE__
+    GetPeer()->GetContentArea(left, top, w, h);
+#else
     m_nowpeer->GetContentArea(left, top, w, h);
-
+#endif
+    
     if (width)
        *width = w ;
     if (height)
        *height = h ;
 }
 
+void wxNonOwnedWindow::WindowWasPainted()
+{
+    s_lastFlush = clock();
+}
 
 void wxNonOwnedWindow::Update()
 {
-    m_nowpeer->Update();
+    if ( clock() - s_lastFlush > CLOCKS_PER_SEC / 30 )
+    {
+        s_lastFlush = clock();
+        m_nowpeer->Update();
+    }
 }
 
 WXWindow wxNonOwnedWindow::GetWXWindow() const
@@ -405,23 +500,49 @@ WXWindow wxNonOwnedWindow::GetWXWindow() const
 // Shape implementation
 // ---------------------------------------------------------------------------
 
+bool wxNonOwnedWindow::DoClearShape()
+{
+    m_shape.Clear();
+
+    wxSize sz = GetClientSize();
+    wxRegion region(0, 0, sz.x, sz.y);
+
+    return m_nowpeer->SetShape(region);
+}
+
+bool wxNonOwnedWindow::DoSetRegionShape(const wxRegion& region)
+{
+    m_shape = region;
+
+    return m_nowpeer->SetShape(region);
+}
+
+#if wxUSE_GRAPHICS_CONTEXT
 
-bool wxNonOwnedWindow::SetShape(const wxRegion& region)
+#include "wx/scopedptr.h"
+
+bool wxNonOwnedWindow::DoSetPathShape(const wxGraphicsPath& path)
 {
-    wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
-                 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
+    m_shapePath = path;
+
+    // Convert the path to wxRegion by rendering the path on a window-sized
+    // bitmap, creating a mask from it and finally creating the region from
+    // this mask.
+    wxBitmap bmp(GetSize());
 
-    // The empty region signifies that the shape
-    // should be removed from the window.
-    if ( region.IsEmpty() )
     {
-        wxSize sz = GetClientSize();
-        wxRegion rgn(0, 0, sz.x, sz.y);
-        if ( rgn.IsEmpty() )
-            return false ;
-        else
-            return SetShape(rgn);
+        wxMemoryDC dc(bmp);
+        dc.SetBackground(*wxBLACK);
+        dc.Clear();
+
+        wxScopedPtr<wxGraphicsContext> context(wxGraphicsContext::Create(dc));
+        context->SetBrush(*wxWHITE);
+        context->FillPath(m_shapePath);
     }
 
-    return m_nowpeer->SetShape(region);
+    bmp.SetMask(new wxMask(bmp, *wxBLACK));
+
+    return DoSetRegionShape(wxRegion(bmp));
 }
+
+#endif // wxUSE_GRAPHICS_CONTEXT