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