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