]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/mediactrl.cpp
create stock GDI objects on demand; use const with GDI objects appropriately (patch...
[wxWidgets.git] / src / mac / carbon / mediactrl.cpp
CommitLineData
1a680109 1/////////////////////////////////////////////////////////////////////////////
ff4aedc5
RN
2// Name: mac/carbon/mediactrl.cpp
3// Purpose: Built-in Media Backends for Mac
1a680109 4// Author: Ryan Norton <wxprojects@comcast.net>
ff4aedc5 5// Modified by:
1a680109
RN
6// Created: 11/07/04
7// RCS-ID: $Id$
0c81ef7f 8// Copyright: (c) 2004-2006 Ryan Norton
1a680109
RN
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
bf354396 12//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0c81ef7f
SC
13// OK, a casual overseer of this file may wonder why we don't use
14// either CreateMovieControl or HIMovieView...
557002cf 15//
0c81ef7f
SC
16// CreateMovieControl
17// 1) Need to dispose and create each time a new movie is loaded
18// 2) Not that many real advantages
19// 3) Progressively buggier in higher OSX versions
20// (see main.c of QTCarbonShell sample for details)
21// HIMovieView
22// 1) Crashes on destruction in ALL cases on quite a few systems!
23// (With the only real "alternative" is to simply not
24// dispose of it and let it leak...)
25// 2) Massive refreshing bugs with its movie controller between
26// movies
557002cf 27//
0c81ef7f
SC
28// At one point we had a complete implementation for CreateMovieControl
29// and on my (RN) local copy I had one for HIMovieView - but they
30// were simply deemed to be too buggy/unuseful. HIMovieView could
31// have been useful as well because it uses OpenGL contexts instead
32// of GWorlds. Perhaps someday when someone comes out with some
33// ingenious workarounds :).
bf354396
VZ
34//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
1a680109
RN
36// For compilers that support precompilation, includes "wx.h".
37#include "wx/wxprec.h"
38
ff4aedc5 39#include "wx/mediactrl.h"
1a680109 40
9419b0d6
DS
41// uma is for wxMacFSSpec
42#include "wx/mac/uma.h"
43#include "wx/timer.h"
44
9419b0d6 45// standard QT stuff
0c81ef7f 46#ifndef __DARWIN__
9419b0d6
DS
47#include <Movies.h>
48#include <Gestalt.h>
49#include <QuickTimeComponents.h>
50#else
51#include <QuickTime/QuickTimeComponents.h>
52#endif
53
1a680109
RN
54#if wxUSE_MEDIACTRL
55
3b5023b9 56//---------------------------------------------------------------------------
0c81ef7f 57// Height and Width of movie controller in the movie control (apple samples)
bf354396
VZ
58//---------------------------------------------------------------------------
59#define wxMCWIDTH 320
60#define wxMCHEIGHT 16
61
ff4aedc5
RN
62//===========================================================================
63// BACKEND DECLARATIONS
64//===========================================================================
212945de 65
ff4aedc5 66//---------------------------------------------------------------------------
ff4aedc5 67// wxQTMediaBackend
ff4aedc5 68//---------------------------------------------------------------------------
1a680109 69
bf354396 70class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
ff4aedc5
RN
71{
72public:
ff4aedc5
RN
73 wxQTMediaBackend();
74 ~wxQTMediaBackend();
75
d0ee33f5 76 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 77 wxWindowID id,
d0ee33f5 78 const wxPoint& pos,
ff4aedc5 79 const wxSize& size,
d0ee33f5 80 long style,
ff4aedc5
RN
81 const wxValidator& validator,
82 const wxString& name);
83
0c81ef7f
SC
84 virtual bool Load(const wxString& fileName);
85 virtual bool Load(const wxURI& location);
86
ff4aedc5
RN
87 virtual bool Play();
88 virtual bool Pause();
89 virtual bool Stop();
90
ff4aedc5
RN
91 virtual wxMediaState GetState();
92
93 virtual bool SetPosition(wxLongLong where);
94 virtual wxLongLong GetPosition();
95 virtual wxLongLong GetDuration();
96
97 virtual void Move(int x, int y, int w, int h);
98 wxSize GetVideoSize() const;
99
100 virtual double GetPlaybackRate();
101 virtual bool SetPlaybackRate(double dRate);
102
c5191fbd
VZ
103 virtual double GetVolume();
104 virtual bool SetVolume(double);
105
ff4aedc5
RN
106 void Cleanup();
107 void FinishLoad();
108
bf354396 109 virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
9419b0d6 110
557002cf
VZ
111 virtual wxLongLong GetDownloadProgress();
112 virtual wxLongLong GetDownloadTotal();
bf354396 113
0c81ef7f
SC
114 virtual void MacVisibilityChanged();
115
557002cf 116 //
bf354396 117 // ------ Implementation from now on --------
557002cf
VZ
118 //
119 bool DoPause();
120 bool DoStop();
592a247d 121
bf354396
VZ
122 void DoLoadBestSize();
123 void DoSetControllerVisible(wxMediaCtrlPlayerControls flags);
124
557002cf
VZ
125 wxLongLong GetDataSizeFromStart(TimeValue end);
126
0c81ef7f
SC
127 Boolean IsQuickTime4Installed();
128 void DoNewMovieController();
129
130 static pascal void PPRMProc(
131 Movie theMovie, OSErr theErr, void* theRefCon);
132
bf354396 133 //TODO: Last param actually long - does this work on 64bit machines?
9419b0d6 134 static pascal Boolean MCFilterProc(MovieController theController,
bf354396
VZ
135 short action, void *params, long refCon);
136
0c81ef7f
SC
137 static pascal OSStatus WindowEventHandler(
138 EventHandlerCallRef inHandlerCallRef,
139 EventRef inEvent, void *inUserData );
bf354396
VZ
140
141 wxSize m_bestSize; // Original movie size
bf354396 142 Movie m_movie; // Movie instance
bf354396
VZ
143 bool m_bPlaying; // Whether media is playing or not
144 class wxTimer* m_timer; // Timer for streaming the movie
145 MovieController m_mc; // MovieController instance
146 wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags
9419b0d6 147
0c81ef7f
SC
148 // Event handlers and UPPs/Callbacks
149 EventHandlerRef m_windowEventHandler;
150 EventHandlerUPP m_windowUPP;
151
557002cf 152 MoviePrePrerollCompleteUPP m_preprerollupp;
557002cf 153 MCActionFilterWithRefConUPP m_mcactionupp;
ff4aedc5 154
0c81ef7f
SC
155 GWorldPtr m_movieWorld; //Offscreen movie GWorld
156
bf354396 157 friend class wxQTMediaEvtHandler;
9419b0d6 158
d0ee33f5 159 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend)
ff4aedc5
RN
160};
161
bf354396
VZ
162// helper to hijack background erasing for the QT window
163class WXDLLIMPEXP_MEDIA wxQTMediaEvtHandler : public wxEvtHandler
164{
165public:
166 wxQTMediaEvtHandler(wxQTMediaBackend *qtb)
167 {
168 m_qtb = qtb;
169
9419b0d6
DS
170 qtb->m_ctrl->Connect(
171 qtb->m_ctrl->GetId(), wxEVT_ERASE_BACKGROUND,
bf354396
VZ
172 wxEraseEventHandler(wxQTMediaEvtHandler::OnEraseBackground),
173 NULL, this);
174 }
175
176 void OnEraseBackground(wxEraseEvent& event);
177
178private:
179 wxQTMediaBackend *m_qtb;
180
181 DECLARE_NO_COPY_CLASS(wxQTMediaEvtHandler)
182};
183
bf354396
VZ
184//===========================================================================
185// IMPLEMENTATION
186//===========================================================================
187
ff4aedc5
RN
188
189//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
0c81ef7f 190//
ff4aedc5 191// wxQTMediaBackend
0c81ef7f 192//
ff4aedc5
RN
193//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
194
412e0d47 195IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend)
1a680109 196
bf354396
VZ
197//Time between timer calls - this is the Apple recommondation to the TCL
198//team I believe
199#define MOVIE_DELAY 20
1a680109 200
bf354396
VZ
201//---------------------------------------------------------------------------
202// wxQTMediaLoadTimer
203//
204// QT, esp. QT for Windows is very picky about how you go about
205// async loading. If you were to go through a Windows message loop
206// or a MoviesTask or both and then check the movie load state
207// it would still return 1000 (loading)... even (pre)prerolling doesn't
208// help. However, making a load timer like this works
209//---------------------------------------------------------------------------
210class wxQTMediaLoadTimer : public wxTimer
1a680109
RN
211{
212public:
0c81ef7f
SC
213 wxQTMediaLoadTimer(wxQTMediaBackend* parent) :
214 m_parent(parent) {}
1a680109 215
bf354396
VZ
216 void Notify()
217 {
bf354396 218 ::MCIdle(m_parent->m_mc);
9419b0d6
DS
219
220 // kMovieLoadStatePlayable is not enough on MAC:
221 // it plays, but IsMovieDone might return true (!)
222 // sure we need to wait until kMovieLoadStatePlaythroughOK
0c81ef7f 223 if (::GetMovieLoadState(m_parent->m_movie) >= 20000)
9419b0d6 224 {
bf354396
VZ
225 m_parent->FinishLoad();
226 delete this;
9419b0d6 227 }
1a680109
RN
228 }
229
bf354396 230protected:
9419b0d6 231 wxQTMediaBackend *m_parent; // Backend pointer
bf354396
VZ
232};
233
234// --------------------------------------------------------------------------
235// wxQTMediaPlayTimer - Handle Asyncronous Playing
236//
237// 1) Checks to see if the movie is done, and if not continues
238// streaming the movie
239// 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
240// the movie.
241// --------------------------------------------------------------------------
242class wxQTMediaPlayTimer : public wxTimer
243{
244public:
0c81ef7f
SC
245 wxQTMediaPlayTimer(wxQTMediaBackend* parent) :
246 m_parent(parent) {}
1a680109
RN
247
248 void Notify()
9419b0d6 249 {
bf354396
VZ
250 //
251 // OK, a little explaining - basically originally
252 // we only called MoviesTask if the movie was actually
253 // playing (not paused or stopped)... this was before
254 // we realized MoviesTask actually handles repainting
255 // of the current frame - so if you were to resize
256 // or something it would previously not redraw that
257 // portion of the movie.
258 //
259 // So now we call MoviesTask always so that it repaints
260 // correctly.
261 //
262 ::MCIdle(m_parent->m_mc);
ff4aedc5 263
0c81ef7f 264 //
bf354396
VZ
265 // Handle the stop event - if the movie has reached
266 // the end, notify our handler
0c81ef7f
SC
267 //
268 if (::IsMovieDone(m_parent->m_movie))
9419b0d6 269 {
bf354396
VZ
270 if ( m_parent->SendStopEvent() )
271 {
ff4aedc5
RN
272 m_parent->Stop();
273 wxASSERT(::GetMoviesError() == noErr);
274
bf354396 275 m_parent->QueueFinishEvent();
1a680109
RN
276 }
277 }
278 }
279
280protected:
9419b0d6 281 wxQTMediaBackend* m_parent; // Backend pointer
1a680109
RN
282};
283
bf354396 284
ff4aedc5 285//---------------------------------------------------------------------------
e7b97da3 286// wxQTMediaBackend Constructor
ff4aedc5
RN
287//
288// Sets m_timer to NULL signifying we havn't loaded anything yet
289//---------------------------------------------------------------------------
9419b0d6 290wxQTMediaBackend::wxQTMediaBackend()
bf354396
VZ
291 : m_movie(NULL), m_bPlaying(false), m_timer(NULL)
292 , m_mc(NULL), m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
0c81ef7f 293 , m_preprerollupp(NULL), m_movieWorld(NULL)
1a680109 294{
1a680109
RN
295}
296
ff4aedc5
RN
297//---------------------------------------------------------------------------
298// wxQTMediaBackend Destructor
299//
300// 1) Cleans up the QuickTime movie instance
301// 2) Decrements the QuickTime reference counter - if this reaches
302// 0, QuickTime shuts down
303// 3) Decrements the QuickTime Windows Media Layer reference counter -
304// if this reaches 0, QuickTime shuts down the Windows Media Layer
305//---------------------------------------------------------------------------
306wxQTMediaBackend::~wxQTMediaBackend()
1a680109 307{
9419b0d6 308 if (m_movie)
ff4aedc5 309 Cleanup();
1a680109 310
bf354396 311 // Cleanup for moviecontroller
9419b0d6 312 if (m_mc)
bf354396
VZ
313 {
314 // destroy wxQTMediaEvtHandler we pushed on it
315 m_ctrl->PopEventHandler(true);
0c81ef7f
SC
316 RemoveEventHandler(m_windowEventHandler);
317 DisposeEventHandlerUPP(m_windowUPP);
557002cf
VZ
318
319 // Dispose of the movie controller
bf354396 320 ::DisposeMovieController(m_mc);
0c81ef7f 321 m_mc = NULL;
557002cf 322 DisposeMCActionFilterWithRefConUPP(m_mcactionupp);
0c81ef7f
SC
323
324 // Dispose of offscreen GWorld
325 ::DisposeGWorld(m_movieWorld);
bf354396 326 }
bf354396 327
9419b0d6 328 // Note that ExitMovies() is not necessary...
ff4aedc5 329 ExitMovies();
1a680109
RN
330}
331
ff4aedc5
RN
332//---------------------------------------------------------------------------
333// wxQTMediaBackend::CreateControl
334//
335// 1) Intializes QuickTime
336// 2) Creates the control window
337//---------------------------------------------------------------------------
9419b0d6
DS
338bool wxQTMediaBackend::CreateControl(
339 wxControl* ctrl,
340 wxWindow* parent,
341 wxWindowID id,
342 const wxPoint& pos,
343 const wxSize& size,
344 long style,
345 const wxValidator& validator,
346 const wxString& name)
1a680109 347{
bf354396 348 if (!IsQuickTime4Installed())
1a680109 349 return false;
1a680109 350
ff4aedc5
RN
351 EnterMovies();
352
0c81ef7f
SC
353 wxMediaCtrl* mediactrl = (wxMediaCtrl*)ctrl;
354
355 //
ff4aedc5
RN
356 // Create window
357 // By default wxWindow(s) is created with a border -
358 // so we need to get rid of those
359 //
360 // Since we don't have a child window like most other
361 // backends, we don't need wxCLIP_CHILDREN
0c81ef7f
SC
362 //
363 if ( !mediactrl->wxControl::Create(
9419b0d6
DS
364 parent, id, pos, size,
365 wxWindow::MacRemoveBordersFromStyle(style),
366 validator, name))
367 {
1a680109 368 return false;
9419b0d6 369 }
1a680109 370
ecd20d4a 371#if wxUSE_VALIDATORS
0c81ef7f 372 mediactrl->SetValidator(validator);
ecd20d4a
RN
373#endif
374
0c81ef7f 375 m_ctrl = mediactrl;
1a680109
RN
376 return true;
377}
378
bf354396
VZ
379//---------------------------------------------------------------------------
380// wxQTMediaBackend::IsQuickTime4Installed
381//
9419b0d6
DS
382// Determines whether version 4 of QT is installed
383// (Pretty much for Classic only)
bf354396 384//---------------------------------------------------------------------------
bf354396
VZ
385Boolean wxQTMediaBackend::IsQuickTime4Installed()
386{
9419b0d6 387 OSErr error;
bf354396
VZ
388 long result;
389
9419b0d6 390 error = Gestalt(gestaltQuickTime, &result);
bf354396
VZ
391 return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0400);
392}
bf354396 393
ff4aedc5
RN
394//---------------------------------------------------------------------------
395// wxQTMediaBackend::Load (file version)
396//
397// 1) Get an FSSpec from the Windows path name
398// 2) Open the movie
399// 3) Obtain the movie instance from the movie resource
3b5023b9
RN
400// 4) Close the movie resource
401// 5) Finish loading
ff4aedc5
RN
402//---------------------------------------------------------------------------
403bool wxQTMediaBackend::Load(const wxString& fileName)
1a680109 404{
9419b0d6 405 if (m_movie)
1a680109
RN
406 Cleanup();
407
0c81ef7f
SC
408 ::ClearMoviesStickyError(); // clear previous errors so
409 // GetMoviesStickyError is useful
410
1a680109
RN
411 OSErr err = noErr;
412 short movieResFile;
413 FSSpec sfFile;
d0ee33f5 414
9419b0d6
DS
415 wxMacFilename2FSSpec( fileName, &sfFile );
416 if (OpenMovieFile( &sfFile, &movieResFile, fsRdPerm ) != noErr)
1a680109
RN
417 return false;
418
419 short movieResID = 0;
420 Str255 movieName;
557002cf 421
9419b0d6
DS
422 err = NewMovieFromFile(
423 &m_movie,
424 movieResFile,
425 &movieResID,
426 movieName,
427 newMovieActive,
428 NULL); // wasChanged
557002cf 429
0c81ef7f
SC
430 //
431 // check GetMoviesStickyError() because it may not find the
432 // proper codec and play black video and other strange effects,
433 // not to mention mess up the dynamic backend loading scheme
434 // of wxMediaCtrl - so it just does what the QuickTime player does
435 //
436 if (err == noErr && ::GetMoviesStickyError() == noErr)
bf354396 437 {
9419b0d6 438 ::CloseMovieFile(movieResFile);
1a680109 439
bf354396 440 // Create movie controller/control
bf354396 441 DoNewMovieController();
9419b0d6
DS
442
443 FinishLoad();
0c81ef7f 444 return true;
bf354396 445 }
9419b0d6 446
0c81ef7f 447 return false;
bf354396 448}
1a680109 449
ff4aedc5 450//---------------------------------------------------------------------------
3b5023b9 451// wxQTMediaBackend::Load (URL Version)
ff4aedc5 452//
3b5023b9
RN
453// 1) Build an escaped URI from location
454// 2) Create a handle to store the URI string
455// 3) Put the URI string inside the handle
456// 4) Make a QuickTime URL data ref from the handle with the URI in it
457// 5) Clean up the URI string handle
458// 6) Do some prerolling
459// 7) Finish Loading
ff4aedc5
RN
460//---------------------------------------------------------------------------
461bool wxQTMediaBackend::Load(const wxURI& location)
1a680109 462{
9419b0d6 463 if (m_movie)
1a680109
RN
464 Cleanup();
465
0c81ef7f
SC
466 ::ClearMoviesStickyError(); // clear previous errors so
467 // GetMoviesStickyError is useful
468
1a680109 469 wxString theURI = location.BuildURI();
0c81ef7f 470 OSErr err;
1a680109 471
0c81ef7f
SC
472 size_t len;
473 const char* theURIString;
474
475#if wxUSE_UNICODE
476 wxCharBuffer buf = wxConvLocal.cWC2MB(theURI, theURI.length(), &len);
477 theURIString = buf;
478#else
479 theURIString = theURI;
480 len = theURI.length();
481#endif
1a680109 482
0c81ef7f 483 Handle theHandle = ::NewHandleClear(len + 1);
1a680109
RN
484 wxASSERT(theHandle);
485
0c81ef7f 486 ::BlockMoveData(theURIString, *theHandle, len + 1);
1a680109 487
9419b0d6
DS
488 // create the movie from the handle that refers to the URI
489 err = ::NewMovieFromDataRef(
490 &m_movie,
491 newMovieActive | newMovieAsyncOK /* | newMovieIdleImportOK*/,
492 NULL, theHandle,
493 URLDataHandlerSubType);
1a680109 494
bf354396 495 ::DisposeHandle(theHandle);
1a680109 496
0c81ef7f 497 if (err == noErr && ::GetMoviesStickyError() == noErr)
bf354396 498 {
9419b0d6 499 // Movie controller resets prerolling, so we must create first
bf354396 500 DoNewMovieController();
9419b0d6 501
bf354396 502 long timeNow;
9419b0d6 503 Fixed playRate;
1a680109 504
bf354396
VZ
505 timeNow = ::GetMovieTime(m_movie, NULL);
506 wxASSERT(::GetMoviesError() == noErr);
1a680109 507
bf354396
VZ
508 playRate = ::GetMoviePreferredRate(m_movie);
509 wxASSERT(::GetMoviesError() == noErr);
510
0c81ef7f 511 //
bf354396
VZ
512 // Note that the callback here is optional,
513 // but without it PrePrerollMovie can be buggy
514 // (see Apple ml). Also, some may wonder
515 // why we need this at all - this is because
516 // Apple docs say QuickTime streamed movies
517 // require it if you don't use a Movie Controller,
518 // which we don't by default.
519 //
0c81ef7f
SC
520 m_preprerollupp =
521 NewMoviePrePrerollCompleteUPP( wxQTMediaBackend::PPRMProc );
522 ::PrePrerollMovie( m_movie, timeNow, playRate,
523 m_preprerollupp, (void*)this);
9419b0d6 524
0c81ef7f
SC
525 return true;
526 }
1a680109 527
0c81ef7f 528 return false;
bf354396 529}
bf354396
VZ
530
531//---------------------------------------------------------------------------
532// wxQTMediaBackend::DoNewMovieController
533//
534// Attaches movie to moviecontroller or creates moviecontroller
535// if not created yet
536//---------------------------------------------------------------------------
bf354396
VZ
537void wxQTMediaBackend::DoNewMovieController()
538{
9419b0d6 539 if (!m_mc)
bf354396
VZ
540 {
541 // Get top level window ref for some mac functions
542 WindowRef wrTLW = (WindowRef) m_ctrl->MacGetTopLevelWindowRef();
9419b0d6
DS
543
544 // MovieController not set up yet, so we need to create a new one.
545 // You have to pass a valid movie to NewMovieController, evidently
bf354396
VZ
546 ::SetMovieGWorld(m_movie,
547 (CGrafPtr) GetWindowPort(wrTLW),
548 NULL);
549 wxASSERT(::GetMoviesError() == noErr);
550
9419b0d6
DS
551 Rect bounds = wxMacGetBoundsForControl(
552 m_ctrl,
553 m_ctrl->GetPosition(),
554 m_ctrl->GetSize());
bf354396 555
9419b0d6
DS
556 m_mc = ::NewMovieController(
557 m_movie, &bounds,
558 mcTopLeftMovie | mcNotVisible /* | mcWithFrame */ );
bf354396 559 wxASSERT(::GetMoviesError() == noErr);
9419b0d6
DS
560
561 ::MCDoAction(m_mc, 32, (void*)true); // mcActionSetKeysEnabled
bf354396
VZ
562 wxASSERT(::GetMoviesError() == noErr);
563
564 // Setup a callback so we can tell when the user presses
565 // play on the player controls
0c81ef7f
SC
566 m_mcactionupp =
567 NewMCActionFilterWithRefConUPP( wxQTMediaBackend::MCFilterProc );
9419b0d6 568 ::MCSetActionFilterWithRefCon( m_mc, m_mcactionupp, (long)this );
bf354396
VZ
569 wxASSERT(::GetMoviesError() == noErr);
570
9419b0d6 571 // Part of a suggestion from Greg Hazel to repaint movie when idle
bf354396 572 m_ctrl->PushEventHandler(new wxQTMediaEvtHandler(this));
9419b0d6 573
0c81ef7f
SC
574 // Create offscreen GWorld for where to "show" when window is hidden
575 Rect worldRect;
576 worldRect.left = worldRect.top = 0;
577 worldRect.right = worldRect.bottom = 1;
578 ::NewGWorld(&m_movieWorld, 0, &worldRect, NULL, NULL, 0);
579
580 // Catch window messages:
581 // if we do not do this and if the user clicks the play
582 // button on the controller, for instance, nothing will happen...
583 EventTypeSpec theWindowEventTypes[] =
9419b0d6
DS
584 {
585 { kEventClassMouse, kEventMouseDown },
586 { kEventClassMouse, kEventMouseUp },
587 { kEventClassMouse, kEventMouseDragged },
588 { kEventClassKeyboard, kEventRawKeyDown },
589 { kEventClassKeyboard, kEventRawKeyRepeat },
590 { kEventClassKeyboard, kEventRawKeyUp },
591 { kEventClassWindow, kEventWindowUpdate },
592 { kEventClassWindow, kEventWindowActivated },
593 { kEventClassWindow, kEventWindowDeactivated }
594 };
0c81ef7f
SC
595 m_windowUPP =
596 NewEventHandlerUPP( wxQTMediaBackend::WindowEventHandler );
9419b0d6
DS
597 InstallWindowEventHandler(
598 wrTLW,
0c81ef7f
SC
599 m_windowUPP,
600 GetEventTypeCount( theWindowEventTypes ), theWindowEventTypes,
601 this,
602 &m_windowEventHandler );
bf354396
VZ
603 }
604 else
605 {
9419b0d6 606 // MovieController already created:
bf354396
VZ
607 // Just change the movie in it and we're good to go
608 Point thePoint;
609 thePoint.h = thePoint.v = 0;
9419b0d6 610 ::MCSetMovie(m_mc, m_movie,
bf354396 611 (WindowRef)m_ctrl->MacGetTopLevelWindowRef(),
9419b0d6 612 thePoint);
bf354396 613 wxASSERT(::GetMoviesError() == noErr);
1a680109 614 }
bf354396 615}
bf354396
VZ
616
617//---------------------------------------------------------------------------
618// wxQTMediaBackend::FinishLoad
619//
620// Performs operations after a movie ready to play/loaded.
621//---------------------------------------------------------------------------
622void wxQTMediaBackend::FinishLoad()
9419b0d6
DS
623{
624 // Dispose of the PrePrerollMovieUPP if we used it
557002cf 625 DisposeMoviePrePrerollCompleteUPP(m_preprerollupp);
9419b0d6 626
bf354396
VZ
627 // get the real size of the movie
628 DoLoadBestSize();
629
9419b0d6
DS
630 // show the player controls if the user wants to
631 if (m_interfaceflags)
bf354396 632 DoSetControllerVisible(m_interfaceflags);
1a680109 633
9419b0d6 634 // we want millisecond precision
1a680109 635 ::SetMovieTimeScale(m_movie, 1000);
ff4aedc5
RN
636 wxASSERT(::GetMoviesError() == noErr);
637
9419b0d6 638 // start movie progress timer
0c81ef7f 639 m_timer = new wxQTMediaPlayTimer(this);
bf354396
VZ
640 wxASSERT(m_timer);
641 m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
642
9419b0d6 643 // send loaded event and refresh size
bf354396
VZ
644 NotifyMovieLoaded();
645}
646
647//---------------------------------------------------------------------------
648// wxQTMediaBackend::DoLoadBestSize
649//
650// Sets the best size of the control from the real size of the movie
651//---------------------------------------------------------------------------
652void wxQTMediaBackend::DoLoadBestSize()
653{
9419b0d6 654 // get the real size of the movie
bf354396 655 Rect outRect;
9419b0d6 656 ::GetMovieNaturalBoundsRect(m_movie, &outRect);
bf354396
VZ
657 wxASSERT(::GetMoviesError() == noErr);
658
9419b0d6 659 // determine best size
bf354396
VZ
660 m_bestSize.x = outRect.right - outRect.left;
661 m_bestSize.y = outRect.bottom - outRect.top;
1a680109
RN
662}
663
ff4aedc5 664//---------------------------------------------------------------------------
e7b97da3 665// wxQTMediaBackend::Play
ff4aedc5 666//
bf354396 667// Start the QT movie
557002cf 668// (Apple recommends mcActionPrerollAndPlay but that's QT 4.1+)
ff4aedc5
RN
669//---------------------------------------------------------------------------
670bool wxQTMediaBackend::Play()
1a680109 671{
bf354396 672 Fixed fixRate = (Fixed) (wxQTMediaBackend::GetPlaybackRate() * 0x10000);
9419b0d6 673 if (!fixRate)
bf354396 674 fixRate = ::GetMoviePreferredRate(m_movie);
9419b0d6 675
bf354396
VZ
676 wxASSERT(fixRate != 0);
677
9419b0d6
DS
678 if (!m_bPlaying)
679 ::MCDoAction( m_mc, 8 /* mcActionPlay */, (void*) fixRate);
557002cf 680
9419b0d6
DS
681 bool result = (::GetMoviesError() == noErr);
682 if (result)
557002cf 683 {
9419b0d6 684 m_bPlaying = true;
557002cf 685 QueuePlayEvent();
557002cf 686 }
9419b0d6
DS
687
688 return result;
1a680109
RN
689}
690
ff4aedc5 691//---------------------------------------------------------------------------
e7b97da3 692// wxQTMediaBackend::Pause
ff4aedc5 693//
bf354396 694// Stop the movie
ff4aedc5 695//---------------------------------------------------------------------------
557002cf 696bool wxQTMediaBackend::DoPause()
1a680109 697{
9419b0d6
DS
698 // Stop the movie A.K.A. ::StopMovie(m_movie);
699 if (m_bPlaying)
bf354396 700 {
9419b0d6 701 ::MCDoAction( m_mc, 8 /*mcActionPlay*/, (void *) 0);
bf354396 702 m_bPlaying = false;
9419b0d6 703 return ::GetMoviesError() == noErr;
bf354396 704 }
9419b0d6
DS
705
706 // already paused
707 return true;
557002cf 708}
592a247d 709
557002cf
VZ
710bool wxQTMediaBackend::Pause()
711{
712 bool bSuccess = DoPause();
9419b0d6 713 if (bSuccess)
557002cf 714 this->QueuePauseEvent();
9419b0d6
DS
715
716 return bSuccess;
1a680109
RN
717}
718
ff4aedc5 719//---------------------------------------------------------------------------
e7b97da3 720// wxQTMediaBackend::Stop
ff4aedc5 721//
3b5023b9 722// 1) Stop the movie
bf354396 723// 2) Seek to the beginning of the movie
ff4aedc5 724//---------------------------------------------------------------------------
4ac483eb 725bool wxQTMediaBackend::DoStop()
1a680109 726{
4ac483eb 727 if (!wxQTMediaBackend::DoPause())
1a680109 728 return false;
d0ee33f5 729
1a680109
RN
730 ::GoToBeginningOfMovie(m_movie);
731 return ::GetMoviesError() == noErr;
732}
733
557002cf
VZ
734bool wxQTMediaBackend::Stop()
735{
736 bool bSuccess = DoStop();
9419b0d6 737 if (bSuccess)
557002cf 738 QueueStopEvent();
9419b0d6
DS
739
740 return bSuccess;
557002cf
VZ
741}
742
ff4aedc5 743//---------------------------------------------------------------------------
e7b97da3 744// wxQTMediaBackend::GetPlaybackRate
ff4aedc5 745//
3b5023b9 746// 1) Get the movie playback rate from ::GetMovieRate
ff4aedc5
RN
747//---------------------------------------------------------------------------
748double wxQTMediaBackend::GetPlaybackRate()
1a680109 749{
1a680109
RN
750 return ( ((double)::GetMovieRate(m_movie)) / 0x10000);
751}
752
ff4aedc5 753//---------------------------------------------------------------------------
e7b97da3 754// wxQTMediaBackend::SetPlaybackRate
ff4aedc5 755//
3b5023b9 756// 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
ff4aedc5
RN
757//---------------------------------------------------------------------------
758bool wxQTMediaBackend::SetPlaybackRate(double dRate)
1a680109 759{
1a680109
RN
760 ::SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
761 return ::GetMoviesError() == noErr;
762}
763
ff4aedc5 764//---------------------------------------------------------------------------
e7b97da3 765// wxQTMediaBackend::SetPosition
ff4aedc5 766//
3b5023b9
RN
767// 1) Create a time record struct (TimeRecord) with appropriate values
768// 2) Pass struct to SetMovieTime
ff4aedc5
RN
769//---------------------------------------------------------------------------
770bool wxQTMediaBackend::SetPosition(wxLongLong where)
1a680109 771{
1a680109
RN
772 TimeRecord theTimeRecord;
773 memset(&theTimeRecord, 0, sizeof(TimeRecord));
ff4aedc5 774 theTimeRecord.value.lo = where.GetValue();
1a680109
RN
775 theTimeRecord.scale = ::GetMovieTimeScale(m_movie);
776 theTimeRecord.base = ::GetMovieTimeBase(m_movie);
777 ::SetMovieTime(m_movie, &theTimeRecord);
778
779 if (::GetMoviesError() != noErr)
780 return false;
781
782 return true;
783}
784
ff4aedc5 785//---------------------------------------------------------------------------
e7b97da3 786// wxQTMediaBackend::GetPosition
ff4aedc5 787//
3b5023b9 788// Calls GetMovieTime
ff4aedc5
RN
789//---------------------------------------------------------------------------
790wxLongLong wxQTMediaBackend::GetPosition()
1a680109 791{
1a680109
RN
792 return ::GetMovieTime(m_movie, NULL);
793}
794
ff4aedc5 795//---------------------------------------------------------------------------
c5191fbd
VZ
796// wxQTMediaBackend::GetVolume
797//
798// Gets the volume through GetMovieVolume - which returns a 16 bit short -
799//
800// +--------+--------+
801// + (1) + (2) +
802// +--------+--------+
803//
804// (1) first 8 bits are value before decimal
805// (2) second 8 bits are value after decimal
806//
807// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
808// 1 (full gain and sound)
809//---------------------------------------------------------------------------
810double wxQTMediaBackend::GetVolume()
811{
bf354396 812 short sVolume = ::GetMovieVolume(m_movie);
c5191fbd 813
9419b0d6 814 if (sVolume & (128 << 8)) //negative - no sound
c5191fbd
VZ
815 return 0.0;
816
9419b0d6 817 return sVolume / 256.0;
c5191fbd
VZ
818}
819
820//---------------------------------------------------------------------------
821// wxQTMediaBackend::SetVolume
822//
823// Sets the volume through SetMovieVolume - which takes a 16 bit short -
824//
825// +--------+--------+
826// + (1) + (2) +
827// +--------+--------+
828//
829// (1) first 8 bits are value before decimal
830// (2) second 8 bits are value after decimal
831//
832// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
833// 1 (full gain and sound)
834//---------------------------------------------------------------------------
835bool wxQTMediaBackend::SetVolume(double dVolume)
836{
bf354396 837 ::SetMovieVolume(m_movie, (short) (dVolume * 256));
c5191fbd
VZ
838 return true;
839}
9419b0d6
DS
840
841//---------------------------------------------------------------------------
e7b97da3 842// wxQTMediaBackend::GetDuration
ff4aedc5 843//
3b5023b9 844// Calls GetMovieDuration
ff4aedc5
RN
845//---------------------------------------------------------------------------
846wxLongLong wxQTMediaBackend::GetDuration()
1a680109 847{
1a680109
RN
848 return ::GetMovieDuration(m_movie);
849}
850
ff4aedc5 851//---------------------------------------------------------------------------
e7b97da3 852// wxQTMediaBackend::GetState
ff4aedc5 853//
3b5023b9
RN
854// Determines the current state - the timer keeps track of whether or not
855// we are paused or stopped (if the timer is running we are playing)
ff4aedc5
RN
856//---------------------------------------------------------------------------
857wxMediaState wxQTMediaBackend::GetState()
1a680109 858{
bf354396 859 // Could use
9419b0d6 860 // GetMovieActive/IsMovieDone/SetMovieActive
bf354396 861 // combo if implemented that way
9419b0d6 862 if (m_bPlaying)
1a680109 863 return wxMEDIASTATE_PLAYING;
0c81ef7f 864 else if (!m_movie || wxQTMediaBackend::GetPosition() == 0)
bf354396 865 return wxMEDIASTATE_STOPPED;
1a680109
RN
866 else
867 return wxMEDIASTATE_PAUSED;
868}
869
ff4aedc5 870//---------------------------------------------------------------------------
e7b97da3 871// wxQTMediaBackend::Cleanup
ff4aedc5 872//
3b5023b9
RN
873// Diposes of the movie timer, Control if native, and stops and disposes
874// of the QT movie
ff4aedc5
RN
875//---------------------------------------------------------------------------
876void wxQTMediaBackend::Cleanup()
1a680109 877{
bf354396 878 m_bPlaying = false;
9419b0d6 879 if (m_timer)
bf354396 880 {
9419b0d6
DS
881 delete m_timer;
882 m_timer = NULL;
bf354396 883 }
d0ee33f5 884
9419b0d6 885 // Stop the movie:
bf354396
VZ
886 // Apple samples with CreateMovieControl typically
887 // install a event handler and do this on the dispose
888 // event, but we do it here for simplicity
889 // (It might keep playing for several seconds after
9419b0d6 890 // control destruction if not)
bf354396 891 wxQTMediaBackend::Pause();
9419b0d6 892
bf354396 893 // Dispose of control or remove movie from MovieController
bf354396
VZ
894 Point thePoint;
895 thePoint.h = thePoint.v = 0;
896 ::MCSetVisible(m_mc, false);
897 ::MCSetMovie(m_mc, NULL, NULL, thePoint);
1a680109 898
bf354396 899 ::DisposeMovie(m_movie);
9419b0d6 900 m_movie = NULL;
bf354396
VZ
901}
902
ff4aedc5 903//---------------------------------------------------------------------------
e7b97da3 904// wxQTMediaBackend::GetVideoSize
ff4aedc5 905//
3b5023b9 906// Returns the actual size of the QT movie
ff4aedc5
RN
907//---------------------------------------------------------------------------
908wxSize wxQTMediaBackend::GetVideoSize() const
1a680109
RN
909{
910 return m_bestSize;
911}
912
ff4aedc5
RN
913//---------------------------------------------------------------------------
914// wxQTMediaBackend::Move
915//
557002cf
VZ
916// Move the movie controller or movie control
917// (we need to actually move the movie control manually...)
918// Top 10 things to do with quicktime in March 93's issue
919// of DEVELOP - very useful
920// http:// www.mactech.com/articles/develop/issue_13/031-033_QuickTime_column.html
921// OLD NOTE: Calling MCSetControllerBoundsRect without detaching
922// supposively resulted in a crash back then. Current code even
923// with CFM classic runs fine. If there is ever a problem,
924// take out the if 0 lines below
ff4aedc5
RN
925//---------------------------------------------------------------------------
926void wxQTMediaBackend::Move(int x, int y, int w, int h)
1a680109 927{
9419b0d6 928 if (m_timer)
1a680109 929 {
9419b0d6
DS
930 m_ctrl->GetParent()->MacWindowToRootWindow(&x, &y);
931 Rect theRect = {y, x, y + h, x + w};
932
0c81ef7f 933#if 0 // see note above
9419b0d6
DS
934 ::MCSetControllerAttached(m_mc, false);
935 wxASSERT(::GetMoviesError() == noErr);
557002cf 936#endif
9419b0d6 937
bf354396 938 ::MCSetControllerBoundsRect(m_mc, &theRect);
1a680109 939 wxASSERT(::GetMoviesError() == noErr);
557002cf
VZ
940
941#if 0 // see note above
9419b0d6 942 if (m_interfaceflags)
557002cf 943 {
9419b0d6
DS
944 ::MCSetVisible(m_mc, true);
945 wxASSERT(::GetMoviesError() == noErr);
946 }
557002cf 947#endif
1a680109
RN
948 }
949}
950
bf354396
VZ
951//---------------------------------------------------------------------------
952// wxQTMediaBackend::DoSetControllerVisible
953//
954// Utility function that takes care of showing the moviecontroller
955// and showing/hiding the particular controls on it
956//---------------------------------------------------------------------------
0c81ef7f
SC
957void wxQTMediaBackend::DoSetControllerVisible(
958 wxMediaCtrlPlayerControls flags)
9419b0d6
DS
959{
960 ::MCSetVisible(m_mc, true);
961
bf354396 962 // Take care of subcontrols
9419b0d6 963 if (::GetMoviesError() == noErr)
bf354396
VZ
964 {
965 long mcFlags = 0;
966 ::MCDoAction(m_mc, 39/*mcActionGetFlags*/, (void*)&mcFlags);
9419b0d6
DS
967
968 if (::GetMoviesError() == noErr)
969 {
bf354396 970 mcFlags |= ( //(1<<0)/*mcFlagSuppressMovieFrame*/ |
9419b0d6 971 (1 << 3)/*mcFlagsUseWindowPalette*/
bf354396 972 | ((flags & wxMEDIACTRLPLAYERCONTROLS_STEP)
9419b0d6 973 ? 0 : (1 << 1)/*mcFlagSuppressStepButtons*/)
bf354396 974 | ((flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME)
9419b0d6 975 ? 0 : (1 << 2)/*mcFlagSuppressSpeakerButton*/)
0c81ef7f
SC
976 //if we take care of repainting ourselves
977 // | (1 << 4) /*mcFlagDontInvalidate*/
bf354396 978 );
9419b0d6
DS
979
980 ::MCDoAction(m_mc, 38/*mcActionSetFlags*/, (void*)mcFlags);
bf354396 981 }
9419b0d6
DS
982 }
983
984 // Adjust height and width of best size for movie controller
985 // if the user wants it shown
bf354396
VZ
986 m_bestSize.x = m_bestSize.x > wxMCWIDTH ? m_bestSize.x : wxMCWIDTH;
987 m_bestSize.y += wxMCHEIGHT;
988}
989
990//---------------------------------------------------------------------------
991// wxQTMediaBackend::ShowPlayerControls
992//
993// Shows/Hides subcontrols on the media control
994//---------------------------------------------------------------------------
995bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
996{
9419b0d6
DS
997 if (!m_mc)
998 return false; // no movie controller...
999
bf354396 1000 bool bSizeChanged = false;
9419b0d6
DS
1001
1002 // if the controller is visible and we want to hide it do so
1003 if (m_interfaceflags && !flags)
bf354396
VZ
1004 {
1005 bSizeChanged = true;
1006 DoLoadBestSize();
9419b0d6 1007 ::MCSetVisible(m_mc, false);
bf354396 1008 }
9419b0d6 1009 else if (!m_interfaceflags && flags) // show controller if hidden
bf354396
VZ
1010 {
1011 bSizeChanged = true;
1012 DoSetControllerVisible(flags);
1013 }
9419b0d6
DS
1014
1015 // readjust parent sizers
1016 if (bSizeChanged)
bf354396 1017 {
9419b0d6
DS
1018 NotifyMovieSizeChanged();
1019
1020 // remember state in case of loading new media
bf354396 1021 m_interfaceflags = flags;
9419b0d6
DS
1022 }
1023
557002cf
VZ
1024 return ::GetMoviesError() == noErr;
1025}
1026
1027//---------------------------------------------------------------------------
1028// wxQTMediaBackend::GetDataSizeFromStart
1029//
1030// Calls either GetMovieDataSize or GetMovieDataSize64 with a value
1031// of 0 for the starting value
1032//---------------------------------------------------------------------------
1033wxLongLong wxQTMediaBackend::GetDataSizeFromStart(TimeValue end)
1034{
1035#if 0 // old pre-qt4 way
1036 return ::GetMovieDataSize(m_movie, 0, end)
1037#else // qt4 way
1038 wide llDataSize;
1039 ::GetMovieDataSize64(m_movie, 0, end, &llDataSize);
1040 return wxLongLong(llDataSize.hi, llDataSize.lo);
1041#endif
1042}
1043
1044//---------------------------------------------------------------------------
1045// wxQTMediaBackend::GetDownloadProgress
1046//---------------------------------------------------------------------------
1047wxLongLong wxQTMediaBackend::GetDownloadProgress()
1048{
1049#if 0 // hackish and slow
1050 Handle hMovie = NewHandle(0);
1051 PutMovieIntoHandle(m_movie, hMovie);
1052 long lSize = GetHandleSize(hMovie);
1053 DisposeHandle(hMovie);
9419b0d6 1054
557002cf
VZ
1055 return lSize;
1056#else
1057 TimeValue tv;
9419b0d6 1058 if (::GetMaxLoadedTimeInMovie(m_movie, &tv) != noErr)
557002cf
VZ
1059 {
1060 wxLogDebug(wxT("GetMaxLoadedTimeInMovie failed"));
1061 return 0;
592a247d 1062 }
9419b0d6 1063
557002cf
VZ
1064 return wxQTMediaBackend::GetDataSizeFromStart(tv);
1065#endif
1066}
592a247d 1067
557002cf
VZ
1068//---------------------------------------------------------------------------
1069// wxQTMediaBackend::GetDownloadTotal
1070//---------------------------------------------------------------------------
1071wxLongLong wxQTMediaBackend::GetDownloadTotal()
1072{
0c81ef7f
SC
1073 return wxQTMediaBackend::GetDataSizeFromStart(
1074 ::GetMovieDuration(m_movie)
1075 );
1076}
1077
1078//---------------------------------------------------------------------------
1079// wxQTMediaBackend::MacVisibilityChanged
1080//
1081// The main problem here is that Windows quicktime, for example,
1082// renders more directly to a HWND. Mac quicktime does not do this
1083// and instead renders to the port of the WindowRef/WindowPtr on top
1084// of everything else/all other windows.
1085//
1086// So, for example, if you were to have a CreateTabsControl/wxNotebook
1087// and change pages, even if you called HIViewSetVisible/SetControlVisibility
1088// directly the movie will still continue playing on top of everything else
1089// if you went to a different tab.
1090//
1091// Note that another issue, and why we call MCSetControllerPort instead
1092// of SetMovieGWorld directly, is that in addition to rendering on
1093// top of everything else the last created controller steals mouse and
1094// other input from everything else in the window, including other
1095// controllers. Setting the port of it releases this behaviour.
1096//---------------------------------------------------------------------------
1097void wxQTMediaBackend::MacVisibilityChanged()
1098{
1099 if(!m_mc || !m_ctrl->m_bLoaded)
1100 return; //not initialized yet
1101
1102 if(m_ctrl->MacIsReallyShown())
1103 {
1104 //The window is being shown again, so set the GWorld of the
1105 //controller back to the port of the parent WindowRef
1106 WindowRef wrTLW =
1107 (WindowRef) m_ctrl->MacGetTopLevelWindowRef();
1108
1109 ::MCSetControllerPort(m_mc, (CGrafPtr) GetWindowPort(wrTLW));
1110 wxASSERT(::GetMoviesError() == noErr);
1111 }
1112 else
1113 {
1114 //We are being hidden - set the GWorld of the controller
1115 //to the offscreen GWorld
1116 ::MCSetControllerPort(m_mc, m_movieWorld);
1117 wxASSERT(::GetMoviesError() == noErr);
1118 }
bf354396
VZ
1119}
1120
1121//---------------------------------------------------------------------------
1122// wxQTMediaBackend::OnEraseBackground
1123//
1124// Suggestion from Greg Hazel to repaint the movie when idle
1125// (on pause also)
1126//---------------------------------------------------------------------------
bf354396
VZ
1127void wxQTMediaEvtHandler::OnEraseBackground(wxEraseEvent& evt)
1128{
9419b0d6 1129 // Work around Nasty OSX drawing bug:
bf354396 1130 // http://lists.apple.com/archives/QuickTime-API/2002/Feb/msg00311.html
9419b0d6 1131 WindowRef wrTLW = (WindowRef) m_qtb->m_ctrl->MacGetTopLevelWindowRef();
bf354396 1132
0c81ef7f
SC
1133 RgnHandle region = ::MCGetControllerBoundsRgn(m_qtb->m_mc);
1134 ::MCInvalidate(m_qtb->m_mc, wrTLW, region);
1135 ::MCIdle(m_qtb->m_mc);
1136}
1137
1138//---------------------------------------------------------------------------
1139// wxQTMediaBackend::PPRMProc (static)
1140//
1141// Called when done PrePrerolling the movie.
1142// Note that in 99% of the cases this does nothing...
1143// Anyway we set up the loading timer here to tell us when the movie is done
1144//---------------------------------------------------------------------------
1145pascal void wxQTMediaBackend::PPRMProc(
1146 Movie theMovie,
1147 OSErr WXUNUSED_UNLESS_DEBUG(theErr),
1148 void* theRefCon)
1149{
1150 wxASSERT( theMovie );
1151 wxASSERT( theRefCon );
1152 wxASSERT( theErr == noErr );
1153
1154 wxQTMediaBackend* pBE = (wxQTMediaBackend*) theRefCon;
1155
1156 long lTime = ::GetMovieTime(theMovie,NULL);
1157 Fixed rate = ::GetMoviePreferredRate(theMovie);
1158 ::PrerollMovie(theMovie,lTime,rate);
1159 pBE->m_timer = new wxQTMediaLoadTimer(pBE);
1160 pBE->m_timer->Start(MOVIE_DELAY);
bf354396 1161}
bf354396
VZ
1162
1163//---------------------------------------------------------------------------
0c81ef7f
SC
1164// wxQTMediaBackend::MCFilterProc (static)
1165//
1166// Callback for when the movie controller recieves a message
1167//---------------------------------------------------------------------------
1168pascal Boolean wxQTMediaBackend::MCFilterProc(
1169 MovieController WXUNUSED(theController),
1170 short action,
1171 void * WXUNUSED(params),
1172 long refCon)
1173{
1174 wxQTMediaBackend* pThis = (wxQTMediaBackend*)refCon;
1175
1176 switch (action)
1177 {
1178 case 1:
1179 // don't process idle events
1180 break;
1181
1182 case 8:
1183 // play button triggered - MC will set movie to opposite state
1184 // of current - playing ? paused : playing
1185 pThis->m_bPlaying = !(pThis->m_bPlaying);
1186 break;
1187
1188 default:
1189 break;
1190 }
1191
1192 return 0;
1193}
1194
1195//---------------------------------------------------------------------------
1196// wxQTMediaBackend::WindowEventHandler [static]
bf354396
VZ
1197//
1198// Event callback for the top level window of our control that passes
9419b0d6 1199// messages to our moviecontroller so it can receive mouse clicks etc.
bf354396 1200//---------------------------------------------------------------------------
0c81ef7f 1201pascal OSStatus wxQTMediaBackend::WindowEventHandler(
9419b0d6
DS
1202 EventHandlerCallRef inHandlerCallRef,
1203 EventRef inEvent,
1204 void *inUserData)
bf354396 1205{
0c81ef7f
SC
1206 wxQTMediaBackend* be = (wxQTMediaBackend*) inUserData;
1207
1208 // Only process keyboard messages on this window if it actually
1209 // has focus, otherwise it will steal keystrokes from other windows!
1210 // As well as when it is not loaded properly as it
1211 // will crash in MCIsPlayerEvent
1212 if((GetEventClass(inEvent) == kEventClassKeyboard &&
1213 wxWindow::FindFocus() != be->m_ctrl)
1214 || !be->m_ctrl->m_bLoaded)
557002cf 1215 return eventNotHandledErr;
9419b0d6 1216
0c81ef7f 1217 // Pass the event onto the movie controller
bf354396
VZ
1218 EventRecord theEvent;
1219 ConvertEventRefToEventRecord( inEvent, &theEvent );
1220 OSStatus err;
592a247d 1221
0c81ef7f
SC
1222 // TODO: Apple says MCIsPlayerEvent is depreciated and
1223 // MCClick, MCKey, MCIdle etc. should be used
1224 // (RN: Of course that's what they say about
1225 // CreateMovieControl and HIMovieView as well, LOL!)
1226 err = ::MCIsPlayerEvent( be->m_mc, &theEvent );
9419b0d6 1227
0c81ef7f 1228 // Pass on to other event handlers if not handled- i.e. wx
9419b0d6 1229 if (err != noErr)
bf354396
VZ
1230 return noErr;
1231 else
1232 return eventNotHandledErr;
1233}
ff4aedc5 1234
9419b0d6 1235// in source file that contains stuff you don't directly use
f572d649 1236#include "wx/html/forcelnk.h"
412e0d47 1237FORCE_LINK_ME(basewxmediabackends)
ff4aedc5 1238
9419b0d6 1239#endif // wxUSE_MEDIACTRL