]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/toplevel.cpp
Live resizing is OS X only.
[wxWidgets.git] / src / mac / toplevel.cpp
index b774abc5d0928587144e3f0386b61f596cfeb0d1..31cdcb791300aae2b2dbca5573377545a77f68fa 100644 (file)
@@ -1,11 +1,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Name:        mac/toplevel.cpp
-// Purpose:     implements wxTopLevelWindow for MSW
-// Author:      Vadim Zeitlin
+// Purpose:     implements wxTopLevelWindow for Mac
+// Author:      Stefan Csomor
 // Modified by:
 // Created:     24.09.01
 // RCS-ID:      $Id$
-// Copyright:   (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
+// Copyright:   (c) 2001-2004 Stefan Csomor
 // License:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -42,6 +42,9 @@
 #include "wx/app.h"
 #include "wx/tooltip.h"
 #include "wx/dnd.h"
+#if wxUSE_SYSTEM_OPTIONS
+    #include "wx/sysopt.h"
+#endif
 
 #include "ToolUtils.h"
 
@@ -97,6 +100,7 @@ static const EventTypeSpec eventList[] =
 
     { kEventClassMouse , kEventMouseDown } ,
     { kEventClassMouse , kEventMouseUp } ,
+    { kEventClassMouse , kEventMouseWheelMoved } ,
     { kEventClassMouse , kEventMouseMoved } ,
     { kEventClassMouse , kEventMouseDragged } ,
 
@@ -176,15 +180,17 @@ static pascal OSStatus KeyboardEventHandler( EventHandlerCallRef handler , Event
     {
         case kEventRawKeyRepeat :
         case kEventRawKeyDown :
-            WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
-            WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
-            wxTheApp->MacSetCurrentEvent( event , handler ) ;
-            if ( (focus != NULL) && wxTheApp->MacSendKeyDownEvent(
-                focus , message , modifiers , when , point.h , point.v ) )
             {
-                result = noErr ;
+                WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
+                WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
+                wxTheApp->MacSetCurrentEvent( event , handler ) ;
+                if ( (focus != NULL) && wxTheApp->MacSendKeyDownEvent(
+                    focus , message , modifiers , when , point.h , point.v ) )
+                {
+                    result = noErr ;
+                }
+                wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
             }
-            wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
             break ;
         case kEventRawKeyUp :
             if ( (focus != NULL) && wxTheApp->MacSendKeyUpEvent(
@@ -240,7 +246,7 @@ static pascal OSStatus KeyboardEventHandler( EventHandlerCallRef handler , Event
     return result ;
 }
 
-static pascal OSStatus MouseEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
+pascal OSStatus MouseEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
 {
     OSStatus result = eventNotHandledErr ;
 
@@ -262,10 +268,18 @@ static pascal OSStatus MouseEventHandler( EventHandlerCallRef handler , EventRef
     if ( button == 0 || GetEventKind( event ) == kEventMouseUp )
         modifiers += btnState ;
 
+       // temporary hack to support true two button mouse
+       if ( button == kEventMouseButtonSecondary )
+       {
+               modifiers |= controlKey ;
+       }
     WindowRef window ;
     short windowPart = ::FindWindow(point, &window);
 
-    if ( IsWindowActive(window) && windowPart == inContent )
+    // either we really are active or we are capturing mouse events
+
+    if ( (IsWindowActive(window) && windowPart == inContent) || 
+        (wxTheApp->s_captureWindow && wxTheApp->s_captureWindow->MacGetTopLevelWindow() == toplevelWindow) )
     {
         switch ( GetEventKind( event ) )
         {
@@ -278,13 +292,46 @@ static pascal OSStatus MouseEventHandler( EventHandlerCallRef handler , EventRef
                 result = noErr ;
                 break ;
             case kEventMouseMoved :
-                toplevelWindow->MacFireMouseEvent( nullEvent , point.h , point.v , modifiers , EventTimeToTicks( GetEventTime( event ) ) ) ;
+                wxTheApp->MacHandleMouseMovedEvent( point.h , point.v , modifiers , EventTimeToTicks( GetEventTime( event ) ) ) ;
                 result = noErr ;
                 break ;
             case kEventMouseDragged :
                 toplevelWindow->MacFireMouseEvent( nullEvent , point.h , point.v , modifiers , EventTimeToTicks( GetEventTime( event ) ) ) ;
                 result = noErr ;
                 break ;
+            case kEventMouseWheelMoved :
+                {
+                    //bClearTooltip = false;
+                    EventMouseWheelAxis axis = kEventMouseWheelAxisY;
+                    SInt32 delta = 0;
+                    Point mouseLoc = {0, 0};
+                    if (::GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis,
+                                        NULL, sizeof(EventMouseWheelAxis), NULL, &axis) == noErr &&
+                        ::GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger,
+                                        NULL, sizeof(SInt32), NULL, &delta) == noErr &&
+                        ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint,
+                                        NULL, sizeof(Point), NULL, &mouseLoc) == noErr)
+                    {
+                        wxMouseEvent wheelEvent(wxEVT_MOUSEWHEEL);
+                       
+                        wheelEvent.m_x = mouseLoc.h;
+                        wheelEvent.m_y = mouseLoc.v;
+                       
+                        wheelEvent.m_wheelRotation = delta;
+                        wheelEvent.m_wheelDelta = 1;
+                        wheelEvent.m_linesPerAction = 1;
+
+                        wxWindow* currentMouseWindow = NULL;
+                        wxWindow::MacGetWindowFromPoint(wxPoint(mouseLoc.h, mouseLoc.v), &currentMouseWindow);
+                       
+                        if (currentMouseWindow)
+                        {
+                            currentMouseWindow->GetEventHandler()->ProcessEvent(wheelEvent);
+                            result = noErr;
+                        }
+                    }
+                }
+                break ;
             default :
                 break ;
         }
@@ -352,30 +399,27 @@ static pascal OSStatus WindowEventHandler( EventHandlerCallRef handler , EventRe
                 GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL,
                     sizeof( newContentRect ), NULL, &newContentRect );
 
-                wxRect contentRect(newContentRect.left , newContentRect.top ,
-                    newContentRect.right - newContentRect.left ,
-                    newContentRect.bottom - newContentRect.top) ;
+                wxSize formerSize = toplevelWindow->GetSize() ;
 
-                bool handled = false ;
-                if ((attributes & kWindowBoundsChangeSizeChanged) != 0)
-                {
-                    wxSizeEvent event(contentRect , toplevelWindow->GetId());
-                    event.SetEventObject(toplevelWindow);
-                    handled = toplevelWindow->GetEventHandler()->ProcessEvent(event);
-                    contentRect = event.GetRect() ;
-                }
-                else if ( attributes & kWindowBoundsChangeOriginChanged != 0)
-                {
-                    wxMoveEvent event(contentRect , toplevelWindow->GetId());
-                    event.SetEventObject(toplevelWindow);
-                    handled = toplevelWindow->GetEventHandler()->ProcessEvent(event);
-                    contentRect = event.GetRect() ;
-                }
-                if ( handled )
+                if ( (attributes & kWindowBoundsChangeSizeChanged ) || 
+                    ( attributes & kWindowBoundsChangeOriginChanged ) )
+                    toplevelWindow->SetSize( newContentRect.left , newContentRect.top ,
+                        newContentRect.right - newContentRect.left ,
+                        newContentRect.bottom - newContentRect.top, wxSIZE_USE_EXISTING);
+    
+                int x , y , w , h ;
+                toplevelWindow->GetPosition( &x , &y ) ;
+                toplevelWindow->GetSize( &w , &h ) ;
+                Rect adjustedRect  = { y , x , y + h , x + w } ;
+
+                if ( !EqualRect( &newContentRect , &adjustedRect ) )
                 {
-                    SetRect( &newContentRect , contentRect.GetLeft() , contentRect.GetTop() , contentRect.GetRight() , contentRect.GetBottom() ) ;
-                    SetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, sizeof( newContentRect ), &newContentRect );
+                    SetEventParameter( event , kEventParamCurrentBounds , typeQDRectangle, sizeof( adjustedRect ) , &adjustedRect ) ;
                 }
+                
+                if ( toplevelWindow->GetSize() != formerSize )
+                    toplevelWindow->Update() ;
+        
                 result = noErr ;
             }
             break ;
@@ -422,6 +466,8 @@ DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler )
 wxList *wxWinMacWindowList = NULL;
 wxTopLevelWindowMac *wxFindWinFromMacWindow(WXWindow inWindowRef)
 {
+    if ( wxWinMacWindowList == NULL )
+        return NULL ;
     wxNode *node = wxWinMacWindowList->Find((long)inWindowRef);
     if (!node)
         return NULL;
@@ -450,6 +496,7 @@ void wxRemoveMacWindowAssociation(wxTopLevelWindowMac *win)
 
 WXHWND wxTopLevelWindowMac::s_macWindowInUpdate = NULL;
 wxTopLevelWindowMac *wxTopLevelWindowMac::s_macDeactivateWindow = NULL;
+bool wxTopLevelWindowMac::s_macWindowCompositing = FALSE;
 
 void wxTopLevelWindowMac::Init()
 {
@@ -458,6 +505,7 @@ void wxTopLevelWindowMac::Init()
     m_macNoEraseUpdateRgn = NewRgn() ;
     m_macNeedsErasing = false ;
     m_macWindow = NULL ;
+    m_macUsesCompositing = FALSE ;
 #if TARGET_CARBON
     m_macEventHandler = NULL ;
  #endif
@@ -534,6 +582,8 @@ wxTopLevelWindowMac::~wxTopLevelWindowMac()
 
 void wxTopLevelWindowMac::Maximize(bool maximize)
 {
+    wxMacPortStateHelper help( (GrafPtr) GetWindowPort( (WindowRef) m_macWindow) ) ;
+    wxMacWindowClipper clip (this);
     ZoomWindow( (WindowRef)m_macWindow , maximize ? inZoomOut : inZoomIn , false ) ;
 
     Rect tempRect ;
@@ -677,13 +727,34 @@ void  wxTopLevelWindowMac::MacCreateRealWindow( const wxString& title,
         attr |= kWindowCloseBoxAttribute ;
     }
 
+    if (UMAGetSystemVersion() >= 0x1000)
+    {
+        //turn on live resizing (OS X only)
+        attr |= kWindowLiveResizeAttribute;
+    }
+
 #if TARGET_CARBON
 #if 0 //  having problems right now with that
     if (HasFlag(wxSTAY_ON_TOP))
-       wclass = kUtilityWindowClass;
+        wclass = kUtilityWindowClass;
 #endif
 #endif
 
+    //this setup lets us have compositing and non-compositing 
+    //windows in the same application. 
+  
+#if UNIVERSAL_INTERFACES_VERSION >= 0x0400  
+    if ( wxTopLevelWindowMac::s_macWindowCompositing )
+    {
+        attr |= kWindowCompositingAttribute;
+        m_macUsesCompositing = TRUE;
+    }
+    else
+#endif
+    {
+        m_macUsesCompositing = FALSE;
+    }
+    
 #if TARGET_CARBON
     if ( HasFlag(wxFRAME_SHAPED) )
     {
@@ -704,7 +775,14 @@ void  wxTopLevelWindowMac::MacCreateRealWindow( const wxString& title,
     wxCHECK_RET( err == noErr, wxT("Mac OS error when trying to create new window") );
     wxAssociateWinWithMacWindow( m_macWindow , this ) ;
     UMASetWTitle( (WindowRef)m_macWindow , title ) ;
-    ::CreateRootControl( (WindowRef)m_macWindow , (ControlHandle*)&m_macRootControl ) ;
+    if ( wxTopLevelWindowMac::s_macWindowCompositing )
+    {
+        ::GetRootControl( (WindowRef)m_macWindow, (ControlHandle*)&m_macRootControl ) ;
+    }
+    else
+    {
+        ::CreateRootControl( (WindowRef)m_macWindow , (ControlHandle*)&m_macRootControl ) ;
+    }
 #if TARGET_CARBON
     InstallStandardEventHandler( GetWindowEventTarget(MAC_WXHWND(m_macWindow)) ) ;
     InstallWindowEventHandler(MAC_WXHWND(m_macWindow), GetwxMacWindowEventHandlerUPP(),
@@ -721,6 +799,16 @@ void  wxTopLevelWindowMac::MacCreateRealWindow( const wxString& title,
         SetShape(rgn);
     }
 #endif
+
+    wxWindowCreateEvent event(this);
+    GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxTopLevelWindowMac::MacEnableCompositing( bool useCompositing )
+{
+    bool oldval = s_macWindowCompositing;
+    s_macWindowCompositing = useCompositing; 
+    return oldval; 
 }
 
 void wxTopLevelWindowMac::MacGetPortParams(WXPOINTPTR localOrigin, WXRECTPTR clipRect, WXHWND *window  , wxWindowMac** rootwin)
@@ -955,7 +1043,8 @@ void wxTopLevelWindowMac::MacDelayedDeactivation(long timestamp)
 
 void wxTopLevelWindowMac::MacActivate( long timestamp , bool inIsActivating )
 {
-    wxLogDebug(wxT("TopLevel=%p::MacActivate"),this);
+    // wxLogDebug(wxT("TopLevel=%p::MacActivate"),this);
+
     if(s_macDeactivateWindow==this)
         s_macDeactivateWindow=NULL;
     MacDelayedDeactivation(timestamp);
@@ -1003,18 +1092,36 @@ bool wxTopLevelWindowMac::Show(bool show)
 
     if (show)
     {
-      ::TransitionWindow((WindowRef)m_macWindow,kWindowZoomTransitionEffect,kWindowShowTransitionAction,nil);
-      ::SelectWindow( (WindowRef)m_macWindow ) ;
-      // no need to generate events here, they will get them triggered by macos
-      // actually they should be , but apparently they are not
-      wxSize size(m_width, m_height);
-      wxSizeEvent event(size, m_windowId);
-      event.SetEventObject(this);
-      GetEventHandler()->ProcessEvent(event);
+        #if wxUSE_SYSTEM_OPTIONS       //code contributed by Ryan Wilcox December 18, 2003
+        if ( (wxSystemOptions::HasOption(wxMAC_WINDOW_PLAIN_TRANSITION) ) && ( wxSystemOptions::GetOptionInt( wxMAC_WINDOW_PLAIN_TRANSITION ) == 1) )
+        {
+           ::ShowWindow( (WindowRef)m_macWindow );
+        }
+        else
+        #endif
+        {
+           ::TransitionWindow((WindowRef)m_macWindow,kWindowZoomTransitionEffect,kWindowShowTransitionAction,nil);
+        }
+        ::SelectWindow( (WindowRef)m_macWindow ) ;
+        // no need to generate events here, they will get them triggered by macos
+        // actually they should be , but apparently they are not
+        wxSize size(m_width, m_height);
+        wxSizeEvent event(size, m_windowId);
+        event.SetEventObject(this);
+        GetEventHandler()->ProcessEvent(event);
     }
     else
     {
-      ::TransitionWindow((WindowRef)m_macWindow,kWindowZoomTransitionEffect,kWindowHideTransitionAction,nil);
+        #if wxUSE_SYSTEM_OPTIONS
+        if ( (wxSystemOptions::HasOption(wxMAC_WINDOW_PLAIN_TRANSITION) ) && ( wxSystemOptions::GetOptionInt( wxMAC_WINDOW_PLAIN_TRANSITION ) == 1) )
+        {
+           ::HideWindow((WindowRef) m_macWindow );
+        }
+        else
+        #endif
+        {
+           ::TransitionWindow((WindowRef)m_macWindow,kWindowZoomTransitionEffect,kWindowHideTransitionAction,nil);
+        }
     }
 
     if ( !show )
@@ -1030,6 +1137,9 @@ bool wxTopLevelWindowMac::Show(bool show)
 
 void wxTopLevelWindowMac::DoMoveWindow(int x, int y, int width, int height)
 {
+    wxMacPortStateHelper help( (GrafPtr) GetWindowPort( (WindowRef) m_macWindow) ) ;
+    wxMacWindowClipper clip (this);
+
     int former_x = m_x ;
     int former_y = m_y ;
     int former_w = m_width ;
@@ -1065,27 +1175,32 @@ void wxTopLevelWindowMac::DoMoveWindow(int x, int y, int width, int height)
     {
         m_x = actualX ;
         m_y = actualY ;
-        m_width = actualWidth ;
-        m_height = actualHeight ;
 
         if ( doMove )
             ::MoveWindow((WindowRef)m_macWindow, m_x, m_y  , false); // don't make frontmost
 
+        m_width = actualWidth ;
+        m_height = actualHeight ;
+
         if ( doResize )
             ::SizeWindow((WindowRef)m_macWindow, m_width, m_height  , true);
 
         // the OS takes care of invalidating and erasing the new area so we only have to
         // take care of refreshing for full repaints
 
-        if ( doResize && !HasFlag(wxNO_FULL_REPAINT_ON_RESIZE) )
+        if ( doResize && HasFlag(wxFULL_REPAINT_ON_RESIZE) )
             Refresh() ;
 
 
         if ( IsKindOf( CLASSINFO( wxFrame ) ) )
         {
             wxFrame* frame = (wxFrame*) this ;
+#if wxUSE_STATUSBAR
             frame->PositionStatusBar();
+#endif            
+#if wxUSE_TOOLBAR
             frame->PositionToolBar();
+#endif            
         }
         if ( doMove )
             wxWindowMac::MacTopLevelWindowChangedPosition() ; // like this only children will be notified