]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/mediactrl.mm
No changes, just use wxRecursionGuard instead of manual boolean flag.
[wxWidgets.git] / src / osx / cocoa / mediactrl.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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 // Copyright: (c) 2004-2005 Ryan Norton, (c) 2005 David Elliot
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 //===========================================================================
12 // DECLARATIONS
13 //===========================================================================
14
15 //---------------------------------------------------------------------------
16 // Pre-compiled header stuff
17 //---------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 //---------------------------------------------------------------------------
27 // Compilation guard
28 //---------------------------------------------------------------------------
29 #if wxUSE_MEDIACTRL
30
31 #include "wx/mediactrl.h"
32
33 #ifndef WX_PRECOMP
34 #include "wx/timer.h"
35 #endif
36
37 #include "wx/osx/private.h"
38
39 //===========================================================================
40 // BACKEND DECLARATIONS
41 //===========================================================================
42
43 //---------------------------------------------------------------------------
44 //
45 // wxQTMediaBackend
46 //
47 //---------------------------------------------------------------------------
48
49 //---------------------------------------------------------------------------
50 // QT Includes
51 //---------------------------------------------------------------------------
52 #include <QTKit/QTKit.h>
53
54 #include "wx/cocoa/autorelease.h"
55 #include "wx/cocoa/string.h"
56
57 class WXDLLIMPEXP_FWD_MEDIA wxQTMediaBackend;
58
59 @interface wxQTMovie : QTMovie {
60
61 wxQTMediaBackend* m_backend;
62 }
63
64 -(BOOL)isPlaying;
65
66 @end
67
68 class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
69 {
70 public:
71
72 wxQTMediaBackend();
73 ~wxQTMediaBackend();
74
75 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
76 wxWindowID id,
77 const wxPoint& pos,
78 const wxSize& size,
79 long style,
80 const wxValidator& validator,
81 const wxString& name);
82
83 virtual bool Play();
84 virtual bool Pause();
85 virtual bool Stop();
86
87 virtual bool Load(const wxString& fileName);
88 virtual bool Load(const wxURI& location);
89
90 virtual wxMediaState GetState();
91
92 virtual bool SetPosition(wxLongLong where);
93 virtual wxLongLong GetPosition();
94 virtual wxLongLong GetDuration();
95
96 virtual void Move(int x, int y, int w, int h);
97 wxSize GetVideoSize() const;
98
99 virtual double GetPlaybackRate();
100 virtual bool SetPlaybackRate(double dRate);
101
102 virtual double GetVolume();
103 virtual bool SetVolume(double dVolume);
104
105 void Cleanup();
106 void FinishLoad();
107
108 virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
109 private:
110 void DoShowPlayerControls(wxMediaCtrlPlayerControls flags);
111
112 wxSize m_bestSize; //Original movie size
113 wxQTMovie* m_movie; //QTMovie handle/instance
114 QTMovieView* m_movieview; //QTMovieView instance
115
116 wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags
117
118 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
119 };
120
121 // --------------------------------------------------------------------------
122 // wxQTMovie
123 // --------------------------------------------------------------------------
124
125 @implementation wxQTMovie
126
127 - (id)initWithURL:(NSURL *)url error:(NSError **)errorPtr
128 {
129 if ( [super initWithURL:url error:errorPtr] != nil )
130 {
131 m_backend = NULL;
132
133 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
134 [nc addObserver:self selector:@selector(movieDidEnd:)
135 name:QTMovieDidEndNotification object:nil];
136 [nc addObserver:self selector:@selector(movieRateChanged:)
137 name:QTMovieRateDidChangeNotification object:nil];
138 [nc addObserver:self selector:@selector(loadStateChanged:)
139 name:QTMovieLoadStateDidChangeNotification object:nil];
140
141 return self;
142 }
143 else
144 return nil;
145 }
146
147 -(void)dealloc
148 {
149 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
150 [nc removeObserver:self];
151
152 [super dealloc];
153 }
154
155 -(wxQTMediaBackend*) backend;
156 {
157 return m_backend;
158 }
159
160 -(void) setBackend:(wxQTMediaBackend*) backend
161 {
162 m_backend = backend;
163 }
164
165 - (void)movieDidEnd:(NSNotification *)notification
166 {
167 if ( m_backend )
168 {
169 if ( m_backend->SendStopEvent() )
170 m_backend->QueueFinishEvent();
171 }
172 }
173
174 - (void)movieRateChanged:(NSNotification *)notification
175 {
176 NSDictionary *userInfo = [notification userInfo];
177
178 NSNumber *newRate = [userInfo objectForKey:QTMovieRateDidChangeNotificationParameter];
179
180 if ([newRate intValue] == 0)
181 {
182 m_backend->QueuePauseEvent();
183 }
184 else if ( [self isPlaying] == NO )
185 {
186 m_backend->QueuePlayEvent();
187 }
188 }
189
190 -(void)loadStateChanged:(NSNotification *)notification
191 {
192 QTMovie *movie = [notification object];
193 long loadState = [[movie attributeForKey:QTMovieLoadStateAttribute] longValue];
194 if ( loadState == QTMovieLoadStateError )
195 {
196 // error occurred
197 }
198 else if (loadState >= QTMovieLoadStatePlayable)
199 {
200 // the movie has loaded enough media data to begin playing, but we don't have an event for that yet
201 }
202 else if (loadState >= QTMovieLoadStateComplete) // we might use QTMovieLoadStatePlaythroughOK
203 {
204 m_backend->FinishLoad();
205 }
206 }
207
208 -(BOOL)isPlaying
209 {
210 if ([self rate] == 0)
211 {
212 return NO;
213 }
214
215 return YES;
216 }
217
218 @end
219
220 // --------------------------------------------------------------------------
221 // wxQTMediaBackend
222 // --------------------------------------------------------------------------
223
224 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
225
226 wxQTMediaBackend::wxQTMediaBackend() :
227 m_movie(nil), m_movieview(nil),
228 m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
229 {
230 }
231
232 wxQTMediaBackend::~wxQTMediaBackend()
233 {
234 Cleanup();
235 }
236
237 bool wxQTMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
238 wxWindowID wid,
239 const wxPoint& pos,
240 const wxSize& size,
241 long style,
242 const wxValidator& validator,
243 const wxString& name)
244 {
245 wxMediaCtrl* mediactrl = (wxMediaCtrl*) inctrl;
246
247 mediactrl->DontCreatePeer();
248
249 if ( !mediactrl->wxControl::Create(
250 parent, wid, pos, size,
251 wxWindow::MacRemoveBordersFromStyle(style),
252 validator, name))
253 {
254 return false;
255 }
256
257 NSRect r = wxOSXGetFrameForControl( mediactrl, pos , size ) ;
258 QTMovieView* theView = [[QTMovieView alloc] initWithFrame: r];
259
260 wxWidgetCocoaImpl* impl = new wxWidgetCocoaImpl(mediactrl,theView);
261 mediactrl->SetPeer(impl);
262
263 m_movieview = theView;
264 // will be set up after load
265 [theView setControllerVisible:NO];
266
267 m_ctrl = mediactrl;
268 return true;
269 }
270
271 bool wxQTMediaBackend::Load(const wxString& fileName)
272 {
273 return Load(
274 wxURI(
275 wxString( wxT("file://") ) + fileName
276 )
277 );
278 }
279
280 bool wxQTMediaBackend::Load(const wxURI& location)
281 {
282 wxCFStringRef uri(location.BuildURI());
283 NSURL *url = [NSURL URLWithString: uri.AsNSString()];
284
285 if (! [wxQTMovie canInitWithURL:url])
286 return false;
287
288 [m_movie release];
289 wxQTMovie* movie = [[wxQTMovie alloc] initWithURL:url error: nil ];
290
291 m_movie = movie;
292 if (movie != nil)
293 {
294 [m_movie setBackend:this];
295 [m_movieview setMovie:movie];
296
297 // If the media file is able to be loaded quickly then there may not be
298 // any QTMovieLoadStateDidChangeNotification message sent, so we need to
299 // also check the load state here and finish our initialization if it has
300 // been loaded.
301 long loadState = [[m_movie attributeForKey:QTMovieLoadStateAttribute] longValue];
302 if (loadState >= QTMovieLoadStateComplete)
303 {
304 FinishLoad();
305 }
306 }
307
308 return movie != nil;
309 }
310
311 void wxQTMediaBackend::FinishLoad()
312 {
313 DoShowPlayerControls(m_interfaceflags);
314
315 NSSize s = [[m_movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
316 m_bestSize = wxSize(s.width, s.height);
317
318 NotifyMovieLoaded();
319 }
320
321 bool wxQTMediaBackend::Play()
322 {
323 [m_movieview play:nil];
324 return true;
325 }
326
327 bool wxQTMediaBackend::Pause()
328 {
329 [m_movieview pause:nil];
330 return true;
331 }
332
333 bool wxQTMediaBackend::Stop()
334 {
335 [m_movieview pause:nil];
336 [m_movieview gotoBeginning:nil];
337 return true;
338 }
339
340 double wxQTMediaBackend::GetVolume()
341 {
342 return [m_movie volume];
343 }
344
345 bool wxQTMediaBackend::SetVolume(double dVolume)
346 {
347 [m_movie setVolume:dVolume];
348 return true;
349 }
350 double wxQTMediaBackend::GetPlaybackRate()
351 {
352 return [m_movie rate];
353 }
354
355 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
356 {
357 [m_movie setRate:dRate];
358 return true;
359 }
360
361 bool wxQTMediaBackend::SetPosition(wxLongLong where)
362 {
363 QTTime position;
364 position = [m_movie currentTime];
365 position.timeValue = (where.GetValue() / 1000.0) * position.timeScale;
366 [m_movie setCurrentTime:position];
367 return true;
368 }
369
370 wxLongLong wxQTMediaBackend::GetPosition()
371 {
372 QTTime position = [m_movie currentTime];
373 return ((double) position.timeValue) / position.timeScale * 1000;
374 }
375
376 wxLongLong wxQTMediaBackend::GetDuration()
377 {
378 QTTime duration = [m_movie duration];
379 return ((double) duration.timeValue) / duration.timeScale * 1000;
380 }
381
382 wxMediaState wxQTMediaBackend::GetState()
383 {
384 if ( [m_movie isPlaying] )
385 return wxMEDIASTATE_PLAYING;
386 else
387 {
388 if ( GetPosition() == 0 )
389 return wxMEDIASTATE_STOPPED;
390 else
391 return wxMEDIASTATE_PAUSED;
392 }
393 }
394
395 void wxQTMediaBackend::Cleanup()
396 {
397 [m_movieview setMovie:NULL];
398 [m_movie release];
399 m_movie = nil;
400 }
401
402 wxSize wxQTMediaBackend::GetVideoSize() const
403 {
404 return m_bestSize;
405 }
406
407 void wxQTMediaBackend::Move(int x, int y, int w, int h)
408 {
409 // as we have a native player, no need to move the video area
410 }
411
412 bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
413 {
414 if ( m_interfaceflags != flags )
415 DoShowPlayerControls(flags);
416
417 m_interfaceflags = flags;
418 return true;
419 }
420
421 void wxQTMediaBackend::DoShowPlayerControls(wxMediaCtrlPlayerControls flags)
422 {
423 if (flags == wxMEDIACTRLPLAYERCONTROLS_NONE )
424 {
425 [m_movieview setControllerVisible:NO];
426 }
427 else
428 {
429 [m_movieview setControllerVisible:YES];
430
431 [m_movieview setStepButtonsVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_STEP) ? YES:NO];
432 [m_movieview setVolumeButtonVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME) ? YES:NO];
433 }
434 }
435
436 //in source file that contains stuff you don't directly use
437 #include "wx/html/forcelnk.h"
438 FORCE_LINK_ME(basewxmediabackends);
439
440 #endif //wxUSE_MEDIACTRL