Update OpenVMS makefile
[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