]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/mediactrl.mm
Fixed child positioning on window resizing.
[wxWidgets.git] / src / cocoa / mediactrl.mm
CommitLineData
4fc81cbc
RN
1/////////////////////////////////////////////////////////////////////////////
2// Name: mac/cocoa/mediactrl.cpp
3// Purpose: Built-in Media Backends for Cocoa
4// Author: Ryan Norton <wxprojects@comcast.net>
5// Modified by:
6// Created: 02/03/05
7// RCS-ID: $Id$
8// Copyright: (c) 2004-2005 Ryan Norton, (c) 2005 David Elliot
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12//===========================================================================
13// DECLARATIONS
14//===========================================================================
15
16//---------------------------------------------------------------------------
17// Pre-compiled header stuff
18//---------------------------------------------------------------------------
19
20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21#pragma implementation "mediactrl.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28#pragma hdrstop
29#endif
30
31//---------------------------------------------------------------------------
32// Includes
33//---------------------------------------------------------------------------
34#include "wx/mediactrl.h"
35
36//---------------------------------------------------------------------------
37// Compilation guard
38//---------------------------------------------------------------------------
39#if wxUSE_MEDIACTRL
40
41//===========================================================================
42// BACKEND DECLARATIONS
43//===========================================================================
44
45//---------------------------------------------------------------------------
46//
47// wxQTMediaBackend
48//
49//---------------------------------------------------------------------------
50
51//---------------------------------------------------------------------------
52// QT Includes
53//---------------------------------------------------------------------------
0b6d4714 54#include "wx/timer.h"
4fc81cbc
RN
55#include <QuickTime/QuickTime.h>
56
57#include "wx/cocoa/autorelease.h"
58#include "wx/cocoa/string.h"
59
60#import <AppKit/NSMovie.h>
61#import <AppKit/NSMovieView.h>
62
63
64class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
65{
66public:
67
68 wxQTMediaBackend();
69 ~wxQTMediaBackend();
70
71 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
72 wxWindowID id,
73 const wxPoint& pos,
74 const wxSize& size,
75 long style,
76 const wxValidator& validator,
77 const wxString& name);
78
79 virtual bool Play();
80 virtual bool Pause();
81 virtual bool Stop();
82
83 virtual bool Load(const wxString& fileName);
84 virtual bool Load(const wxURI& location);
85
86 virtual wxMediaState GetState();
87
88 virtual bool SetPosition(wxLongLong where);
89 virtual wxLongLong GetPosition();
90 virtual wxLongLong GetDuration();
91
92 virtual void Move(int x, int y, int w, int h);
93 wxSize GetVideoSize() const;
94
95 virtual double GetPlaybackRate();
96 virtual bool SetPlaybackRate(double dRate);
97
98 void Cleanup();
99 void FinishLoad();
100
101 wxSize m_bestSize; //Original movie size
102 Movie m_movie; //QT Movie handle/instance
103 NSMovieView* m_movieview; //NSMovieView instance
104 wxControl* m_ctrl; //Parent control
105 bool m_bVideo; //Whether or not we have video
0b6d4714 106 class _wxQTTimer* m_timer; //Timer for streaming the movie
4fc81cbc
RN
107
108 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
109};
110
111
112//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
113//
114// wxQTMediaBackend
115//
116//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
117
118IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
119
0b6d4714
RN
120//Time between timer calls
121#define MOVIE_DELAY 100
122
123// --------------------------------------------------------------------------
124// wxQTTimer - Handle Asyncronous Playing
125// --------------------------------------------------------------------------
126class _wxQTTimer : public wxTimer
127{
128public:
129 _wxQTTimer(Movie movie, wxQTMediaBackend* parent) :
130 m_movie(movie), m_bPaused(false), m_parent(parent)
131 {
132 }
133
134 ~_wxQTTimer()
135 {
136 }
137
138 bool GetPaused() {return m_bPaused;}
139 void SetPaused(bool bPaused) {m_bPaused = bPaused;}
140
141 //-----------------------------------------------------------------------
142 // _wxQTTimer::Notify
143 //
144 // 1) Checks to see if the movie is done, and if not continues
145 // streaming the movie
146 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
147 // the movie.
148 //-----------------------------------------------------------------------
149 void Notify()
150 {
151 if (!m_bPaused)
152 {
153 if(!IsMovieDone(m_movie))
154 MoviesTask(m_movie, MOVIE_DELAY);
155 else
156 {
157 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
158 m_parent->m_ctrl->GetId());
159 m_parent->m_ctrl->ProcessEvent(theEvent);
160
161 if(theEvent.IsAllowed())
162 {
163 Stop();
164 m_parent->Stop();
165 wxASSERT(::GetMoviesError() == noErr);
166
167 //send the event to our child
168 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
169 m_parent->m_ctrl->GetId());
170 m_parent->m_ctrl->ProcessEvent(theEvent);
171 }
172 }
173 }
174 }
175
176protected:
177 Movie m_movie; //Our movie instance
178 bool m_bPaused; //Whether we are paused or not
179 wxQTMediaBackend* m_parent; //Backend pointer
180};
181
4fc81cbc
RN
182//---------------------------------------------------------------------------
183// wxQTMediaBackend Constructor
184//
185// Sets m_timer to NULL signifying we havn't loaded anything yet
186//---------------------------------------------------------------------------
0b6d4714 187wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
4fc81cbc
RN
188{
189}
190
191//---------------------------------------------------------------------------
192// wxQTMediaBackend Destructor
193//
194// 1) Cleans up the QuickTime movie instance
195// 2) Decrements the QuickTime reference counter - if this reaches
196// 0, QuickTime shuts down
197// 3) Decrements the QuickTime Windows Media Layer reference counter -
198// if this reaches 0, QuickTime shuts down the Windows Media Layer
199//---------------------------------------------------------------------------
200wxQTMediaBackend::~wxQTMediaBackend()
201{
0b6d4714
RN
202 if(m_timer)
203 Cleanup();
4fc81cbc
RN
204
205 //Note that ExitMovies() is not neccessary...
0b6d4714 206 ExitMovies();
4fc81cbc
RN
207}
208
209//---------------------------------------------------------------------------
210// wxQTMediaBackend::CreateControl
211//
212// 1) Intializes QuickTime
213// 2) Creates the control window
214//---------------------------------------------------------------------------
215bool wxQTMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
216 wxWindowID wid,
217 const wxPoint& pos,
218 const wxSize& size,
219 long style,
220 const wxValidator& validator,
221 const wxString& name)
222{
223 EnterMovies();
224
225 wxMediaCtrl* ctrl = (wxMediaCtrl*) inctrl;
226
227 //Create the control base
ecd20d4a 228 wxASSERT(ctrl->CreateBase(parent,wid,pos,size,style, validator, name));
4fc81cbc
RN
229
230 //Create the NSMovieView
231 ctrl->SetNSView(NULL);
ecd20d4a 232 NSMovieView* theView = [[NSMovieView alloc] initWithFrame: ctrl->MakeDefaultNSRect(size)];
4fc81cbc
RN
233 ctrl->SetNSView(theView);
234 [theView release];
235
236 if (parent)
237 {
238 parent->AddChild(ctrl);
239 parent->CocoaAddChild(ctrl);
240 ctrl->SetInitialFrameRect(pos,size);
241 }
0b6d4714 242
ecd20d4a 243 [theView showController:false adjustingSize:true];
4fc81cbc
RN
244 m_movieview = theView;
245 m_ctrl = ctrl;
246 return true;
247}
248
249//---------------------------------------------------------------------------
250// wxQTMediaBackend::Load (file version)
251//
252// Calls the URI version
253//---------------------------------------------------------------------------
254bool wxQTMediaBackend::Load(const wxString& fileName)
255{
256 return Load(
257 wxURI(
258 wxString( wxT("file://") ) + fileName
259 )
260 );
261}
262
263//---------------------------------------------------------------------------
264// wxQTMediaBackend::Load (URL Version)
265//
266// 1) Build an escaped URI from location
267// ...
268//---------------------------------------------------------------------------
269bool wxQTMediaBackend::Load(const wxURI& location)
270{
0b6d4714
RN
271 if(m_timer)
272 Cleanup();
4fc81cbc
RN
273
274 wxString theURI = location.BuildURI();
275
276 [m_movieview setMovie:[[NSMovie alloc] initWithURL: [NSURL URLWithString: wxNSStringWithWxString(theURI)]
277 byReference: YES ] ];
278
279 m_movie = (Movie) [[m_movieview movie] QTMovie];
280
0b6d4714
RN
281 //preroll movie for streaming
282 //TODO:Async this using threads?
283 TimeValue timeNow;
284 Fixed playRate;
285 timeNow = GetMovieTime(m_movie, NULL);
286 playRate = GetMoviePreferredRate(m_movie);
287 PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
288 PrerollMovie(m_movie, timeNow, playRate);
289 SetMovieRate(m_movie, playRate);
290
4fc81cbc
RN
291 FinishLoad();
292
293 return ::GetMoviesError() == noErr;
294}
295
296//---------------------------------------------------------------------------
297// wxQTMediaBackend::FinishLoad
0b6d4714
RN
298//
299// 1) Create the movie timer
300// 2) Get real size of movie for GetBestSize/sizers
301// 3) See if there is video in the movie, and if so then either
302// SetMovieGWorld if < 10.2 or use Native CreateMovieControl
303// 4) Set the movie time scale to something usable so that seeking
304// etc. will work correctly
305// 5) Refresh parent window
4fc81cbc
RN
306//---------------------------------------------------------------------------
307void wxQTMediaBackend::FinishLoad()
308{
0b6d4714
RN
309 m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this);
310 wxASSERT(m_timer);
311
4fc81cbc
RN
312 //get the real size of the movie
313 Rect outRect;
314 ::GetMovieNaturalBoundsRect (m_movie, &outRect);
315 wxASSERT(::GetMoviesError() == noErr);
316
317 m_bestSize.x = outRect.right - outRect.left;
318 m_bestSize.y = outRect.bottom - outRect.top;
319
320 //we want millisecond precision
321 ::SetMovieTimeScale(m_movie, 1000);
322 wxASSERT(::GetMoviesError() == noErr);
323
324 //
325 //Here, if the parent of the control has a sizer - we
326 //tell it to recalculate the size of this control since
327 //the user opened a seperate media file
328 //
329 m_ctrl->InvalidateBestSize();
330 m_ctrl->GetParent()->Layout();
331 m_ctrl->GetParent()->Refresh();
332 m_ctrl->GetParent()->Update();
333}
334
335//---------------------------------------------------------------------------
336// wxQTMediaBackend::Play
337//
338// 1) Start the QT movie
339// 2) Start the movie loading timer
340//---------------------------------------------------------------------------
341bool wxQTMediaBackend::Play()
342{
0b6d4714
RN
343 ::StartMovie(m_movie);
344 m_timer->SetPaused(false);
345 m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
4fc81cbc
RN
346 return ::GetMoviesError() == noErr;
347}
348
349//---------------------------------------------------------------------------
350// wxQTMediaBackend::Pause
351//
352// 1) Stop the movie
353// 2) Stop the movie timer
354//---------------------------------------------------------------------------
355bool wxQTMediaBackend::Pause()
356{
0b6d4714
RN
357 ::StopMovie(m_movie);
358 m_timer->SetPaused(true);
359 m_timer->Stop();
4fc81cbc
RN
360 return ::GetMoviesError() == noErr;
361}
362
363//---------------------------------------------------------------------------
364// wxQTMediaBackend::Stop
365//
366// 1) Stop the movie
367// 2) Stop the movie timer
368// 3) Seek to the beginning of the movie
369//---------------------------------------------------------------------------
370bool wxQTMediaBackend::Stop()
371{
0b6d4714
RN
372 m_timer->SetPaused(false);
373 m_timer->Stop();
374
375 ::StopMovie(m_movie);
376 if(::GetMoviesError() != noErr)
377 return false;
378
379 ::GoToBeginningOfMovie(m_movie);
4fc81cbc
RN
380 return ::GetMoviesError() == noErr;
381}
382
383//---------------------------------------------------------------------------
384// wxQTMediaBackend::GetPlaybackRate
385//
386// 1) Get the movie playback rate from ::GetMovieRate
387//---------------------------------------------------------------------------
388double wxQTMediaBackend::GetPlaybackRate()
389{
390 return ( ((double)::GetMovieRate(m_movie)) / 0x10000);
391}
392
393//---------------------------------------------------------------------------
394// wxQTMediaBackend::SetPlaybackRate
395//
396// 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
397//---------------------------------------------------------------------------
398bool wxQTMediaBackend::SetPlaybackRate(double dRate)
399{
400 ::SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
401 return ::GetMoviesError() == noErr;
402}
403
404//---------------------------------------------------------------------------
405// wxQTMediaBackend::SetPosition
406//
407// 1) Create a time record struct (TimeRecord) with appropriate values
408// 2) Pass struct to SetMovieTime
409//---------------------------------------------------------------------------
410bool wxQTMediaBackend::SetPosition(wxLongLong where)
411{
412 TimeRecord theTimeRecord;
413 memset(&theTimeRecord, 0, sizeof(TimeRecord));
414 theTimeRecord.value.lo = where.GetValue();
415 theTimeRecord.scale = ::GetMovieTimeScale(m_movie);
416 theTimeRecord.base = ::GetMovieTimeBase(m_movie);
417 ::SetMovieTime(m_movie, &theTimeRecord);
418
419 if (::GetMoviesError() != noErr)
420 return false;
421
422 return true;
423}
424
425//---------------------------------------------------------------------------
426// wxQTMediaBackend::GetPosition
427//
428// Calls GetMovieTime
429//---------------------------------------------------------------------------
430wxLongLong wxQTMediaBackend::GetPosition()
431{
432 return ::GetMovieTime(m_movie, NULL);
433}
434
435//---------------------------------------------------------------------------
436// wxQTMediaBackend::GetDuration
437//
438// Calls GetMovieDuration
439//---------------------------------------------------------------------------
440wxLongLong wxQTMediaBackend::GetDuration()
441{
442 return ::GetMovieDuration(m_movie);
443}
444
445//---------------------------------------------------------------------------
446// wxQTMediaBackend::GetState
447//
448// Determines the current state - the timer keeps track of whether or not
449// we are paused or stopped (if the timer is running we are playing)
450//---------------------------------------------------------------------------
451wxMediaState wxQTMediaBackend::GetState()
452{
0b6d4714
RN
453 if ( !m_timer || (m_timer->IsRunning() == false &&
454 m_timer->GetPaused() == false) )
ecd20d4a 455 return wxMEDIASTATE_STOPPED;
0b6d4714
RN
456
457 if( m_timer->IsRunning() == true )
458 return wxMEDIASTATE_PLAYING;
4fc81cbc
RN
459 else
460 return wxMEDIASTATE_PAUSED;
461}
462
463//---------------------------------------------------------------------------
464// wxQTMediaBackend::Cleanup
465//
466// Diposes of the movie timer, Control if native, and stops and disposes
467// of the QT movie
468//---------------------------------------------------------------------------
469void wxQTMediaBackend::Cleanup()
470{
0b6d4714
RN
471 delete m_timer;
472 m_timer = NULL;
473
474 [[m_movieview movie] release];
475 [m_movieview setMovie:NULL];
4fc81cbc
RN
476}
477
478//---------------------------------------------------------------------------
479// wxQTMediaBackend::GetVideoSize
480//
481// Returns the actual size of the QT movie
482//---------------------------------------------------------------------------
483wxSize wxQTMediaBackend::GetVideoSize() const
484{
485 return m_bestSize;
486}
487
488//---------------------------------------------------------------------------
489// wxQTMediaBackend::Move
490//
491// Nothin... cocoa takes care of this for us
492//---------------------------------------------------------------------------
493void wxQTMediaBackend::Move(int x, int y, int w, int h)
494{
495}
496
497
498//in source file that contains stuff you don't directly use
499#include <wx/html/forcelnk.h>
500FORCE_LINK_ME(basewxmediabackends);
501
502#endif //wxUSE_MEDIACTRL