1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/mediactrl_qt.cpp
3 // Purpose:     QuickTime Media Backend for Windows
4 // Author:      Ryan Norton <wxprojects@comcast.net>
5 // Modified by: Robin Dunn (moved QT code from mediactrl.cpp)
6 //
7 // Created:     11/07/04
8 // Copyright:   (c) Ryan Norton
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 
13 //===========================================================================
14 //  DECLARATIONS
15 //===========================================================================
16 
17 //---------------------------------------------------------------------------
18 // Pre-compiled header stuff
19 //---------------------------------------------------------------------------
20 
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23 
24 #ifdef __BORLANDC__
25     #pragma hdrstop
26 #endif
27 
28 #if wxUSE_MEDIACTRL
29 
30 #include "wx/mediactrl.h"
31 
32 #ifndef WX_PRECOMP
33     #include "wx/log.h"
34     #include "wx/dcclient.h"
35     #include "wx/timer.h"
36     #include "wx/math.h"        // log10 & pow
37 #endif
38 
39 #include "wx/msw/private.h" // user info and wndproc setting/getting
40 #include "wx/dynlib.h"
41 
42 //---------------------------------------------------------------------------
43 // Externals (somewhere in src/msw/app.cpp and src/msw/window.cpp)
44 //---------------------------------------------------------------------------
45 extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(void);
46 extern WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName;
47 
48 LRESULT WXDLLIMPEXP_CORE APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
49                                    WPARAM wParam, LPARAM lParam);
50 
51 //---------------------------------------------------------------------------
52 // Killed MSVC warnings
53 //---------------------------------------------------------------------------
54 //disable "cast truncates constant value" for VARIANT_BOOL values
55 //passed as parameters in VC5 and up
56 #ifdef _MSC_VER
57 #pragma warning (disable:4310)
58 #endif
59 
60 
61 //---------------------------------------------------------------------------
62 //  wxQTMediaBackend
63 //
64 // We don't include Quicktime headers here and define all the types
65 // ourselves because looking for the quicktime libaries etc. would
66 // be tricky to do and making this a dependency for the MSVC projects
67 // would be unrealistic.
68 //
69 // Thanks to Robert Roebling for the wxDL macro/library idea
70 //---------------------------------------------------------------------------
71 
72 //---------------------------------------------------------------------------
73 //  QT Includes
74 //---------------------------------------------------------------------------
75 //#include <qtml.h>                   // Windoze QT include
76 //#include <QuickTimeComponents.h>    // Standard QT stuff
77 #include "wx/dynlib.h"
78 
79 //---------------------------------------------------------------------------
80 //  QT Types
81 //---------------------------------------------------------------------------
82 typedef struct MovieRecord* Movie;
83 typedef wxInt16 OSErr;
84 typedef wxInt32 OSStatus;
85 #define noErr 0
86 #define fsRdPerm 1
87 typedef unsigned char                   Str255[256];
88 #define StringPtr unsigned char*
89 #define newMovieActive 1
90 #define newMovieAsyncOK (1 << 8)
91 #define Ptr char*
92 #define Handle Ptr*
93 #define Fixed long
94 #define OSType unsigned long
95 #define CGrafPtr struct GrafPort *
96 #define TimeScale long
97 #define TimeBase struct TimeBaseRecord *
98 typedef struct ComponentInstanceRecord * ComponentInstance;
99 #define kMovieLoadStatePlayable 10000
100 #define Boolean int
101 #define MovieController ComponentInstance
102 
103 #ifndef URLDataHandlerSubType
104 #if defined(__WATCOMC__) || defined(__MINGW32__)
105 // use magic numbers for compilers which complain about multicharacter integers
106 const OSType URLDataHandlerSubType     = 1970433056;
107 const OSType VisualMediaCharacteristic = 1702454643;
108 #else
109 const OSType URLDataHandlerSubType     = 'url ';
110 const OSType VisualMediaCharacteristic = 'eyes';
111 #endif
112 #endif
113 
114 struct FSSpec
115 {
116     short      vRefNum;
117     long       parID;
118     Str255     name;  // Str63 on mac, Str255 on msw
119 };
120 
121 struct Rect
122 {
123     short      top;
124     short      left;
125     short      bottom;
126     short      right;
127 };
128 
129 struct wide
130 {
131     wxInt32    hi;
132     wxUint32   lo;
133 };
134 
135 struct TimeRecord
136 {
137     wide       value; // units
138     TimeScale  scale; // units per second
139     TimeBase   base;
140 };
141 
142 struct Point
143 {
144     short                           v;
145     short                           h;
146 };
147 
148 struct EventRecord
149 {
150     wxUint16                       what;
151     wxUint32                          message;
152     wxUint32                          when;
153     Point                           where;
154     wxUint16                  modifiers;
155 };
156 
157 enum
158 {
159     mcTopLeftMovie              = 1,
160     mcScaleMovieToFit           = 2,
161     mcWithBadge                 = 4,
162     mcNotVisible                = 8,
163     mcWithFrame                 = 16
164 };
165 
166 //---------------------------------------------------------------------------
167 //  QT Library
168 //---------------------------------------------------------------------------
169 
170 class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary
171 {
172 public:
~wxQuickTimeLibrary()173     ~wxQuickTimeLibrary()
174     {
175         if (m_dll.IsLoaded())
176             m_dll.Unload();
177     }
178 
179     bool Initialize();
IsOk() const180     bool IsOk() const {return m_ok;}
181 
182 protected:
183     wxDynamicLibrary m_dll;
184     bool m_ok;
185 
186 public:
187     wxDL_VOIDMETHOD_DEFINE( StartMovie, (Movie m), (m) )
188     wxDL_VOIDMETHOD_DEFINE( StopMovie, (Movie m), (m) )
189     wxDL_METHOD_DEFINE( bool, IsMovieDone, (Movie m), (m), false)
190     wxDL_VOIDMETHOD_DEFINE( GoToBeginningOfMovie, (Movie m), (m) )
191     wxDL_METHOD_DEFINE( OSErr, GetMoviesError, (), (), -1)
192     wxDL_METHOD_DEFINE( OSErr, EnterMovies, (), (), -1)
193     wxDL_VOIDMETHOD_DEFINE( ExitMovies, (), () )
194     wxDL_METHOD_DEFINE( OSErr, InitializeQTML, (long flags), (flags), -1)
195     wxDL_VOIDMETHOD_DEFINE( TerminateQTML, (), () )
196 
197     wxDL_METHOD_DEFINE( OSErr, NativePathNameToFSSpec,
198                         (char* inName, FSSpec* outFile, long flags),
199                         (inName, outFile, flags), -1)
200 
201     wxDL_METHOD_DEFINE( OSErr, OpenMovieFile,
202                         (const FSSpec * fileSpec, short * resRefNum, wxInt8 permission),
203                         (fileSpec, resRefNum, permission), -1 )
204 
205     wxDL_METHOD_DEFINE( OSErr, CloseMovieFile,
206                         (short resRefNum), (resRefNum), -1)
207 
208     wxDL_METHOD_DEFINE( OSErr, NewMovieFromFile,
209                             (Movie * theMovie, short resRefNum, short *  resId,
210                              StringPtr resName, short newMovieFlags,
211                              bool * dataRefWasChanged),
212                              (theMovie, resRefNum, resId, resName, newMovieFlags,
213                               dataRefWasChanged), -1)
214 
215     wxDL_VOIDMETHOD_DEFINE( SetMovieRate, (Movie m, Fixed rate), (m, rate) )
216     wxDL_METHOD_DEFINE( Fixed, GetMovieRate, (Movie m), (m), 0)
217     wxDL_VOIDMETHOD_DEFINE( MoviesTask, (Movie m, long maxms), (m, maxms) )
218     wxDL_VOIDMETHOD_DEFINE( BlockMove,
219         (const char* p1, const char* p2, long s), (p1,p2,s) )
220     wxDL_METHOD_DEFINE( Handle, NewHandleClear, (long s), (s), NULL )
221 
222     wxDL_METHOD_DEFINE( OSErr, NewMovieFromDataRef,
223                            (Movie * m, short flags, short * id,
224                             Handle  dataRef, OSType  dataRefType),
225                             (m,flags,id,dataRef,dataRefType), -1 )
226 
227     wxDL_VOIDMETHOD_DEFINE( DisposeHandle, (Handle h), (h) )
228     wxDL_VOIDMETHOD_DEFINE( GetMovieNaturalBoundsRect, (Movie m, Rect* r), (m,r) )
229     wxDL_METHOD_DEFINE( void*, GetMovieIndTrackType,
230                         (Movie m, long index, OSType type, long flags),
231                         (m,index,type,flags), NULL )
232     wxDL_VOIDMETHOD_DEFINE( CreatePortAssociation,
233             (void* hWnd, void* junk, long morejunk), (hWnd, junk, morejunk) )
234     wxDL_METHOD_DEFINE(void*, GetNativeWindowPort, (void* hWnd), (hWnd), NULL)
235     wxDL_VOIDMETHOD_DEFINE(SetMovieGWorld, (Movie m, CGrafPtr port, void* whatever),
236                             (m, port, whatever) )
237     wxDL_VOIDMETHOD_DEFINE(DisposeMovie, (Movie m), (m) )
238     wxDL_VOIDMETHOD_DEFINE(SetMovieBox, (Movie m, Rect* r), (m,r))
239     wxDL_VOIDMETHOD_DEFINE(SetMovieTimeScale, (Movie m, long s), (m,s))
240     wxDL_METHOD_DEFINE(long, GetMovieDuration, (Movie m), (m), 0)
241     wxDL_METHOD_DEFINE(TimeBase, GetMovieTimeBase, (Movie m), (m), 0)
242     wxDL_METHOD_DEFINE(TimeScale, GetMovieTimeScale, (Movie m), (m), 0)
243     wxDL_METHOD_DEFINE(long, GetMovieTime, (Movie m, void* cruft), (m,cruft), 0)
244     wxDL_VOIDMETHOD_DEFINE(SetMovieTime, (Movie m, TimeRecord* tr), (m,tr) )
245     wxDL_METHOD_DEFINE(short, GetMovieVolume, (Movie m), (m), 0)
246     wxDL_VOIDMETHOD_DEFINE(SetMovieVolume, (Movie m, short sVolume), (m,sVolume) )
247     wxDL_VOIDMETHOD_DEFINE(SetMovieTimeValue, (Movie m, long s), (m,s))
248     wxDL_METHOD_DEFINE(ComponentInstance, NewMovieController, (Movie m, const Rect* mr, long fl), (m,mr,fl), 0)
249     wxDL_VOIDMETHOD_DEFINE(DisposeMovieController, (ComponentInstance ci), (ci))
250     wxDL_METHOD_DEFINE(int, MCSetVisible, (ComponentInstance m, int b), (m, b), 0)
251 
252     wxDL_VOIDMETHOD_DEFINE(PrePrerollMovie, (Movie m, long t, Fixed r, WXFARPROC p1, void* p2), (m,t,r,p1,p2) )
253     wxDL_VOIDMETHOD_DEFINE(PrerollMovie, (Movie m, long t, Fixed r), (m,t,r) )
254     wxDL_METHOD_DEFINE(Fixed, GetMoviePreferredRate, (Movie m), (m), 0)
255     wxDL_METHOD_DEFINE(long, GetMovieLoadState, (Movie m), (m), 0)
256     wxDL_METHOD_DEFINE(void*, NewRoutineDescriptor, (WXFARPROC f, int l, void* junk), (f, l, junk), 0)
257     wxDL_VOIDMETHOD_DEFINE(DisposeRoutineDescriptor, (void* f), (f))
258     wxDL_METHOD_DEFINE(void*, GetCurrentArchitecture, (), (), 0)
259     wxDL_METHOD_DEFINE(int, MCDoAction, (ComponentInstance ci, long f, void* p), (ci,f,p), 0)
260     wxDL_VOIDMETHOD_DEFINE(MCSetControllerBoundsRect, (ComponentInstance ci, Rect* r), (ci,r))
261     wxDL_VOIDMETHOD_DEFINE(DestroyPortAssociation, (CGrafPtr g), (g))
262     wxDL_VOIDMETHOD_DEFINE(NativeEventToMacEvent, (MSG* p1, EventRecord* p2), (p1,p2))
263     wxDL_VOIDMETHOD_DEFINE(MCIsPlayerEvent, (ComponentInstance ci, EventRecord* p2), (ci, p2))
264     wxDL_METHOD_DEFINE(int, MCSetMovie, (ComponentInstance ci, Movie m, void* p1, Point w),
265                           (ci,m,p1,w),0)
266     wxDL_VOIDMETHOD_DEFINE(MCPositionController,
267         (ComponentInstance ci, Rect* r, void* junk, void* morejunk), (ci,r,junk,morejunk))
268     wxDL_VOIDMETHOD_DEFINE(MCSetActionFilterWithRefCon,
269         (ComponentInstance ci, WXFARPROC cb, void* ref), (ci,cb,ref))
270     wxDL_VOIDMETHOD_DEFINE(MCGetControllerInfo, (MovieController mc, long* flags), (mc,flags))
271     wxDL_VOIDMETHOD_DEFINE(BeginUpdate, (CGrafPtr port), (port))
272     wxDL_VOIDMETHOD_DEFINE(UpdateMovie, (Movie m), (m))
273     wxDL_VOIDMETHOD_DEFINE(EndUpdate, (CGrafPtr port), (port))
274     wxDL_METHOD_DEFINE( OSErr, GetMoviesStickyError, (), (), -1)
275 };
276 
Initialize()277 bool wxQuickTimeLibrary::Initialize()
278 {
279     // Turn off the wxDynamicLibrary logging as we're prepared to handle the
280     // errors
281     wxLogNull nolog;
282 
283     m_ok = m_dll.Load(wxT("qtmlClient.dll"));
284     if ( !m_ok )
285         return false;
286 
287     wxDL_METHOD_LOAD( m_dll, StartMovie );
288     wxDL_METHOD_LOAD( m_dll, StopMovie );
289     wxDL_METHOD_LOAD( m_dll, IsMovieDone );
290     wxDL_METHOD_LOAD( m_dll, GoToBeginningOfMovie );
291     wxDL_METHOD_LOAD( m_dll, GetMoviesError );
292     wxDL_METHOD_LOAD( m_dll, EnterMovies );
293     wxDL_METHOD_LOAD( m_dll, ExitMovies );
294     wxDL_METHOD_LOAD( m_dll, InitializeQTML );
295     wxDL_METHOD_LOAD( m_dll, TerminateQTML );
296     wxDL_METHOD_LOAD( m_dll, NativePathNameToFSSpec );
297     wxDL_METHOD_LOAD( m_dll, OpenMovieFile );
298     wxDL_METHOD_LOAD( m_dll, CloseMovieFile );
299     wxDL_METHOD_LOAD( m_dll, NewMovieFromFile );
300     wxDL_METHOD_LOAD( m_dll, GetMovieRate );
301     wxDL_METHOD_LOAD( m_dll, SetMovieRate );
302     wxDL_METHOD_LOAD( m_dll, MoviesTask );
303     wxDL_METHOD_LOAD( m_dll, BlockMove );
304     wxDL_METHOD_LOAD( m_dll, NewHandleClear );
305     wxDL_METHOD_LOAD( m_dll, NewMovieFromDataRef );
306     wxDL_METHOD_LOAD( m_dll, DisposeHandle );
307     wxDL_METHOD_LOAD( m_dll, GetMovieNaturalBoundsRect );
308     wxDL_METHOD_LOAD( m_dll, GetMovieIndTrackType );
309     wxDL_METHOD_LOAD( m_dll, CreatePortAssociation );
310     wxDL_METHOD_LOAD( m_dll, DestroyPortAssociation );
311     wxDL_METHOD_LOAD( m_dll, GetNativeWindowPort );
312     wxDL_METHOD_LOAD( m_dll, SetMovieGWorld );
313     wxDL_METHOD_LOAD( m_dll, DisposeMovie );
314     wxDL_METHOD_LOAD( m_dll, SetMovieBox );
315     wxDL_METHOD_LOAD( m_dll, SetMovieTimeScale );
316     wxDL_METHOD_LOAD( m_dll, GetMovieDuration );
317     wxDL_METHOD_LOAD( m_dll, GetMovieTimeBase );
318     wxDL_METHOD_LOAD( m_dll, GetMovieTimeScale );
319     wxDL_METHOD_LOAD( m_dll, GetMovieTime );
320     wxDL_METHOD_LOAD( m_dll, SetMovieTime );
321     wxDL_METHOD_LOAD( m_dll, GetMovieVolume );
322     wxDL_METHOD_LOAD( m_dll, SetMovieVolume );
323     wxDL_METHOD_LOAD( m_dll, SetMovieTimeValue );
324     wxDL_METHOD_LOAD( m_dll, NewMovieController );
325     wxDL_METHOD_LOAD( m_dll, DisposeMovieController );
326     wxDL_METHOD_LOAD( m_dll, MCSetVisible );
327     wxDL_METHOD_LOAD( m_dll, PrePrerollMovie );
328     wxDL_METHOD_LOAD( m_dll, PrerollMovie );
329     wxDL_METHOD_LOAD( m_dll, GetMoviePreferredRate );
330     wxDL_METHOD_LOAD( m_dll, GetMovieLoadState );
331     wxDL_METHOD_LOAD( m_dll, MCDoAction );
332     wxDL_METHOD_LOAD( m_dll, MCSetControllerBoundsRect );
333     wxDL_METHOD_LOAD( m_dll, NativeEventToMacEvent );
334     wxDL_METHOD_LOAD( m_dll, MCIsPlayerEvent );
335     wxDL_METHOD_LOAD( m_dll, MCSetMovie );
336     wxDL_METHOD_LOAD( m_dll, MCSetActionFilterWithRefCon );
337     wxDL_METHOD_LOAD( m_dll, MCGetControllerInfo );
338     wxDL_METHOD_LOAD( m_dll, BeginUpdate );
339     wxDL_METHOD_LOAD( m_dll, UpdateMovie );
340     wxDL_METHOD_LOAD( m_dll, EndUpdate );
341     wxDL_METHOD_LOAD( m_dll, GetMoviesStickyError );
342 
343     return m_ok;
344 }
345 
346 class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
347 {
348 public:
349     wxQTMediaBackend();
350     virtual ~wxQTMediaBackend();
351 
352     virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
353                                      wxWindowID id,
354                                      const wxPoint& pos,
355                                      const wxSize& size,
356                                      long style,
357                                      const wxValidator& validator,
358                                      const wxString& name);
359 
360     virtual bool Play();
361     virtual bool Pause();
362     virtual bool Stop();
363 
Load(const wxURI & location,const wxURI & proxy)364     virtual bool Load(const wxURI& location,
365                       const wxURI& proxy)
366     { return wxMediaBackend::Load(location, proxy); }
367 
368     virtual bool Load(const wxString& fileName);
369     virtual bool Load(const wxURI& location);
370 
371     virtual wxMediaState GetState();
372 
373     virtual bool SetPosition(wxLongLong where);
374     virtual wxLongLong GetPosition();
375     virtual wxLongLong GetDuration();
376 
377     virtual void Move(int x, int y, int w, int h);
378     wxSize GetVideoSize() const;
379 
380     virtual double GetPlaybackRate();
381     virtual bool SetPlaybackRate(double dRate);
382 
383     virtual double GetVolume();
384     virtual bool SetVolume(double);
385 
386     void Cleanup();
387     void FinishLoad();
388 
389     static void PPRMProc (Movie theMovie, OSErr theErr, void* theRefCon);
390 
391     // TODO: Last param actually long - does this work on 64bit machines?
392     static Boolean MCFilterProc(MovieController theController,
393         short action, void *params, LONG_PTR refCon);
394 
395     static LRESULT CALLBACK QTWndProc(HWND, UINT, WPARAM, LPARAM);
396 
397     virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
398 
399     wxSize m_bestSize;              // Original movie size
400     Movie m_movie;    // QT Movie handle/instance
401     bool m_bVideo;                  // Whether or not we have video
402     bool m_bPlaying;                // Whether or not movie is playing
403     wxTimer* m_timer;               // Load or Play timer
404     wxQuickTimeLibrary m_lib;       // DLL to load functions from
405     ComponentInstance m_pMC;        // Movie Controller
406     wxEvtHandler* m_evthandler;
407 
408     friend class wxQTMediaEvtHandler;
409 
410     DECLARE_DYNAMIC_CLASS(wxQTMediaBackend)
411 };
412 
413 // helper to hijack background erasing for the QT window
414 class WXDLLIMPEXP_MEDIA wxQTMediaEvtHandler : public wxEvtHandler
415 {
416 public:
wxQTMediaEvtHandler(wxQTMediaBackend * qtb,WXHWND hwnd)417     wxQTMediaEvtHandler(wxQTMediaBackend *qtb, WXHWND hwnd)
418     {
419         m_qtb = qtb;
420         m_hwnd = hwnd;
421 
422         m_qtb->m_ctrl->Connect(m_qtb->m_ctrl->GetId(),
423             wxEVT_ERASE_BACKGROUND,
424             wxEraseEventHandler(wxQTMediaEvtHandler::OnEraseBackground),
425             NULL, this);
426     }
427 
428     void OnEraseBackground(wxEraseEvent& event);
429 
430 private:
431     wxQTMediaBackend *m_qtb;
432     WXHWND m_hwnd;
433 
434     wxDECLARE_NO_COPY_CLASS(wxQTMediaEvtHandler);
435 };
436 
437 
438 //===========================================================================
439 //  IMPLEMENTATION
440 //===========================================================================
441 
442 
443 //---------------------------------------------------------------------------
444 // wxQTMediaBackend
445 //
446 // TODO: Use a less kludgy way to pause/get state/set state
447 // FIXME: Greg Hazel reports that sometimes files that cannot be played
448 // with this backend are treated as playable anyway - not verified though.
449 //---------------------------------------------------------------------------
450 
451 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend)
452 
453 // Time between timer calls - this is the Apple recommendation to the TCL
454 // team I believe
455 #define MOVIE_DELAY 20
456 
457 //---------------------------------------------------------------------------
458 // wxQTLoadTimer
459 //
460 //  QT, esp. QT for Windows is very picky about how you go about
461 //  async loading.  If you were to go through a Windows message loop
462 //  or a MoviesTask or both and then check the movie load state
463 //  it would still return 1000 (loading)... even (pre)prerolling doesn't
464 //  help.  However, making a load timer like this works
465 //---------------------------------------------------------------------------
466 class wxQTLoadTimer : public wxTimer
467 {
468 public:
wxQTLoadTimer(Movie movie,wxQTMediaBackend * parent,wxQuickTimeLibrary * pLib)469     wxQTLoadTimer(Movie movie, wxQTMediaBackend* parent, wxQuickTimeLibrary* pLib) :
470       m_movie(movie), m_parent(parent), m_pLib(pLib) {}
471 
Notify()472     void Notify()
473     {
474         m_pLib->MoviesTask(m_movie, 0);
475         // kMovieLoadStatePlayable
476         if (m_pLib->GetMovieLoadState(m_movie) >= 10000)
477         {
478             m_parent->FinishLoad();
479             delete this;
480         }
481     }
482 
483 protected:
484     Movie m_movie;                  //Our movie instance
485     wxQTMediaBackend* m_parent;     //Backend pointer
486     wxQuickTimeLibrary* m_pLib;     //Interfaces
487 };
488 
489 
490 // --------------------------------------------------------------------------
491 // wxQTPlayTimer - Handle Asyncronous Playing
492 //
493 // 1) Checks to see if the movie is done, and if not continues
494 //    streaming the movie
495 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
496 //    the movie.
497 // --------------------------------------------------------------------------
498 class wxQTPlayTimer : public wxTimer
499 {
500 public:
wxQTPlayTimer(Movie movie,wxQTMediaBackend * parent,wxQuickTimeLibrary * pLib)501     wxQTPlayTimer(Movie movie, wxQTMediaBackend* parent,
502                   wxQuickTimeLibrary* pLib) :
503         m_movie(movie), m_parent(parent), m_pLib(pLib) {}
504 
Notify()505     void Notify()
506     {
507         //
508         //  OK, a little explaining - basically originally
509         //  we only called MoviesTask if the movie was actually
510         //  playing (not paused or stopped)... this was before
511         //  we realized MoviesTask actually handles repainting
512         //  of the current frame - so if you were to resize
513         //  or something it would previously not redraw that
514         //  portion of the movie.
515         //
516         //  So now we call MoviesTask always so that it repaints
517         //  correctly.
518         //
519         m_pLib->MoviesTask(m_movie, 0);
520 
521         //
522         // Handle the stop event - if the movie has reached
523         // the end, notify our handler
524         //
525         //  m_bPlaying == !(Stopped | Paused)
526         //
527         if (m_parent->m_bPlaying)
528         {
529             if (m_pLib->IsMovieDone(m_movie))
530             {
531                 if ( m_parent->SendStopEvent() )
532                 {
533                     m_parent->Stop();
534                     wxASSERT(m_pLib->GetMoviesError() == noErr);
535 
536                     m_parent->QueueFinishEvent();
537                 }
538             }
539         }
540     }
541 
542 protected:
543     Movie m_movie;                  // Our movie instance
544     wxQTMediaBackend* m_parent;     //Backend pointer
545     wxQuickTimeLibrary* m_pLib;         //Interfaces
546 };
547 
548 
549 //---------------------------------------------------------------------------
550 // wxQTMediaBackend::QTWndProc
551 //
552 // Forwards events to the Movie Controller so that it can
553 // redraw itself/process messages etc..
554 //---------------------------------------------------------------------------
QTWndProc(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam)555 LRESULT CALLBACK wxQTMediaBackend::QTWndProc(HWND hWnd, UINT nMsg,
556                                              WPARAM wParam, LPARAM lParam)
557 {
558     wxQTMediaBackend* pThis = (wxQTMediaBackend*)wxGetWindowUserData(hWnd);
559 
560     MSG msg;
561     msg.hwnd = hWnd;
562     msg.message = nMsg;
563     msg.wParam = wParam;
564     msg.lParam = lParam;
565     msg.time = 0;
566     msg.pt.x = 0;
567     msg.pt.y = 0;
568     EventRecord theEvent;
569     pThis->m_lib.NativeEventToMacEvent(&msg, &theEvent);
570     pThis->m_lib.MCIsPlayerEvent(pThis->m_pMC, &theEvent);
571 
572     return pThis->m_ctrl->MSWWindowProc(nMsg, wParam, lParam);
573 }
574 
575 //---------------------------------------------------------------------------
576 // wxQTMediaBackend Destructor
577 //
578 // Sets m_timer to NULL signifying we havn't loaded anything yet
579 //---------------------------------------------------------------------------
wxQTMediaBackend()580 wxQTMediaBackend::wxQTMediaBackend()
581 : m_movie(NULL), m_bPlaying(false), m_timer(NULL), m_pMC(NULL)
582 {
583     m_evthandler = NULL;
584 }
585 
586 //---------------------------------------------------------------------------
587 // wxQTMediaBackend Destructor
588 //
589 // 1) Cleans up the QuickTime movie instance
590 // 2) Decrements the QuickTime reference counter - if this reaches
591 //    0, QuickTime shuts down
592 // 3) Decrements the QuickTime Windows Media Layer reference counter -
593 //    if this reaches 0, QuickTime shuts down the Windows Media Layer
594 //---------------------------------------------------------------------------
~wxQTMediaBackend()595 wxQTMediaBackend::~wxQTMediaBackend()
596 {
597     if (m_movie)
598         Cleanup();
599 
600     if (m_lib.IsOk())
601     {
602         if (m_pMC)
603         {
604             m_lib.DisposeMovieController(m_pMC);
605             // m_pMC = NULL;
606         }
607 
608         // destroy wxQTMediaEvtHandler we pushed on it
609         if (m_evthandler)
610         {
611             m_ctrl->RemoveEventHandler(m_evthandler);
612             delete m_evthandler;
613         }
614 
615         m_lib.DestroyPortAssociation(
616             (CGrafPtr)m_lib.GetNativeWindowPort(m_ctrl->GetHWND()));
617 
618         //Note that ExitMovies() is not necessary, but
619         //the docs are fuzzy on whether or not TerminateQTML is
620         m_lib.ExitMovies();
621         m_lib.TerminateQTML();
622     }
623 }
624 
625 //---------------------------------------------------------------------------
626 // wxQTMediaBackend::CreateControl
627 //
628 // 1) Initializes QuickTime
629 // 2) Creates the control window
630 //---------------------------------------------------------------------------
CreateControl(wxControl * ctrl,wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)631 bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
632                                      wxWindowID id,
633                                      const wxPoint& pos,
634                                      const wxSize& size,
635                                      long style,
636                                      const wxValidator& validator,
637                                      const wxString& name)
638 {
639     if (!m_lib.Initialize())
640         return false;
641 
642     int nError = m_lib.InitializeQTML(0);
643     if (nError != noErr)    //-2093 no dll
644     {
645         wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
646         return false;
647     }
648 
649     m_lib.EnterMovies();
650 
651     // Create window
652     // By default wxWindow(s) is created with a border -
653     // so we need to get rid of those
654     //
655     // Since we don't have a child window like most other
656     // backends, we don't need wxCLIP_CHILDREN
657     if ( !ctrl->wxControl::Create(parent, id, pos, size,
658                             (style & ~wxBORDER_MASK) | wxBORDER_NONE,
659                             validator, name) )
660     {
661         return false;
662     }
663 
664     m_ctrl = wxStaticCast(ctrl, wxMediaCtrl);
665 
666     // Create a port association for our window so we
667     // can use it as a WindowRef
668     m_lib.CreatePortAssociation(m_ctrl->GetHWND(), NULL, 0L);
669 
670     // Part of a suggestion from Greg Hazel
671     // to repaint movie when idle
672     m_evthandler = new wxQTMediaEvtHandler(this, m_ctrl->GetHWND());
673     m_ctrl->PushEventHandler(m_evthandler);
674 
675     // done
676     return true;
677 }
678 
679 //---------------------------------------------------------------------------
680 // wxQTMediaBackend::Load (file version)
681 //
682 // 1) Get an FSSpec from the Windows path name
683 // 2) Open the movie
684 // 3) Obtain the movie instance from the movie resource
685 // 4) Close the movie resource
686 // 5) Finish loading
687 //---------------------------------------------------------------------------
Load(const wxString & fileName)688 bool wxQTMediaBackend::Load(const wxString& fileName)
689 {
690     if (m_movie)
691         Cleanup();
692 
693     short movieResFile = 0; //= 0 because of annoying VC6 warning
694     FSSpec sfFile;
695 
696     OSErr err = m_lib.NativePathNameToFSSpec(
697         (char*) (const char*) fileName.mb_str(),
698         &sfFile, 0);
699     bool result = (err == noErr);
700 
701     if (result)
702     {
703         err = m_lib.OpenMovieFile(&sfFile, &movieResFile, fsRdPerm);
704         result = (err == noErr);
705     }
706 
707     if (result)
708     {
709         short movieResID = 0;
710         Str255 movieName;
711 
712         err = m_lib.NewMovieFromFile(
713                    &m_movie,
714                    movieResFile,
715                    &movieResID,
716                    movieName,
717                    newMovieActive,
718                    NULL ); // wasChanged
719         result = (err == noErr /*&& m_lib.GetMoviesStickyError() == noErr*/);
720 
721         // check m_lib.GetMoviesStickyError() because it may not find the
722         // proper codec and play black video and other strange effects,
723         // not to mention mess up the dynamic backend loading scheme
724         // of wxMediaCtrl - so it just does what the QuickTime player does
725         if (result)
726         {
727             m_lib.CloseMovieFile(movieResFile);
728             FinishLoad();
729         }
730     }
731 
732     return result;
733 }
734 
735 //---------------------------------------------------------------------------
736 // wxQTMediaBackend::PPRMProc (static)
737 //
738 // Called when done PrePrerolling the movie.
739 // Note that in 99% of the cases this does nothing...
740 // Anyway we set up the loading timer here to tell us when the movie is done
741 //---------------------------------------------------------------------------
PPRMProc(Movie theMovie,OSErr WXUNUSED_UNLESS_DEBUG (theErr),void * theRefCon)742 void wxQTMediaBackend::PPRMProc (Movie theMovie,
743                                  OSErr WXUNUSED_UNLESS_DEBUG(theErr),
744                                  void* theRefCon)
745 {
746     wxASSERT( theMovie );
747     wxASSERT( theRefCon );
748     wxASSERT( theErr == noErr );
749 
750     wxQTMediaBackend* pBE = (wxQTMediaBackend*) theRefCon;
751 
752     long lTime = pBE->m_lib.GetMovieTime(theMovie,NULL);
753     Fixed rate = pBE->m_lib.GetMoviePreferredRate(theMovie);
754     pBE->m_lib.PrerollMovie(theMovie, lTime, rate);
755     pBE->m_timer = new wxQTLoadTimer(pBE->m_movie, pBE, &pBE->m_lib);
756     pBE->m_timer->Start(MOVIE_DELAY);
757 }
758 
759 //---------------------------------------------------------------------------
760 // wxQTMediaBackend::Load (URL Version)
761 //
762 // 1) Build an escaped URI from location
763 // 2) Create a handle to store the URI string
764 // 3) Put the URI string inside the handle
765 // 4) Make a QuickTime URL data ref from the handle with the URI in it
766 // 5) Clean up the URI string handle
767 // 6) Do some prerolling
768 // 7) Finish Loading
769 //---------------------------------------------------------------------------
Load(const wxURI & location)770 bool wxQTMediaBackend::Load(const wxURI& location)
771 {
772     if (m_movie)
773         Cleanup();
774 
775     wxString theURI = location.BuildURI();
776 
777     Handle theHandle = m_lib.NewHandleClear(theURI.length() + 1);
778     wxASSERT(theHandle);
779 
780     m_lib.BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1);
781 
782     // create the movie from the handle that refers to the URI
783     OSErr err = m_lib.NewMovieFromDataRef(&m_movie, newMovieActive |
784                                                     newMovieAsyncOK
785                                                     /* | newMovieIdleImportOK */,
786                                 NULL, theHandle,
787                                 URLDataHandlerSubType);
788 
789     m_lib.DisposeHandle(theHandle);
790 
791     if (err == noErr)
792     {
793         long timeNow;
794         Fixed playRate;
795 
796         timeNow = m_lib.GetMovieTime(m_movie, NULL);
797         wxASSERT(m_lib.GetMoviesError() == noErr);
798 
799         playRate = m_lib.GetMoviePreferredRate(m_movie);
800         wxASSERT(m_lib.GetMoviesError() == noErr);
801 
802         // Note that the callback here is optional,
803         // but without it PrePrerollMovie can be buggy
804         // (see Apple ml).  Also, some may wonder
805         // why we need this at all - this is because
806         // Apple docs say QuickTime streamed movies
807         // require it if you don't use a Movie Controller,
808         // which we don't by default.
809         //
810         m_lib.PrePrerollMovie(m_movie, timeNow, playRate,
811                               (WXFARPROC)wxQTMediaBackend::PPRMProc,
812                               (void*)this);
813 
814         return true;
815     }
816     else
817         return false;
818 }
819 
820 //---------------------------------------------------------------------------
821 // wxQTMediaBackend::FinishLoad
822 //
823 // 1) Create the movie timer
824 // 2) Get real size of movie for GetBestSize/sizers
825 // 3) Set the movie time scale to something usable so that seeking
826 //    etc.  will work correctly
827 // 4) Set our Movie Controller to display the movie if it exists,
828 //    otherwise set the bounds of the Movie
829 // 5) Refresh parent window
830 //---------------------------------------------------------------------------
FinishLoad()831 void wxQTMediaBackend::FinishLoad()
832 {
833     // Create the playing/streaming timer
834     m_timer = new wxQTPlayTimer(m_movie, (wxQTMediaBackend*) this, &m_lib);
835     wxASSERT(m_timer);
836 
837     m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
838 
839     // get the real size of the movie
840     Rect outRect;
841     memset(&outRect, 0, sizeof(Rect)); // suppress annoying VC6 warning
842     m_lib.GetMovieNaturalBoundsRect (m_movie, &outRect);
843     wxASSERT(m_lib.GetMoviesError() == noErr);
844 
845     m_bestSize.x = outRect.right - outRect.left;
846     m_bestSize.y = outRect.bottom - outRect.top;
847 
848     // Handle the movie GWorld
849     if (m_pMC)
850     {
851         Point thePoint;
852         thePoint.h = thePoint.v = 0;
853         m_lib.MCSetMovie(m_pMC, m_movie,
854                m_lib.GetNativeWindowPort(m_ctrl->GetHandle()),
855                thePoint);
856         m_lib.MCSetVisible(m_pMC, true);
857         m_bestSize.y += 16;
858     }
859     else
860     {
861         m_lib.SetMovieGWorld(m_movie,
862                        (CGrafPtr) m_lib.GetNativeWindowPort(m_ctrl->GetHWND()),
863                        NULL);
864     }
865 
866     // Set the movie to millisecond precision
867     m_lib.SetMovieTimeScale(m_movie, 1000);
868     wxASSERT(m_lib.GetMoviesError() == noErr);
869 
870     NotifyMovieLoaded();
871 }
872 
873 //---------------------------------------------------------------------------
874 // wxQTMediaBackend::Play
875 //
876 // 1) Start the QT movie
877 // 2) Start the movie loading timer
878 //
879 // NOTE:  This will still return success even when
880 // the movie is still loading, and as mentioned in wxQTLoadTimer
881 // I don't know of a way to force this to be sync - so if its
882 // still loading the function will return true but the movie will
883 // still be in the stopped state
884 //---------------------------------------------------------------------------
Play()885 bool wxQTMediaBackend::Play()
886 {
887     m_lib.StartMovie(m_movie);
888     m_bPlaying = true;
889 
890     return m_lib.GetMoviesError() == noErr;
891 }
892 
893 //---------------------------------------------------------------------------
894 // wxQTMediaBackend::Pause
895 //
896 // 1) Stop the movie
897 // 2) Stop the movie timer
898 //---------------------------------------------------------------------------
Pause()899 bool wxQTMediaBackend::Pause()
900 {
901     m_bPlaying = false;
902     m_lib.StopMovie(m_movie);
903 
904     return m_lib.GetMoviesError() == noErr;
905 }
906 
907 //---------------------------------------------------------------------------
908 // wxQTMediaBackend::Stop
909 //
910 // 1) Stop the movie
911 // 2) Stop the movie timer
912 // 3) Seek to the beginning of the movie
913 //---------------------------------------------------------------------------
Stop()914 bool wxQTMediaBackend::Stop()
915 {
916     m_bPlaying = false;
917 
918     m_lib.StopMovie(m_movie);
919     if (m_lib.GetMoviesError() == noErr)
920         m_lib.GoToBeginningOfMovie(m_movie);
921 
922     return m_lib.GetMoviesError() == noErr;
923 }
924 
925 //---------------------------------------------------------------------------
926 // wxQTMediaBackend::GetPlaybackRate
927 //
928 // Get the movie playback rate from ::GetMovieRate
929 //---------------------------------------------------------------------------
GetPlaybackRate()930 double wxQTMediaBackend::GetPlaybackRate()
931 {
932     return ( ((double)m_lib.GetMovieRate(m_movie)) / 0x10000);
933 }
934 
935 //---------------------------------------------------------------------------
936 // wxQTMediaBackend::SetPlaybackRate
937 //
938 // Convert dRate to Fixed and Set the movie rate through SetMovieRate
939 //---------------------------------------------------------------------------
SetPlaybackRate(double dRate)940 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
941 {
942     m_lib.SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
943 
944     return m_lib.GetMoviesError() == noErr;
945 }
946 
947 //---------------------------------------------------------------------------
948 // wxQTMediaBackend::SetPosition
949 //
950 // 1) Create a time record struct (TimeRecord) with appropriate values
951 // 2) Pass struct to SetMovieTime
952 //---------------------------------------------------------------------------
SetPosition(wxLongLong where)953 bool wxQTMediaBackend::SetPosition(wxLongLong where)
954 {
955     // NB:  For some reason SetMovieTime does not work
956     // correctly with the Quicktime Windows SDK (6)
957     // From Muskelkatermann at the wxForum
958     // http://www.solidsteel.nl/users/wxwidgets/viewtopic.php?t=2957
959     // RN - note that I have not verified this but there
960     // is no harm in calling SetMovieTimeValue instead
961 #if 0
962     TimeRecord theTimeRecord;
963     memset(&theTimeRecord, 0, sizeof(TimeRecord));
964     theTimeRecord.value.lo = where.GetLo();
965     theTimeRecord.scale = m_lib.GetMovieTimeScale(m_movie);
966     theTimeRecord.base = m_lib.GetMovieTimeBase(m_movie);
967     m_lib.SetMovieTime(m_movie, &theTimeRecord);
968 #else
969     m_lib.SetMovieTimeValue(m_movie, where.GetLo());
970 #endif
971 
972     return (m_lib.GetMoviesError() == noErr);
973 }
974 
975 //---------------------------------------------------------------------------
976 // wxQTMediaBackend::GetPosition
977 //
978 // 1) Calls GetMovieTime to get the position we are in in the movie
979 // in milliseconds (we called
980 //---------------------------------------------------------------------------
GetPosition()981 wxLongLong wxQTMediaBackend::GetPosition()
982 {
983     return m_lib.GetMovieTime(m_movie, NULL);
984 }
985 
986 //---------------------------------------------------------------------------
987 // wxQTMediaBackend::GetVolume
988 //
989 // Gets the volume through GetMovieVolume - which returns a 16 bit short -
990 //
991 // +--------+--------+
992 // +   (1)  +   (2)  +
993 // +--------+--------+
994 //
995 // (1) first 8 bits are value before decimal
996 // (2) second 8 bits are value after decimal
997 //
998 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
999 // 1 (full gain and sound)
1000 //---------------------------------------------------------------------------
GetVolume()1001 double wxQTMediaBackend::GetVolume()
1002 {
1003     short sVolume = m_lib.GetMovieVolume(m_movie);
1004     wxASSERT(m_lib.GetMoviesError() == noErr);
1005 
1006     if (sVolume & (128 << 8)) //negative - no sound
1007         return 0.0;
1008 
1009     return sVolume / 256.0;
1010 }
1011 
1012 //---------------------------------------------------------------------------
1013 // wxQTMediaBackend::SetVolume
1014 //
1015 // Sets the volume through SetMovieVolume - which takes a 16 bit short -
1016 //
1017 // +--------+--------+
1018 // +   (1)  +   (2)  +
1019 // +--------+--------+
1020 //
1021 // (1) first 8 bits are value before decimal
1022 // (2) second 8 bits are value after decimal
1023 //
1024 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
1025 // 1 (full gain and sound)
1026 //---------------------------------------------------------------------------
SetVolume(double dVolume)1027 bool wxQTMediaBackend::SetVolume(double dVolume)
1028 {
1029     m_lib.SetMovieVolume(m_movie, (short) (dVolume * 256));
1030     return m_lib.GetMoviesError() == noErr;
1031 }
1032 
1033 //---------------------------------------------------------------------------
1034 // wxQTMediaBackend::GetDuration
1035 //
1036 // Calls GetMovieDuration
1037 //---------------------------------------------------------------------------
GetDuration()1038 wxLongLong wxQTMediaBackend::GetDuration()
1039 {
1040     return m_lib.GetMovieDuration(m_movie);
1041 }
1042 
1043 //---------------------------------------------------------------------------
1044 // wxQTMediaBackend::GetState
1045 //
1046 // Determines the current state:
1047 // if we are at the beginning, then we are stopped
1048 //---------------------------------------------------------------------------
GetState()1049 wxMediaState wxQTMediaBackend::GetState()
1050 {
1051     if (m_bPlaying)
1052         return wxMEDIASTATE_PLAYING;
1053     else if ( !m_movie || wxQTMediaBackend::GetPosition() == 0 )
1054         return wxMEDIASTATE_STOPPED;
1055     else
1056         return wxMEDIASTATE_PAUSED;
1057 }
1058 
1059 //---------------------------------------------------------------------------
1060 // wxQTMediaBackend::Cleanup
1061 //
1062 // Diposes of the movie timer, Disassociates the Movie Controller with
1063 // movie and hides it if it exists, and stops and disposes
1064 // of the QT movie
1065 //---------------------------------------------------------------------------
Cleanup()1066 void wxQTMediaBackend::Cleanup()
1067 {
1068     m_bPlaying = false;
1069 
1070     wxDELETE(m_timer);
1071 
1072     m_lib.StopMovie(m_movie);
1073 
1074     if (m_pMC)
1075     {
1076         Point thePoint;
1077         thePoint.h = thePoint.v = 0;
1078         m_lib.MCSetVisible(m_pMC, false);
1079         m_lib.MCSetMovie(m_pMC, NULL, NULL, thePoint);
1080     }
1081 
1082     m_lib.DisposeMovie(m_movie);
1083     m_movie = NULL;
1084 }
1085 
1086 //---------------------------------------------------------------------------
1087 // wxQTMediaBackend::ShowPlayerControls
1088 //
1089 // Creates a movie controller for the Movie if the user wants it
1090 //---------------------------------------------------------------------------
ShowPlayerControls(wxMediaCtrlPlayerControls flags)1091 bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
1092 {
1093     if (m_pMC)
1094     {
1095         // restore old wndproc
1096         wxSetWindowProc((HWND)m_ctrl->GetHWND(), wxWndProc);
1097         m_lib.DisposeMovieController(m_pMC);
1098         m_pMC = NULL;
1099 
1100         // movie controller height
1101         m_bestSize.y -= 16;
1102     }
1103 
1104     if (flags && m_movie)
1105     {
1106         Rect rect;
1107         wxRect wxrect = m_ctrl->GetClientRect();
1108 
1109         // make room for controller
1110         if (wxrect.width < 320)
1111             wxrect.width = 320;
1112 
1113         rect.top = (short)wxrect.y;
1114         rect.left = (short)wxrect.x;
1115         rect.right = (short)(rect.left + wxrect.width);
1116         rect.bottom = (short)(rect.top + wxrect.height);
1117 
1118         if (!m_pMC)
1119         {
1120             m_pMC = m_lib.NewMovieController(m_movie, &rect, mcTopLeftMovie |
1121                                 //                        mcScaleMovieToFit |
1122                                 //                        mcWithBadge |
1123                                                         mcWithFrame);
1124             m_lib.MCDoAction(m_pMC, 32, (void*)true); // mcActionSetKeysEnabled
1125             m_lib.MCSetActionFilterWithRefCon(m_pMC,
1126                 (WXFARPROC)wxQTMediaBackend::MCFilterProc, (void*)this);
1127             m_bestSize.y += 16; // movie controller height
1128 
1129             // By default the movie controller uses its own colour palette
1130             // for the movie which can be bad on some files, so turn it off.
1131             // Also turn off its frame / border for the movie
1132             // Also take care of a couple of the interface flags here
1133             long mcFlags = 0;
1134             m_lib.MCDoAction(m_pMC, 39/*mcActionGetFlags*/, (void*)&mcFlags);
1135 
1136             mcFlags |=
1137                 // (1<< 0) /*mcFlagSuppressMovieFrame*/ |
1138                 (1<< 3) /*mcFlagsUseWindowPalette*/
1139                 | ((flags & wxMEDIACTRLPLAYERCONTROLS_STEP)
1140                       ? 0 : (1<< 1) /*mcFlagSuppressStepButtons*/)
1141                 | ((flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME)
1142                       ? 0 : (1<< 2) /*mcFlagSuppressSpeakerButton*/)
1143 //              | (1<< 4) /*mcFlagDontInvalidate*/ // if we take care of repainting ourselves
1144                       ;
1145 
1146             m_lib.MCDoAction(m_pMC, 38/*mcActionSetFlags*/, wxUIntToPtr(mcFlags));
1147 
1148             // intercept the wndproc of our control window
1149             wxSetWindowProc((HWND)m_ctrl->GetHWND(), wxQTMediaBackend::QTWndProc);
1150 
1151             // set the user data of our window
1152             wxSetWindowUserData((HWND)m_ctrl->GetHWND(), this);
1153         }
1154     }
1155 
1156     NotifyMovieSizeChanged();
1157 
1158     return m_lib.GetMoviesError() == noErr;
1159 }
1160 
1161 //---------------------------------------------------------------------------
1162 // wxQTMediaBackend::MCFilterProc (static)
1163 //
1164 // Callback for when the movie controller receives a message
1165 //---------------------------------------------------------------------------
MCFilterProc(MovieController WXUNUSED (theController),short action,void * WXUNUSED (params),LONG_PTR refCon)1166 Boolean wxQTMediaBackend::MCFilterProc(MovieController WXUNUSED(theController),
1167                                short action,
1168                                void * WXUNUSED(params),
1169                                LONG_PTR refCon)
1170 {
1171 // NB: potential optimisation
1172 //    if (action == 1)
1173 //        return 0;
1174 
1175     wxQTMediaBackend* pThis = (wxQTMediaBackend*)refCon;
1176 
1177     switch (action)
1178     {
1179     case 1:
1180         // don't process idle events
1181         break;
1182 
1183     case 8:
1184         // play button triggered - MC will set movie to opposite state
1185         // of current - playing ? paused : playing
1186         if (pThis)
1187             pThis->m_bPlaying = !(pThis->m_bPlaying);
1188 
1189         // NB: Sometimes it doesn't redraw properly -
1190         // if you click on the button but don't move the mouse
1191         // the button will not change its state until you move
1192         // mcActionDraw and Refresh/Update combo do nothing
1193         // to help this unfortunately
1194         break;
1195 
1196     default:
1197         break;
1198     }
1199 
1200     return 0;
1201 }
1202 
1203 //---------------------------------------------------------------------------
1204 // wxQTMediaBackend::GetVideoSize
1205 //
1206 // Returns the actual size of the QT movie
1207 //---------------------------------------------------------------------------
GetVideoSize() const1208 wxSize wxQTMediaBackend::GetVideoSize() const
1209 {
1210     return m_bestSize;
1211 }
1212 
1213 //---------------------------------------------------------------------------
1214 // wxQTMediaBackend::Move
1215 //
1216 // Sets the bounds of either the Movie or Movie Controller
1217 //---------------------------------------------------------------------------
Move(int WXUNUSED (x),int WXUNUSED (y),int w,int h)1218 void wxQTMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y), int w, int h)
1219 {
1220     if (m_movie)
1221     {
1222         // make room for controller
1223         if (m_pMC)
1224         {
1225             if (w < 320)
1226                 w = 320;
1227 
1228             Rect theRect = {0, 0, (short)h, (short)w};
1229             m_lib.MCSetControllerBoundsRect(m_pMC, &theRect);
1230         }
1231         else
1232         {
1233             Rect theRect = {0, 0, (short)h, (short)w};
1234             m_lib.SetMovieBox(m_movie, &theRect);
1235         }
1236 
1237         wxASSERT(m_lib.GetMoviesError() == noErr);
1238     }
1239 }
1240 
1241 //---------------------------------------------------------------------------
1242 // wxQTMediaBackend::OnEraseBackground
1243 //
1244 // Suggestion from Greg Hazel to repaint the movie when idle
1245 // (on pause also)
1246 //
1247 // TODO: We may be repainting too much here - under what exact circumstances
1248 // do we need this? I think Move also repaints correctly for the Movie
1249 // Controller, so in that instance we don't need this either
1250 //---------------------------------------------------------------------------
OnEraseBackground(wxEraseEvent & evt)1251 void wxQTMediaEvtHandler::OnEraseBackground(wxEraseEvent& evt)
1252 {
1253     wxQuickTimeLibrary& m_pLib = m_qtb->m_lib;
1254 
1255     if ( m_qtb->m_pMC )
1256     {
1257         // repaint movie controller
1258         m_pLib.MCDoAction(m_qtb->m_pMC, 2 /*mcActionDraw*/,
1259                             m_pLib.GetNativeWindowPort(m_hwnd));
1260     }
1261     else if ( m_qtb->m_movie )
1262     {
1263         // no movie controller
1264         CGrafPtr port = (CGrafPtr)m_pLib.GetNativeWindowPort(m_hwnd);
1265 
1266         m_pLib.BeginUpdate(port);
1267         m_pLib.UpdateMovie(m_qtb->m_movie);
1268         wxASSERT(m_pLib.GetMoviesError() == noErr);
1269         m_pLib.EndUpdate(port);
1270     }
1271     else
1272     {
1273         // no movie
1274         // let the system repaint the window
1275         evt.Skip();
1276     }
1277 }
1278 
1279 //---------------------------------------------------------------------------
1280 //  End QT Backend
1281 //---------------------------------------------------------------------------
1282 
1283 // Allow the user code to use wxFORCE_LINK_MODULE() to ensure that this object
1284 // file is not discarded by the linker.
1285 #include "wx/link.h"
1286 wxFORCE_LINK_THIS_MODULE(wxmediabackend_qt)
1287 
1288 #endif // wxUSE_MEDIACTRL && wxUSE_ACTIVEX
1289