]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/osx/cocoa/mediactrl.mm
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / osx / cocoa / mediactrl.mm
... / ...
CommitLineData
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
57class WXDLLIMPEXP_FWD_MEDIA wxQTMediaBackend;
58
59@interface wxQTMovie : QTMovie {
60
61 wxQTMediaBackend* m_backend;
62}
63
64-(BOOL)isPlaying;
65
66@end
67
68class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
69{
70public:
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);
109private:
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
224IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
225
226wxQTMediaBackend::wxQTMediaBackend() :
227 m_movie(nil), m_movieview(nil),
228 m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
229{
230}
231
232wxQTMediaBackend::~wxQTMediaBackend()
233{
234 Cleanup();
235}
236
237bool 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
271bool wxQTMediaBackend::Load(const wxString& fileName)
272{
273 return Load(
274 wxURI(
275 wxString( wxT("file://") ) + fileName
276 )
277 );
278}
279
280bool 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
311void 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
321bool wxQTMediaBackend::Play()
322{
323 [m_movieview play:nil];
324 return true;
325}
326
327bool wxQTMediaBackend::Pause()
328{
329 [m_movieview pause:nil];
330 return true;
331}
332
333bool wxQTMediaBackend::Stop()
334{
335 [m_movieview pause:nil];
336 [m_movieview gotoBeginning:nil];
337 return true;
338}
339
340double wxQTMediaBackend::GetVolume()
341{
342 return [m_movie volume];
343}
344
345bool wxQTMediaBackend::SetVolume(double dVolume)
346{
347 [m_movie setVolume:dVolume];
348 return true;
349}
350double wxQTMediaBackend::GetPlaybackRate()
351{
352 return [m_movie rate];
353}
354
355bool wxQTMediaBackend::SetPlaybackRate(double dRate)
356{
357 [m_movie setRate:dRate];
358 return true;
359}
360
361bool 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
370wxLongLong wxQTMediaBackend::GetPosition()
371{
372 QTTime position = [m_movie currentTime];
373 return ((double) position.timeValue) / position.timeScale * 1000;
374}
375
376wxLongLong wxQTMediaBackend::GetDuration()
377{
378 QTTime duration = [m_movie duration];
379 return ((double) duration.timeValue) / duration.timeScale * 1000;
380}
381
382wxMediaState 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
395void wxQTMediaBackend::Cleanup()
396{
397 [m_movieview setMovie:NULL];
398 [m_movie release];
399 m_movie = nil;
400}
401
402wxSize wxQTMediaBackend::GetVideoSize() const
403{
404 return m_bestSize;
405}
406
407void 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
412bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
413{
414 if ( m_interfaceflags != flags )
415 DoShowPlayerControls(flags);
416
417 m_interfaceflags = flags;
418 return true;
419}
420
421void 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"
438FORCE_LINK_ME(basewxmediabackends);
439
440#endif //wxUSE_MEDIACTRL