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