]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/mediactrl.cpp
use wxString::Format(), calling string.Format() has no effect patch 1267345)
[wxWidgets.git] / src / mac / carbon / mediactrl.cpp
index 506f104b5069a70508c3e6556a25ae554630e35e..d2eb4c053f6e567ba233ce85d3b92c6047bc6876 100644 (file)
@@ -1,17 +1,25 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        mac/carbon/moviectrl.cpp
-// Purpose:     wxMediaCtrl MAC CARBON QT
+// Name:        mac/carbon/mediactrl.cpp
+// Purpose:     Built-in Media Backends for Mac
 // Author:      Ryan Norton <wxprojects@comcast.net>
-// Modified by: 
+// Modified by:
 // Created:     11/07/04
 // RCS-ID:      $Id$
-// Copyright:   (c) Ryan Norton
+// Copyright:   (c) 2004-2005 Ryan Norton, portions (c) 2004 Kevin Olliver
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-//#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-//#pragma implementation "moviectrl.h"
-//#endif
+//===========================================================================
+//  DECLARATIONS
+//===========================================================================
+
+//---------------------------------------------------------------------------
+// Pre-compiled header stuff
+//---------------------------------------------------------------------------
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma implementation "mediactrl.h"
+#endif
 
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 #pragma hdrstop
 #endif
 
-#include "wx/defs.h"
+//---------------------------------------------------------------------------
+// Includes
+//---------------------------------------------------------------------------
+#include "wx/mediactrl.h"
 
+//---------------------------------------------------------------------------
+// Compilation guard
+//---------------------------------------------------------------------------
 #if wxUSE_MEDIACTRL
 
-#include "wx/mac/carbon/mediactrl.h"
+//---------------------------------------------------------------------------
+// Whether or not to use OSX 10.2's CreateMovieControl for native QuickTime
+// control - i.e. native positioning and event handling etc..
+//---------------------------------------------------------------------------
+#ifndef wxUSE_CREATEMOVIECONTROL
+#    if defined( __WXMAC_OSX__ ) && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
+#        define wxUSE_CREATEMOVIECONTROL 1
+#    else
+#        define wxUSE_CREATEMOVIECONTROL 0
+#    endif
+#endif
 
-#include "wx/timer.h"
+//===========================================================================
+//  BACKEND DECLARATIONS
+//===========================================================================
 
-IMPLEMENT_CLASS(wxMediaCtrl, wxControl);
-IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent, wxEvent); 
-DEFINE_EVENT_TYPE(wxEVT_MEDIA_FINISHED); 
+//---------------------------------------------------------------------------
+//
+//  wxQTMediaBackend
+//
+//---------------------------------------------------------------------------
 
+//---------------------------------------------------------------------------
+//  QT Includes
+//---------------------------------------------------------------------------
 //uma is for wxMacFSSpec
-#ifdef __WXMAC__
 #include "wx/mac/uma.h"
+#include "wx/timer.h"
+#ifndef __DARWIN__
 #include <Movies.h>
 #include <Gestalt.h>
+#include <QuickTimeComponents.h>    //Standard QT stuff
 #else
-//quicktime media layer for mac emulation on pc
-#include <qtml.h>
+#include <QuickTime/QuickTimeComponents.h>
 #endif
 
-#include <QuickTimeComponents.h>
+//Determines whether version 4 of QT is installed (Pretty much for classic only)
+Boolean _wxIsQuickTime4Installed (void)
+{
+    short error;
+    long result;
+
+    error = Gestalt (gestaltQuickTime, &result);
+    return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0400);
+}
+
+class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
+{
+public:
+
+    wxQTMediaBackend();
+    ~wxQTMediaBackend();
+
+    virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
+                                     wxWindowID id,
+                                     const wxPoint& pos,
+                                     const wxSize& size,
+                                     long style,
+                                     const wxValidator& validator,
+                                     const wxString& name);
+
+    virtual bool Play();
+    virtual bool Pause();
+    virtual bool Stop();
+
+    virtual bool Load(const wxString& fileName);
+    virtual bool Load(const wxURI& location);
+
+    virtual wxMediaState GetState();
+
+    virtual bool SetPosition(wxLongLong where);
+    virtual wxLongLong GetPosition();
+    virtual wxLongLong GetDuration();
 
-#ifdef __WXMAC__
-#define MSWMOVIECHECK
+    virtual void Move(int x, int y, int w, int h);
+    wxSize GetVideoSize() const;
+
+    virtual double GetPlaybackRate();
+    virtual bool SetPlaybackRate(double dRate);
+
+    virtual double GetVolume();
+    virtual bool SetVolume(double);
+
+    void Cleanup();
+    void FinishLoad();
+
+    wxSize m_bestSize;              //Original movie size
+#ifdef __WXMAC_OSX__
+    struct MovieType** m_movie;     //QT Movie handle/instance
 #else
-#define MSWMOVIECHECK if(!m_bLoaded) return 0;
+    Movie m_movie ;
 #endif
+    wxControl* m_ctrl;              //Parent control
+    bool m_bVideo;                  //Whether or not we have video
+    class _wxQTTimer* m_timer;      //Timer for streaming the movie
+
+    DECLARE_DYNAMIC_CLASS(wxQTMediaBackend)
+};
+
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// wxQTMediaBackend
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
 
 //Time between timer calls
-#define MOVIE_DELAY 50
+#define MOVIE_DELAY 100
 
-// ------------------------------------------------------------------
+// --------------------------------------------------------------------------
 //          wxQTTimer - Handle Asyncronous Playing
-// ------------------------------------------------------------------
+// --------------------------------------------------------------------------
 class _wxQTTimer : public wxTimer
 {
 public:
-    _wxQTTimer(Movie movie, wxMediaCtrl* parent) :
+    _wxQTTimer(Movie movie, wxQTMediaBackend* parent) :
         m_movie(movie), m_bPaused(false), m_parent(parent)
     {
     }
@@ -71,140 +167,152 @@ public:
     bool GetPaused() {return m_bPaused;}
     void SetPaused(bool bPaused) {m_bPaused = bPaused;}
 
+    //-----------------------------------------------------------------------
+    // _wxQTTimer::Notify
+    //
+    // 1) Checks to see if the movie is done, and if not continues
+    //    streaming the movie
+    // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
+    //    the movie.
+    //-----------------------------------------------------------------------
     void Notify()
     {
         if (!m_bPaused)
         {
             if(!IsMovieDone(m_movie))
-                MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
+                MoviesTask(m_movie, MOVIE_DELAY);
             else
             {
-                Stop();
-                m_parent->Stop();
-                wxASSERT(::GetMoviesError() == noErr);
-                wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED, m_parent->GetId());
-                m_parent->GetParent()->ProcessEvent(theEvent);
+                wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
+                                      m_parent->m_ctrl->GetId());
+                m_parent->m_ctrl->ProcessEvent(theEvent);
+
+                if(theEvent.IsAllowed())
+                {
+                    Stop();
+                    m_parent->Stop();
+                    wxASSERT(::GetMoviesError() == noErr);
+
+                    //send the event to our child
+                    wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
+                                          m_parent->m_ctrl->GetId());
+                    m_parent->m_ctrl->ProcessEvent(theEvent);
+                }
             }
         }
     }
 
 protected:
-    Movie m_movie;
-    bool m_bPaused;
-    wxMediaCtrl* m_parent;
+    Movie m_movie;                  //Our movie instance
+    bool m_bPaused;                 //Whether we are paused or not
+    wxQTMediaBackend* m_parent;     //Backend pointer
 };
 
-//Determines whether version 6 of QT is installed
-Boolean _wxIsQuickTime4Installed (void)
+//---------------------------------------------------------------------------
+// wxQTMediaBackend Constructor
+//
+// Sets m_timer to NULL signifying we havn't loaded anything yet
+//---------------------------------------------------------------------------
+wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
 {
-#ifdef __WXMAC__
-    short error;
-    long result;
-
-    error = Gestalt (gestaltQuickTime, &result);
-    return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0400);
-#else
-    return true;
-#endif
 }
 
-bool wxMediaCtrl::InitQT ()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend Destructor
+//
+// 1) Cleans up the QuickTime movie instance
+// 2) Decrements the QuickTime reference counter - if this reaches
+//    0, QuickTime shuts down
+// 3) Decrements the QuickTime Windows Media Layer reference counter -
+//    if this reaches 0, QuickTime shuts down the Windows Media Layer
+//---------------------------------------------------------------------------
+wxQTMediaBackend::~wxQTMediaBackend()
 {
-    if (_wxIsQuickTime4Installed())
-    {
-        #ifndef __WXMAC__
-        int nError;
-        //-2093 no dll
-            if ((nError = InitializeQTML(0)) != noErr)
-            {
-                wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
-            }
-        #endif
-        EnterMovies();
-        return true;
-    }
-    else
-    {
-        wxFAIL_MSG(wxT("Quicktime is not installed, or Your Version of Quicktime is <= 4."));
-        return false;
-    }
-}
-
-bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id, const wxString& fileName, 
-                         const wxPoint& pos, const wxSize& size, 
-                         long style, long WXUNUSED(driver), const wxString& name)
-{
-    if(!DoCreate(parent, id, pos, size, style, name))
-        return false;
-
-    if(!fileName.empty())
-    {
-        if (!Load(fileName))
-            return false;
-
-        if(!Play())
-            return false;
-    }
+    if(m_timer)
+        Cleanup();
 
-    return true;
+    //Note that ExitMovies() is not necessary...
+    ExitMovies();
 }
 
-bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id, const wxURI& location, 
-                         const wxPoint& pos, const wxSize& size, 
-                         long style, long WXUNUSED(driver), const wxString& name)
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::CreateControl
+//
+// 1) Intializes QuickTime
+// 2) Creates the control window
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
+                                     wxWindowID id,
+                                     const wxPoint& pos,
+                                     const wxSize& size,
+                                     long style,
+                                     const wxValidator& validator,
+                                     const wxString& name)
 {
-    if(!DoCreate(parent, id, pos, size, style, name))
+    //Don't bother in Native control mode
+#if defined( __WXMAC__ ) && TARGET_API_MAC_OSX && ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_2 )
+    if (!_wxIsQuickTime4Installed())
         return false;
-    
-    if(!location.IsReference())
-    {
-        if (!Load(location))
-            return false;
-
-        if(!Play())
-            return false;
-    }
-
-    return true;
-}
+#endif
 
-bool wxMediaCtrl::DoCreate(wxWindow* parent, wxWindowID id, 
-                         const wxPoint& pos, const wxSize& size, 
-                         long style, const wxString& name)
-{
-     //do some window stuff
-    if ( !wxControl::Create(parent, id, pos, size, 
-#ifdef __WXMAC__
-                            MacRemoveBordersFromStyle(style), 
+    EnterMovies();
+
+    //
+    // Create window
+    // By default wxWindow(s) is created with a border -
+    // so we need to get rid of those
+    //
+    // Since we don't have a child window like most other
+    // backends, we don't need wxCLIP_CHILDREN
+    //
+    if ( !
+
+#if wxUSE_CREATEMOVIECONTROL
+          ctrl->wxWindow::Create(parent, id, pos, size,
+                                 wxWindow::MacRemoveBordersFromStyle(style),
+                                 name)
 #else
-                            style | wxNO_BORDER, 
+          ctrl->wxControl::Create(parent, id, pos, size,
+                                  wxWindow::MacRemoveBordersFromStyle(style),
+                                  validator, name)
 #endif
-                            wxDefaultValidator, name) )
+        )
         return false;
 
-    //Set our background color to black by default
-    SetBackgroundColour(*wxBLACK);
+#if wxUSE_VALIDATORS
+    ctrl->SetValidator(validator);
+#endif
 
+    m_ctrl = ctrl;
     return true;
 }
 
-bool wxMediaCtrl::Load(const wxString& fileName)
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::Load (file version)
+//
+// 1) Get an FSSpec from the Windows path name
+// 2) Open the movie
+// 3) Obtain the movie instance from the movie resource
+// 4) Close the movie resource
+// 5) Finish loading
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::Load(const wxString& fileName)
 {
-    if(m_bLoaded)
+    if(m_timer)
         Cleanup();
 
-    if ( !InitQT() )
-        return false;
-
     OSErr err = noErr;
     short movieResFile;
     FSSpec sfFile;
-#ifdef __WXMAC__
-    wxMacFilename2FSSpec( fileName , &sfFile ) ;
-#else
-    if (NativePathNameToFSSpec ((char*) fileName.mb_str(), &sfFile, 0) != noErr)
+
+    //FIXME:wxMacFilename2FSSpec crashes on empty string -
+    //does it crash on other strings too and should this
+    //"fix" be put in the carbon wxSound?
+    if (fileName.empty())
         return false;
-#endif
+
+    wxMacFilename2FSSpec( fileName , &sfFile );
+
     if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
         return false;
 
@@ -226,17 +334,25 @@ bool wxMediaCtrl::Load(const wxString& fileName)
 
     FinishLoad();
 
-    return m_bLoaded;
+    return ::GetMoviesError() == noErr;
 }
 
-bool wxMediaCtrl::Load(const wxURI& location)
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::Load (URL Version)
+//
+// 1) Build an escaped URI from location
+// 2) Create a handle to store the URI string
+// 3) Put the URI string inside the handle
+// 4) Make a QuickTime URL data ref from the handle with the URI in it
+// 5) Clean up the URI string handle
+// 6) Do some prerolling
+// 7) Finish Loading
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::Load(const wxURI& location)
 {
-    if(m_bLoaded)
+    if(m_timer)
         Cleanup();
 
-    if ( !InitQT() )
-        return false;
-
     wxString theURI = location.BuildURI();
 
     OSErr err = noErr;
@@ -247,8 +363,8 @@ bool wxMediaCtrl::Load(const wxURI& location)
     BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1);
 
     //create the movie from the handle that refers to the URI
-    err = NewMovieFromDataRef(&m_movie, newMovieActive, 
-                                NULL, theHandle, 
+    err = NewMovieFromDataRef(&m_movie, newMovieActive,
+                                NULL, theHandle,
                                 URLDataHandlerSubType);
 
     DisposeHandle(theHandle);
@@ -257,7 +373,7 @@ bool wxMediaCtrl::Load(const wxURI& location)
         return false;
 
     //preroll movie for streaming
-    //TODO:Async this?
+    //TODO:Async this using threads?
     TimeValue timeNow;
     Fixed playRate;
     timeNow = GetMovieTime(m_movie, NULL);
@@ -268,12 +384,23 @@ bool wxMediaCtrl::Load(const wxURI& location)
 
     FinishLoad();
 
-    return m_bLoaded;
+    return ::GetMoviesError() == noErr;
 }
 
-void wxMediaCtrl::FinishLoad()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::FinishLoad
+//
+// 1) Create the movie timer
+// 2) Get real size of movie for GetBestSize/sizers
+// 3) See if there is video in the movie, and if so then either
+//    SetMovieGWorld if < 10.2 or use Native CreateMovieControl
+// 4) Set the movie time scale to something usable so that seeking
+//    etc.  will work correctly
+// 5) Refresh parent window
+//---------------------------------------------------------------------------
+void wxQTMediaBackend::FinishLoad()
 {
-    m_timer = new _wxQTTimer(m_movie, (wxMediaCtrl*) this);
+    m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this);
     wxASSERT(m_timer);
 
     //get the real size of the movie
@@ -283,91 +410,163 @@ void wxMediaCtrl::FinishLoad()
 
     m_bestSize.x = outRect.right - outRect.left;
     m_bestSize.y = outRect.bottom - outRect.top;
-        
-    //reparent movie
-if(GetMovieIndTrackType(m_movie, 1, VisualMediaCharacteristic/*AudioMediaCharacteristic*/, movieTrackCharacteristic | movieTrackEnabledOnly) != NULL)
-    {
 
-#ifdef __WXMSW__
-    CreatePortAssociation(this->GetHWND(), NULL, 0L);
-#endif
-    SetMovieGWorld(m_movie, (CGrafPtr)
-
-#ifdef __WXMSW__
-    GetNativeWindowPort(this->GetHWND())
+    //reparent movie/*AudioMediaCharacteristic*/
+    if(GetMovieIndTrackType(m_movie, 1,
+                            VisualMediaCharacteristic,
+                            movieTrackCharacteristic |
+                                movieTrackEnabledOnly) != NULL)
+    {
+#if wxUSE_CREATEMOVIECONTROL
+        //
+        //Native CreateMovieControl QT control (Thanks to Kevin Olliver's
+        //wxQTMovie for some of this).
+        //
+        #define GetControlPeer(whatever) ctrl->m_peer
+        wxMediaCtrl* ctrl = (wxMediaCtrl*) m_ctrl;
+            Rect bounds = wxMacGetBoundsForControl(m_ctrl,
+                                                   m_ctrl->GetPosition(),
+                                                   m_ctrl->GetSize());
+
+        //Dispose of old control for new one
+        if (GetControlPeer(m_ctrl) && GetControlPeer(m_ctrl)->Ok() )
+            GetControlPeer(m_ctrl)->Dispose();
+
+        //Options-
+        //kMovieControlOptionXXX
+        //HideController - hide the movie controller
+        //LocateTopLeft - movie is pinned to top left rather than centered in the control
+        //EnableEditing - Allows programmatic editing and dragn'drop
+        //HandleEditingHI- Installs event stuff for edit menu - forces EnableEditing also
+        //SetKeysEnabled - Allows keyboard input
+        //ManuallyIdled - app handles movie idling rather than internal timer event loop
+        ::CreateMovieControl(
+                    (WindowRef)
+                       ctrl->MacGetTopLevelWindowRef(), //parent
+                       &bounds,                         //control bounds
+                       m_movie,                         //movie handle
+                       kMovieControlOptionHideController
+                       | kMovieControlOptionLocateTopLeft
+                       | kMovieControlOptionSetKeysEnabled
+//                       | kMovieControlOptionManuallyIdled
+                       ,                                //flags
+                       ctrl->m_peer->GetControlRefAddr() );
+
+        ::EmbedControl(ctrl->m_peer->GetControlRef(), (ControlRef)ctrl->GetParent()->GetHandle());
 #else
-    GetWindowPort((WindowRef)this->MacGetTopLevelWindowRef())
+        //
+        //"Emulation"
+        //
+        SetMovieGWorld(m_movie,
+                       (CGrafPtr)
+                       GetWindowPort(
+                       (WindowRef)
+                       m_ctrl->MacGetTopLevelWindowRef()
+                       ),
+                       nil);
 #endif
-    , nil);
     }
 
-//    wxPrintf(wxT("%u\n"), ::GetMovieTimeScale(m_movie));
     //we want millisecond precision
     ::SetMovieTimeScale(m_movie, 1000);
-    
-    m_bLoaded = (::GetMoviesError() == noErr);
-
-    //work around refresh issues
-    wxSize size = GetParent()->GetSize();
-    GetParent()->SetSize(wxSize(size.x+1, size.y+1));
-    GetParent()->Refresh();
-    GetParent()->Update();
-    GetParent()->SetSize(size);
-    GetParent()->Refresh();
-    GetParent()->Update();
+    wxASSERT(::GetMoviesError() == noErr);
+
+    //
+    //Here, if the parent of the control has a sizer - we
+    //tell it to recalculate the size of this control since
+    //the user opened a separate media file
+    //
+    m_ctrl->InvalidateBestSize();
+    m_ctrl->GetParent()->Layout();
+    m_ctrl->GetParent()->Refresh();
+    m_ctrl->GetParent()->Update();
+
+    //send loaded event
+    wxMediaEvent theEvent(wxEVT_MEDIA_LOADED,
+                            m_ctrl->GetId());
+    m_ctrl->AddPendingEvent(theEvent);
 }
 
-bool wxMediaCtrl::Play()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::Play
+//
+// 1) Start the QT movie
+// 2) Start the movie loading timer
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::Play()
 {
-    MSWMOVIECHECK
     ::StartMovie(m_movie);
     m_timer->SetPaused(false);
     m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
     return ::GetMoviesError() == noErr;
 }
 
-bool wxMediaCtrl::Pause()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::Pause
+//
+// 1) Stop the movie
+// 2) Stop the movie timer
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::Pause()
 {
-    MSWMOVIECHECK
     ::StopMovie(m_movie);
     m_timer->SetPaused(true);
     m_timer->Stop();
     return ::GetMoviesError() == noErr;
 }
 
-bool wxMediaCtrl::Stop()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::Stop
+//
+// 1) Stop the movie
+// 2) Stop the movie timer
+// 3) Seek to the beginning of the movie
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::Stop()
 {
-    MSWMOVIECHECK
     m_timer->SetPaused(false);
     m_timer->Stop();
 
     ::StopMovie(m_movie);
     if(::GetMoviesError() != noErr)
         return false;
-    
+
     ::GoToBeginningOfMovie(m_movie);
     return ::GetMoviesError() == noErr;
 }
 
-double wxMediaCtrl::GetPlaybackRate()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::GetPlaybackRate
+//
+// 1) Get the movie playback rate from ::GetMovieRate
+//---------------------------------------------------------------------------
+double wxQTMediaBackend::GetPlaybackRate()
 {
-    MSWMOVIECHECK
     return ( ((double)::GetMovieRate(m_movie)) / 0x10000);
 }
 
-bool wxMediaCtrl::SetPlaybackRate(double dRate)
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::SetPlaybackRate
+//
+// 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::SetPlaybackRate(double dRate)
 {
-    MSWMOVIECHECK
     ::SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
     return ::GetMoviesError() == noErr;
 }
 
-bool wxMediaCtrl::SetPosition(long where)
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::SetPosition
+//
+// 1) Create a time record struct (TimeRecord) with appropriate values
+// 2) Pass struct to SetMovieTime
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::SetPosition(wxLongLong where)
 {
-    MSWMOVIECHECK
     TimeRecord theTimeRecord;
     memset(&theTimeRecord, 0, sizeof(TimeRecord));
-    theTimeRecord.value.lo = where;
+    theTimeRecord.value.lo = where.GetValue();
     theTimeRecord.scale = ::GetMovieTimeScale(m_movie);
     theTimeRecord.base = ::GetMovieTimeBase(m_movie);
     ::SetMovieTime(m_movie, &theTimeRecord);
@@ -378,71 +577,156 @@ bool wxMediaCtrl::SetPosition(long where)
     return true;
 }
 
-long wxMediaCtrl::GetPosition()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::GetPosition
+//
+// Calls GetMovieTime
+//---------------------------------------------------------------------------
+wxLongLong wxQTMediaBackend::GetPosition()
 {
-    MSWMOVIECHECK
     return ::GetMovieTime(m_movie, NULL);
 }
 
-long wxMediaCtrl::GetDuration()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::GetVolume
+//
+// Gets the volume through GetMovieVolume - which returns a 16 bit short -
+//
+// +--------+--------+
+// +   (1)  +   (2)  +
+// +--------+--------+
+//
+// (1) first 8 bits are value before decimal
+// (2) second 8 bits are value after decimal
+//
+// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
+// 1 (full gain and sound)
+//---------------------------------------------------------------------------
+double wxQTMediaBackend::GetVolume()
+{
+    short sVolume = GetMovieVolume(m_movie);
+
+    if(sVolume & (128 << 8)) //negative - no sound
+        return 0.0;
+
+    return (sVolume & (127 << 8)) ? 1.0 : ((double)(sVolume & 255)) / 255.0;
+}
+
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::SetVolume
+//
+// Sets the volume through SetMovieVolume - which takes a 16 bit short -
+//
+// +--------+--------+
+// +   (1)  +   (2)  +
+// +--------+--------+
+//
+// (1) first 8 bits are value before decimal
+// (2) second 8 bits are value after decimal
+//
+// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
+// 1 (full gain and sound)
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::SetVolume(double dVolume)
+{
+    short sVolume = (short) (dVolume >= .9999 ? 1 << 8 : (dVolume * 255) );
+    SetMovieVolume(m_movie, sVolume);
+    return true;
+}
+ //---------------------------------------------------------------------------
+// wxQTMediaBackend::GetDuration
+//
+// Calls GetMovieDuration
+//---------------------------------------------------------------------------
+wxLongLong wxQTMediaBackend::GetDuration()
 {
-    MSWMOVIECHECK
     return ::GetMovieDuration(m_movie);
 }
 
-wxMediaState wxMediaCtrl::GetState()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::GetState
+//
+// Determines the current state - the timer keeps track of whether or not
+// we are paused or stopped (if the timer is running we are playing)
+//---------------------------------------------------------------------------
+wxMediaState wxQTMediaBackend::GetState()
 {
-    if ( !m_bLoaded || (m_timer->IsRunning() == false && m_timer->GetPaused() == false) )
+    if ( !m_timer || (m_timer->IsRunning() == false &&
+                      m_timer->GetPaused() == false) )
         return wxMEDIASTATE_STOPPED;
 
-    if( m_timer->IsRunning() == true )
+    if( m_timer->IsRunning() )
         return wxMEDIASTATE_PLAYING;
     else
         return wxMEDIASTATE_PAUSED;
 }
 
-void wxMediaCtrl::Cleanup()
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::Cleanup
+//
+// Diposes of the movie timer, Control if native, and stops and disposes
+// of the QT movie
+//---------------------------------------------------------------------------
+void wxQTMediaBackend::Cleanup()
 {
     delete m_timer;
     m_timer = NULL;
 
-    StopMovie(m_movie);
-    DisposeMovie(m_movie);
-    
-    //Note that ExitMovies() is not neccessary, but
-    //the docs are fuzzy on whether or not TerminateQTML is
-    ExitMovies();
-
-#ifndef __WXMAC__
-    TerminateQTML();
+#if wxUSE_CREATEMOVIECONTROL
+    DisposeControl(((wxMediaCtrl*)m_ctrl)->m_peer->GetControlRef());
 #endif
-}
 
-wxMediaCtrl::~wxMediaCtrl()
-{
-    if(m_bLoaded)
-        Cleanup();
+    StopMovie(m_movie);
+    DisposeMovie(m_movie);
 }
 
-wxSize wxMediaCtrl::DoGetBestSize() const
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::GetVideoSize
+//
+// Returns the actual size of the QT movie
+//---------------------------------------------------------------------------
+wxSize wxQTMediaBackend::GetVideoSize() const
 {
     return m_bestSize;
 }
 
-void wxMediaCtrl::DoMoveWindow(int x, int y, int w, int h)
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::Move
+//
+// We need to do this even when using native qt control because
+// CreateMovieControl is broken in this regard...
+//---------------------------------------------------------------------------
+void wxQTMediaBackend::Move(int x, int y, int w, int h)
 {
-    wxControl::DoMoveWindow(x,y,w,h);
-    
-    if(m_bLoaded)
+#if !wxUSE_CREATEMOVIECONTROL
+    if(m_timer)
     {
-#ifdef __WXMAC__
+        if ( m_ctrl )
+        {
+            m_ctrl->GetParent()->MacWindowToRootWindow(&x, &y);
+        }
+
         Rect theRect = {y, x, y+h, x+w};
-#else
-        Rect theRect = {0, 0, h, w};
-#endif
+
         ::SetMovieBox(m_movie, &theRect);
         wxASSERT(::GetMoviesError() == noErr);
     }
+#else
+    if(m_timer && m_ctrl)
+    {
+        m_ctrl->GetParent()->MacWindowToRootWindow(&x, &y);
+
+        ::MoveControl( (ControlRef) m_ctrl->GetHandle(), x, y );
+        m_ctrl->GetParent()->Refresh();
+        m_ctrl->GetParent()->Update();
+    }
+#endif
 }
 
-#endif //wxUSE_MOVIECTRL
+
+//in source file that contains stuff you don't directly use
+#include "wx/html/forcelnk.h"
+FORCE_LINK_ME(basewxmediabackends);
+
+#endif //wxUSE_MEDIACTRL