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