Use wxDELETE() and wxDELETEA() when possible.
[wxWidgets.git] / src / common / mediactrlcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/mediactrl.cpp
3 // Purpose: wxMediaCtrl common code
4 // Author: Ryan Norton <wxprojects@comcast.net>
5 // Modified by:
6 // Created: 11/07/04
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // TODO: Platform specific backend defaults?
13
14 //===========================================================================
15 // Declarations
16 //===========================================================================
17
18 //---------------------------------------------------------------------------
19 // Includes
20 //---------------------------------------------------------------------------
21
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #if wxUSE_MEDIACTRL
29
30 #ifndef WX_PRECOMP
31 #include "wx/hash.h"
32 #include "wx/log.h"
33 #endif
34
35 #include "wx/mediactrl.h"
36
37 //===========================================================================
38 //
39 // Implementation
40 //
41 //===========================================================================
42
43 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
44 // RTTI and Event implementations
45 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
46
47 IMPLEMENT_CLASS(wxMediaCtrl, wxControl)
48 wxDEFINE_EVENT( wxEVT_MEDIA_STATECHANGED, wxMediaEvent );
49 wxDEFINE_EVENT( wxEVT_MEDIA_PLAY, wxMediaEvent );
50 wxDEFINE_EVENT( wxEVT_MEDIA_PAUSE, wxMediaEvent );
51 IMPLEMENT_CLASS(wxMediaBackend, wxObject)
52 IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent, wxEvent)
53 wxDEFINE_EVENT( wxEVT_MEDIA_FINISHED, wxMediaEvent );
54 wxDEFINE_EVENT( wxEVT_MEDIA_LOADED, wxMediaEvent );
55 wxDEFINE_EVENT( wxEVT_MEDIA_STOP, wxMediaEvent );
56
57 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
58 //
59 // wxMediaCtrl
60 //
61 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
62
63 //---------------------------------------------------------------------------
64 // wxMediaBackend Destructor
65 //
66 // This is here because the DARWIN gcc compiler badly screwed up and
67 // needs the destructor implementation in the source
68 //---------------------------------------------------------------------------
69 wxMediaBackend::~wxMediaBackend()
70 {
71 }
72
73 //---------------------------------------------------------------------------
74 // wxMediaCtrl::Create (file version)
75 // wxMediaCtrl::Create (URL version)
76 //
77 // Searches for a backend that is installed on the system (backends
78 // starting with lower characters in the alphabet are given priority),
79 // and creates the control from it
80 //
81 // This searches by searching the global RTTI hashtable, class by class,
82 // attempting to call CreateControl on each one found that is a derivative
83 // of wxMediaBackend - if it succeeded Create returns true, otherwise
84 // it keeps iterating through the hashmap.
85 //---------------------------------------------------------------------------
86 bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id,
87 const wxString& fileName,
88 const wxPoint& pos,
89 const wxSize& size,
90 long style,
91 const wxString& szBackend,
92 const wxValidator& validator,
93 const wxString& name)
94 {
95 if(!szBackend.empty())
96 {
97 wxClassInfo* pClassInfo = wxClassInfo::FindClass(szBackend);
98
99 if(!pClassInfo || !DoCreate(pClassInfo, parent, id,
100 pos, size, style, validator, name))
101 {
102 m_imp = NULL;
103 return false;
104 }
105
106 if (!fileName.empty())
107 {
108 if (!Load(fileName))
109 {
110 wxDELETE(m_imp);
111 return false;
112 }
113 }
114
115 SetInitialSize(size);
116 return true;
117 }
118 else
119 {
120 wxClassInfo::const_iterator it = wxClassInfo::begin_classinfo();
121
122 const wxClassInfo* classInfo;
123
124 while((classInfo = NextBackend(&it)) != NULL)
125 {
126 wxLogMessage( classInfo->GetClassName() );
127 if(!DoCreate(classInfo, parent, id,
128 pos, size, style, validator, name))
129 continue;
130
131 if (!fileName.empty())
132 {
133 if (Load(fileName))
134 {
135 SetInitialSize(size);
136 return true;
137 }
138 else
139 delete m_imp;
140 }
141 else
142 {
143 SetInitialSize(size);
144 return true;
145 }
146 }
147
148 m_imp = NULL;
149 return false;
150 }
151 }
152
153 bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id,
154 const wxURI& location,
155 const wxPoint& pos,
156 const wxSize& size,
157 long style,
158 const wxString& szBackend,
159 const wxValidator& validator,
160 const wxString& name)
161 {
162 if(!szBackend.empty())
163 {
164 wxClassInfo* pClassInfo = wxClassInfo::FindClass(szBackend);
165 if(!pClassInfo || !DoCreate(pClassInfo, parent, id,
166 pos, size, style, validator, name))
167 {
168 m_imp = NULL;
169 return false;
170 }
171
172 if (!Load(location))
173 {
174 wxDELETE(m_imp);
175 return false;
176 }
177
178 SetInitialSize(size);
179 return true;
180 }
181 else
182 {
183 wxClassInfo::const_iterator it = wxClassInfo::begin_classinfo();
184
185 const wxClassInfo* classInfo;
186
187 while((classInfo = NextBackend(&it)) != NULL)
188 {
189 if(!DoCreate(classInfo, parent, id,
190 pos, size, style, validator, name))
191 continue;
192
193 if (Load(location))
194 {
195 SetInitialSize(size);
196 return true;
197 }
198 else
199 delete m_imp;
200 }
201
202 m_imp = NULL;
203 return false;
204 }
205 }
206
207 //---------------------------------------------------------------------------
208 // wxMediaCtrl::DoCreate
209 //
210 // Attempts to create the control from a backend
211 //---------------------------------------------------------------------------
212 bool wxMediaCtrl::DoCreate(const wxClassInfo* classInfo,
213 wxWindow* parent, wxWindowID id,
214 const wxPoint& pos,
215 const wxSize& size,
216 long style,
217 const wxValidator& validator,
218 const wxString& name)
219 {
220 m_imp = (wxMediaBackend*)classInfo->CreateObject();
221
222 if( m_imp->CreateControl(this, parent, id, pos, size,
223 style, validator, name) )
224 {
225 return true;
226 }
227
228 delete m_imp;
229 return false;
230 }
231
232 //---------------------------------------------------------------------------
233 // wxMediaCtrl::NextBackend (static)
234 //
235 //
236 // Search through the RTTI hashmap one at a
237 // time, attempting to create each derivative
238 // of wxMediaBackend
239 //
240 //
241 // STL isn't compatible with and will have a compilation error
242 // on a wxNode, however, wxHashTable::compatibility_iterator is
243 // incompatible with the old 2.4 stable version - but since
244 // we're in 2.5+ only we don't need to worry about the new version
245 //---------------------------------------------------------------------------
246 const wxClassInfo* wxMediaCtrl::NextBackend(wxClassInfo::const_iterator* it)
247 {
248 for ( wxClassInfo::const_iterator end = wxClassInfo::end_classinfo();
249 *it != end; ++(*it) )
250 {
251 const wxClassInfo* classInfo = **it;
252 if ( classInfo->IsKindOf(CLASSINFO(wxMediaBackend)) &&
253 classInfo != CLASSINFO(wxMediaBackend) )
254 {
255 ++(*it);
256 return classInfo;
257 }
258 }
259
260 //
261 // Nope - couldn't successfully find one... fail
262 //
263 return NULL;
264 }
265
266
267 //---------------------------------------------------------------------------
268 // wxMediaCtrl Destructor
269 //
270 // Free up the backend if it exists
271 //---------------------------------------------------------------------------
272 wxMediaCtrl::~wxMediaCtrl()
273 {
274 if (m_imp)
275 delete m_imp;
276 }
277
278 //---------------------------------------------------------------------------
279 // wxMediaCtrl::Load (file version)
280 // wxMediaCtrl::Load (URL version)
281 // wxMediaCtrl::Load (URL & Proxy version)
282 // wxMediaCtrl::Load (wxInputStream version)
283 //
284 // Here we call load of the backend - keeping
285 // track of whether it was successful or not - which
286 // will determine which later method calls work
287 //---------------------------------------------------------------------------
288 bool wxMediaCtrl::Load(const wxString& fileName)
289 {
290 if(m_imp)
291 return (m_bLoaded = m_imp->Load(fileName));
292 return false;
293 }
294
295 bool wxMediaCtrl::Load(const wxURI& location)
296 {
297 if(m_imp)
298 return (m_bLoaded = m_imp->Load(location));
299 return false;
300 }
301
302 bool wxMediaCtrl::Load(const wxURI& location, const wxURI& proxy)
303 {
304 if(m_imp)
305 return (m_bLoaded = m_imp->Load(location, proxy));
306 return false;
307 }
308
309 //---------------------------------------------------------------------------
310 // wxMediaCtrl::Play
311 // wxMediaCtrl::Pause
312 // wxMediaCtrl::Stop
313 // wxMediaCtrl::GetPlaybackRate
314 // wxMediaCtrl::SetPlaybackRate
315 // wxMediaCtrl::Seek --> SetPosition
316 // wxMediaCtrl::Tell --> GetPosition
317 // wxMediaCtrl::Length --> GetDuration
318 // wxMediaCtrl::GetState
319 // wxMediaCtrl::DoGetBestSize
320 // wxMediaCtrl::SetVolume
321 // wxMediaCtrl::GetVolume
322 // wxMediaCtrl::ShowInterface
323 // wxMediaCtrl::GetDownloadProgress
324 // wxMediaCtrl::GetDownloadTotal
325 //
326 // 1) Check to see whether the backend exists and is loading
327 // 2) Call the backend's version of the method, returning success
328 // if the backend's version succeeds
329 //---------------------------------------------------------------------------
330 bool wxMediaCtrl::Play()
331 {
332 if(m_imp && m_bLoaded)
333 return m_imp->Play();
334 return 0;
335 }
336
337 bool wxMediaCtrl::Pause()
338 {
339 if(m_imp && m_bLoaded)
340 return m_imp->Pause();
341 return 0;
342 }
343
344 bool wxMediaCtrl::Stop()
345 {
346 if(m_imp && m_bLoaded)
347 return m_imp->Stop();
348 return 0;
349 }
350
351 double wxMediaCtrl::GetPlaybackRate()
352 {
353 if(m_imp && m_bLoaded)
354 return m_imp->GetPlaybackRate();
355 return 0;
356 }
357
358 bool wxMediaCtrl::SetPlaybackRate(double dRate)
359 {
360 if(m_imp && m_bLoaded)
361 return m_imp->SetPlaybackRate(dRate);
362 return false;
363 }
364
365 wxFileOffset wxMediaCtrl::Seek(wxFileOffset where, wxSeekMode mode)
366 {
367 wxFileOffset offset;
368
369 switch (mode)
370 {
371 case wxFromStart:
372 offset = where;
373 break;
374 case wxFromEnd:
375 offset = Length() - where;
376 break;
377 // case wxFromCurrent:
378 default:
379 offset = Tell() + where;
380 break;
381 }
382
383 if(m_imp && m_bLoaded && m_imp->SetPosition(offset))
384 return offset;
385 return wxInvalidOffset;
386 }
387
388 wxFileOffset wxMediaCtrl::Tell()
389 {
390 if(m_imp && m_bLoaded)
391 return (wxFileOffset) m_imp->GetPosition().ToLong();
392 return wxInvalidOffset;
393 }
394
395 wxFileOffset wxMediaCtrl::Length()
396 {
397 if(m_imp && m_bLoaded)
398 return (wxFileOffset) m_imp->GetDuration().ToLong();
399 return wxInvalidOffset;
400 }
401
402 wxMediaState wxMediaCtrl::GetState()
403 {
404 if(m_imp && m_bLoaded)
405 return m_imp->GetState();
406 return wxMEDIASTATE_STOPPED;
407 }
408
409 wxSize wxMediaCtrl::DoGetBestSize() const
410 {
411 if(m_imp)
412 return m_imp->GetVideoSize();
413 return wxSize(0,0);
414 }
415
416 double wxMediaCtrl::GetVolume()
417 {
418 if(m_imp && m_bLoaded)
419 return m_imp->GetVolume();
420 return 0.0;
421 }
422
423 bool wxMediaCtrl::SetVolume(double dVolume)
424 {
425 if(m_imp && m_bLoaded)
426 return m_imp->SetVolume(dVolume);
427 return false;
428 }
429
430 bool wxMediaCtrl::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
431 {
432 if(m_imp)
433 return m_imp->ShowPlayerControls(flags);
434 return false;
435 }
436
437 wxFileOffset wxMediaCtrl::GetDownloadProgress()
438 {
439 if(m_imp && m_bLoaded)
440 return (wxFileOffset) m_imp->GetDownloadProgress().ToLong();
441 return wxInvalidOffset;
442 }
443
444 wxFileOffset wxMediaCtrl::GetDownloadTotal()
445 {
446 if(m_imp && m_bLoaded)
447 return (wxFileOffset) m_imp->GetDownloadTotal().ToLong();
448 return wxInvalidOffset;
449 }
450
451 //---------------------------------------------------------------------------
452 // wxMediaCtrl::DoMoveWindow
453 //
454 // 1) Call parent's version so that our control's window moves where
455 // it's supposed to
456 // 2) If the backend exists and is loaded, move the video
457 // of the media to where our control's window is now located
458 //---------------------------------------------------------------------------
459 void wxMediaCtrl::DoMoveWindow(int x, int y, int w, int h)
460 {
461 wxControl::DoMoveWindow(x,y,w,h);
462
463 if(m_imp)
464 m_imp->Move(x, y, w, h);
465 }
466
467 //---------------------------------------------------------------------------
468 // wxMediaCtrl::MacVisibilityChanged
469 //---------------------------------------------------------------------------
470 #ifdef __WXOSX_CARBON__
471 void wxMediaCtrl::MacVisibilityChanged()
472 {
473 wxControl::MacVisibilityChanged();
474
475 if(m_imp)
476 m_imp->MacVisibilityChanged();
477 }
478 #endif
479
480 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
481 //
482 // wxMediaBackendCommonBase
483 //
484 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
485
486 void wxMediaBackendCommonBase::NotifyMovieSizeChanged()
487 {
488 // our best size changed after opening a new file
489 m_ctrl->InvalidateBestSize();
490 m_ctrl->SetSize(m_ctrl->GetSize());
491
492 // if the parent of the control has a sizer ask it to refresh our size
493 wxWindow * const parent = m_ctrl->GetParent();
494 if ( parent->GetSizer() )
495 {
496 m_ctrl->GetParent()->Layout();
497 m_ctrl->GetParent()->Refresh();
498 m_ctrl->GetParent()->Update();
499 }
500 }
501
502 void wxMediaBackendCommonBase::NotifyMovieLoaded()
503 {
504 NotifyMovieSizeChanged();
505
506 // notify about movie being fully loaded
507 QueueEvent(wxEVT_MEDIA_LOADED);
508 }
509
510 bool wxMediaBackendCommonBase::SendStopEvent()
511 {
512 wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
513
514 return !m_ctrl->GetEventHandler()->ProcessEvent(theEvent) || theEvent.IsAllowed();
515 }
516
517 void wxMediaBackendCommonBase::QueueEvent(wxEventType evtType)
518 {
519 wxMediaEvent theEvent(evtType, m_ctrl->GetId());
520 m_ctrl->GetEventHandler()->AddPendingEvent(theEvent);
521 }
522
523 void wxMediaBackendCommonBase::QueuePlayEvent()
524 {
525 QueueEvent(wxEVT_MEDIA_STATECHANGED);
526 QueueEvent(wxEVT_MEDIA_PLAY);
527 }
528
529 void wxMediaBackendCommonBase::QueuePauseEvent()
530 {
531 QueueEvent(wxEVT_MEDIA_STATECHANGED);
532 QueueEvent(wxEVT_MEDIA_PAUSE);
533 }
534
535 void wxMediaBackendCommonBase::QueueStopEvent()
536 {
537 QueueEvent(wxEVT_MEDIA_STATECHANGED);
538 QueueEvent(wxEVT_MEDIA_STOP);
539 }
540
541
542 //
543 // Force link default backends in -
544 // see http://wiki.wxwidgets.org/wiki.pl?RTTI
545 //
546 #include "wx/html/forcelnk.h"
547
548 #ifdef __WXMSW__ // MSW has huge backends so we do it seperately
549 FORCE_LINK(wxmediabackend_am)
550 FORCE_LINK(wxmediabackend_wmp10)
551 #elif !defined(__WXOSX_COCOA__)
552 FORCE_LINK(basewxmediabackends)
553 #endif
554
555 #endif //wxUSE_MEDIACTRL