bump product version to 6.3.0.0.beta1
[LibreOffice.git] / avmedia / source / viewer / mediawindow_impl.cxx
blobd76923bf09f8cb451753f3530ae2c63dea97ccd9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <iostream>
23 #include "mediawindow_impl.hxx"
24 #include "mediaevent_impl.hxx"
25 #include <mediamisc.hxx>
26 #include <bitmaps.hlst>
27 #include <helpids.h>
29 #include <algorithm>
30 #include <cmath>
32 #include <sal/log.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <tools/urlobj.hxx>
35 #include <unotools/securityoptions.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/commandevent.hxx>
38 #include <vcl/event.hxx>
39 #include <vcl/ptrstyle.hxx>
41 #include <com/sun/star/awt/SystemPointer.hpp>
42 #include <com/sun/star/lang/XComponent.hpp>
43 #include <com/sun/star/media/XManager.hpp>
44 #include <com/sun/star/uno/XComponentContext.hpp>
45 #include <vcl/sysdata.hxx>
46 #if HAVE_FEATURE_OPENGL
47 #include <vcl/opengl/OpenGLContext.hxx>
48 #endif
49 using namespace ::com::sun::star;
51 namespace avmedia { namespace priv {
53 MediaWindowControl::MediaWindowControl(vcl::Window* pParent)
54 : MediaControl(pParent, MEDIACONTROLSTYLE_MULTILINE)
58 void MediaWindowControl::update()
60 MediaItem aItem;
62 static_cast< MediaWindowImpl* >( GetParent() )->updateMediaItem( aItem );
63 setState(aItem);
66 void MediaWindowControl::execute(const MediaItem& rItem)
68 static_cast<MediaWindowImpl*>(GetParent())->executeMediaItem(rItem);
71 MediaChildWindow::MediaChildWindow(vcl::Window* pParent)
72 : SystemChildWindow(pParent, WB_CLIPCHILDREN)
76 void MediaChildWindow::MouseMove( const MouseEvent& rMEvt )
78 const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
79 rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
81 SystemChildWindow::MouseMove( rMEvt );
82 GetParent()->MouseMove( aTransformedEvent );
85 void MediaChildWindow::MouseButtonDown( const MouseEvent& rMEvt )
87 const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
88 rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
90 SystemChildWindow::MouseButtonDown( rMEvt );
91 GetParent()->MouseButtonDown( aTransformedEvent );
94 void MediaChildWindow::MouseButtonUp( const MouseEvent& rMEvt )
96 const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
97 rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
99 SystemChildWindow::MouseButtonUp( rMEvt );
100 GetParent()->MouseButtonUp( aTransformedEvent );
103 void MediaChildWindow::KeyInput( const KeyEvent& rKEvt )
105 SystemChildWindow::KeyInput( rKEvt );
106 GetParent()->KeyInput( rKEvt );
109 void MediaChildWindow::KeyUp( const KeyEvent& rKEvt )
111 SystemChildWindow::KeyUp( rKEvt );
112 GetParent()->KeyUp( rKEvt );
115 void MediaChildWindow::Command( const CommandEvent& rCEvt )
117 const CommandEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rCEvt.GetMousePosPixel() ) ),
118 rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData() );
120 SystemChildWindow::Command( rCEvt );
121 GetParent()->Command( aTransformedEvent );
124 MediaWindowImpl::MediaWindowImpl(vcl::Window* pParent, MediaWindow* pMediaWindow, bool bInternalMediaControl)
125 : Control(pParent)
126 , DropTargetHelper(this)
127 , DragSourceHelper(this)
128 , mpMediaWindow(pMediaWindow)
129 , mpMediaWindowControl(bInternalMediaControl ? VclPtr<MediaWindowControl>::Create(this) : nullptr)
131 if (mpMediaWindowControl)
133 mpMediaWindowControl->SetSizePixel(mpMediaWindowControl->getMinSizePixel());
134 mpMediaWindowControl->Show();
138 MediaWindowImpl::~MediaWindowImpl()
140 disposeOnce();
143 void MediaWindowImpl::dispose()
145 if (mxEvents.is())
146 mxEvents->cleanUp();
148 if (mxPlayerWindow.is())
150 auto pEventsIf = static_cast<cppu::OWeakObject*>(mxEvents.get());
151 mxPlayerWindow->removeKeyListener( uno::Reference< awt::XKeyListener >( pEventsIf, uno::UNO_QUERY ) );
152 mxPlayerWindow->removeMouseListener( uno::Reference< awt::XMouseListener >( pEventsIf, uno::UNO_QUERY ) );
153 mxPlayerWindow->removeMouseMotionListener( uno::Reference< awt::XMouseMotionListener >( pEventsIf, uno::UNO_QUERY ) );
155 uno::Reference< lang::XComponent > xComponent( mxPlayerWindow, uno::UNO_QUERY );
156 if (xComponent.is())
157 xComponent->dispose();
159 mxPlayerWindow.clear();
162 uno::Reference< lang::XComponent > xComponent( mxPlayer, uno::UNO_QUERY );
163 if (xComponent.is()) // this stops the player
164 xComponent->dispose();
166 mxPlayer.clear();
168 mpMediaWindow = nullptr;
170 mpEmptyBmpEx.reset();
171 mpAudioBmpEx.reset();
172 mpMediaWindowControl.disposeAndClear();
173 mpChildWindow.disposeAndClear();
175 Control::dispose();
178 uno::Reference<media::XPlayer> MediaWindowImpl::createPlayer(const OUString& rURL, const OUString& rReferer, const OUString* pMimeType)
180 uno::Reference<media::XPlayer> xPlayer;
182 if( rURL.isEmpty() )
183 return xPlayer;
185 if (SvtSecurityOptions().isUntrustedReferer(rReferer))
187 return xPlayer;
189 uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
191 if (!pMimeType || *pMimeType == AVMEDIA_MIMETYPE_COMMON)
194 static const char * aServiceManagers[] =
196 AVMEDIA_MANAGER_SERVICE_PREFERRED,
197 AVMEDIA_MANAGER_SERVICE_NAME,
198 // a fallback path just for gstreamer which has
199 // two significant versions deployed at once ...
200 #ifdef AVMEDIA_MANAGER_SERVICE_NAME_OLD
201 AVMEDIA_MANAGER_SERVICE_NAME_OLD
202 #endif
205 for (sal_uInt32 i = 0; !xPlayer.is() && i < SAL_N_ELEMENTS( aServiceManagers ); ++i)
207 const OUString aServiceName(aServiceManagers[i],
208 strlen( aServiceManagers[i]),
209 RTL_TEXTENCODING_ASCII_US);
211 xPlayer = createPlayer(rURL, aServiceName, xContext);
215 return xPlayer;
218 uno::Reference< media::XPlayer > MediaWindowImpl::createPlayer(
219 const OUString& rURL, const OUString& rManagerServName,
220 const uno::Reference< uno::XComponentContext >& xContext)
222 uno::Reference< media::XPlayer > xPlayer;
225 uno::Reference< media::XManager > xManager (
226 xContext->getServiceManager()->createInstanceWithContext(rManagerServName, xContext),
227 uno::UNO_QUERY );
228 if( xManager.is() )
229 xPlayer.set( xManager->createPlayer( rURL ), uno::UNO_QUERY );
230 else
231 SAL_INFO( "avmedia", "failed to create media player service " << rManagerServName );
232 } catch ( const uno::Exception &e )
234 SAL_WARN( "avmedia", "couldn't create media player " << rManagerServName << ", " << e);
236 return xPlayer;
239 void MediaWindowImpl::setURL( const OUString& rURL,
240 OUString const& rTempURL, OUString const& rReferer)
242 maReferer = rReferer;
243 if( rURL != getURL() )
245 if( mxPlayer.is() )
246 mxPlayer->stop();
248 if( mxPlayerWindow.is() )
250 mxPlayerWindow->setVisible( false );
251 mxPlayerWindow.clear();
254 mxPlayer.clear();
255 mTempFileURL.clear();
257 if (!rTempURL.isEmpty())
259 maFileURL = rURL;
260 mTempFileURL = rTempURL;
262 else
264 INetURLObject aURL( rURL );
266 if (aURL.GetProtocol() != INetProtocol::NotValid)
267 maFileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous);
268 else
269 maFileURL = rURL;
272 mxPlayer = createPlayer((!mTempFileURL.isEmpty()) ? mTempFileURL : maFileURL, rReferer, &m_sMimeType );
273 onURLChanged();
277 const OUString& MediaWindowImpl::getURL() const
279 return maFileURL;
282 bool MediaWindowImpl::isValid() const
284 return mxPlayer.is();
287 Size MediaWindowImpl::getPreferredSize() const
289 Size aRet(480, 360);
291 if( mxPlayer.is() )
293 awt::Size aPrefSize( mxPlayer->getPreferredPlayerWindowSize() );
295 aRet.setWidth( aPrefSize.Width );
296 aRet.setHeight( aPrefSize.Height );
299 return aRet;
302 bool MediaWindowImpl::start()
304 return mxPlayer.is() && ( mxPlayer->start(), true );
307 void MediaWindowImpl::updateMediaItem( MediaItem& rItem ) const
309 if( isPlaying() )
310 rItem.setState( MediaState::Play );
311 else
312 rItem.setState( ( getMediaTime() == 0.0 ) ? MediaState::Stop : MediaState::Pause );
314 rItem.setDuration( getDuration() );
315 rItem.setTime( getMediaTime() );
316 rItem.setLoop( mxPlayer.is() && mxPlayer->isPlaybackLoop() );
317 rItem.setMute( mxPlayer.is() && mxPlayer->isMute() );
318 rItem.setVolumeDB( mxPlayer.is() ? mxPlayer->getVolumeDB() : 0 );
319 rItem.setZoom( mxPlayerWindow.is() ? mxPlayerWindow->getZoomLevel() : media::ZoomLevel_NOT_AVAILABLE );
320 rItem.setURL( getURL(), mTempFileURL, maReferer );
323 void MediaWindowImpl::executeMediaItem( const MediaItem& rItem )
325 const AVMediaSetMask nMaskSet = rItem.getMaskSet();
327 // set URL first
328 if (nMaskSet & AVMediaSetMask::URL)
330 m_sMimeType = rItem.getMimeType();
331 setURL(rItem.getURL(), rItem.getTempURL(), rItem.getReferer());
334 // set different states next
335 if (nMaskSet & AVMediaSetMask::TIME)
336 setMediaTime(std::min(rItem.getTime(), getDuration()));
338 if (nMaskSet & AVMediaSetMask::LOOP && mxPlayer.is() )
339 mxPlayer->setPlaybackLoop( rItem.isLoop() );
341 if (nMaskSet & AVMediaSetMask::MUTE && mxPlayer.is() )
342 mxPlayer->setMute( rItem.isMute() );
344 if (nMaskSet & AVMediaSetMask::VOLUMEDB && mxPlayer.is() )
345 mxPlayer->setVolumeDB( rItem.getVolumeDB() );
347 if (nMaskSet & AVMediaSetMask::ZOOM && mxPlayerWindow.is() )
348 mxPlayerWindow->setZoomLevel( rItem.getZoom() );
350 // set play state at last
351 if (nMaskSet & AVMediaSetMask::STATE)
353 switch (rItem.getState())
355 case MediaState::Play:
357 if (!isPlaying())
358 start();
360 break;
362 case MediaState::Pause:
364 if (isPlaying())
365 stop();
367 break;
369 case MediaState::Stop:
371 if (isPlaying())
373 setMediaTime( 0.0 );
374 stop();
375 setMediaTime( 0.0 );
378 break;
383 void MediaWindowImpl::stop()
385 if( mxPlayer.is() )
386 mxPlayer->stop();
389 bool MediaWindowImpl::isPlaying() const
391 return( mxPlayer.is() && mxPlayer->isPlaying() );
394 double MediaWindowImpl::getDuration() const
396 return( mxPlayer.is() ? mxPlayer->getDuration() : 0.0 );
399 void MediaWindowImpl::setMediaTime( double fTime )
401 if( mxPlayer.is() )
402 mxPlayer->setMediaTime( fTime );
405 double MediaWindowImpl::getMediaTime() const
407 return( mxPlayer.is() ? mxPlayer->getMediaTime() : 0.0 );
410 void MediaWindowImpl::stopPlayingInternal(bool bStop)
412 if (isPlaying())
414 bStop ? mxPlayer->stop() : mxPlayer->start();
418 void MediaWindowImpl::onURLChanged()
420 if (m_sMimeType == AVMEDIA_MIMETYPE_COMMON)
422 mpChildWindow.disposeAndClear();
423 mpChildWindow.reset(VclPtr<MediaChildWindow>::Create(this));
425 if (!mpChildWindow)
426 return;
427 mpChildWindow->SetHelpId(HID_AVMEDIA_PLAYERWINDOW);
428 mxEvents = new MediaEventListenersImpl(*mpChildWindow);
430 if (mxPlayer.is())
432 Resize();
433 uno::Sequence<uno::Any> aArgs( 3 );
434 uno::Reference<media::XPlayerWindow> xPlayerWindow;
435 const Point aPoint;
436 const Size aSize(mpChildWindow->GetSizePixel());
438 aArgs[0] <<= mpChildWindow->GetParentWindowHandle();
439 aArgs[1] <<= awt::Rectangle(aPoint.X(), aPoint.Y(), aSize.Width(), aSize.Height());
440 aArgs[2] <<= reinterpret_cast<sal_IntPtr>(mpChildWindow.get());
444 xPlayerWindow = mxPlayer->createPlayerWindow( aArgs );
446 catch( const uno::RuntimeException& )
448 // happens eg, on MacOSX where Java frames cannot be created from X11 window handles
451 mxPlayerWindow = xPlayerWindow;
453 if( xPlayerWindow.is() )
455 auto pEventsIf = static_cast<cppu::OWeakObject*>(mxEvents.get());
456 xPlayerWindow->addKeyListener( uno::Reference< awt::XKeyListener >( pEventsIf, uno::UNO_QUERY ) );
457 xPlayerWindow->addMouseListener( uno::Reference< awt::XMouseListener >( pEventsIf, uno::UNO_QUERY ) );
458 xPlayerWindow->addMouseMotionListener( uno::Reference< awt::XMouseMotionListener >( pEventsIf, uno::UNO_QUERY ) );
459 xPlayerWindow->addFocusListener( uno::Reference< awt::XFocusListener >( pEventsIf, uno::UNO_QUERY ) );
462 else
463 mxPlayerWindow.clear();
465 if( mxPlayerWindow.is() )
466 mpChildWindow->Show();
467 else
468 mpChildWindow->Hide();
470 if( mpMediaWindowControl )
472 MediaItem aItem;
474 updateMediaItem( aItem );
475 mpMediaWindowControl->setState( aItem );
479 void MediaWindowImpl::setPosSize(const tools::Rectangle& rRect)
481 SetPosSizePixel(rRect.TopLeft(), rRect.GetSize());
484 void MediaWindowImpl::setPointer(PointerStyle aPointer)
486 SetPointer(aPointer);
488 if (mpChildWindow)
489 mpChildWindow->SetPointer(aPointer);
491 if (mxPlayerWindow.is())
493 long nPointer;
495 switch (aPointer)
497 case PointerStyle::Cross:
498 nPointer = awt::SystemPointer::CROSS;
499 break;
500 case PointerStyle::Hand:
501 nPointer = awt::SystemPointer::HAND;
502 break;
503 case PointerStyle::Move:
504 nPointer = awt::SystemPointer::MOVE;
505 break;
506 case PointerStyle::Wait:
507 nPointer = awt::SystemPointer::WAIT;
508 break;
509 default:
510 nPointer = awt::SystemPointer::ARROW;
511 break;
514 mxPlayerWindow->setPointerType(nPointer);
518 void MediaWindowImpl::Resize()
520 const Size aCurSize(GetOutputSizePixel());
521 const sal_Int32 nOffset(mpMediaWindowControl ? AVMEDIA_CONTROLOFFSET : 0);
523 Size aPlayerWindowSize(aCurSize.Width() - (nOffset << 1),
524 aCurSize.Height() - (nOffset << 1));
526 if (mpMediaWindowControl)
528 const sal_Int32 nControlHeight = mpMediaWindowControl->GetSizePixel().Height();
529 const sal_Int32 nControlY = std::max(aCurSize.Height() - nControlHeight - nOffset, 0L);
531 aPlayerWindowSize.setHeight( nControlY - (nOffset << 1) );
532 mpMediaWindowControl->SetPosSizePixel(Point(nOffset, nControlY ), Size(aCurSize.Width() - (nOffset << 1), nControlHeight));
534 if (mpChildWindow)
535 mpChildWindow->SetPosSizePixel(Point(0, 0), aPlayerWindowSize);
537 if (mxPlayerWindow.is())
538 mxPlayerWindow->setPosSize(0, 0, aPlayerWindowSize.Width(), aPlayerWindowSize.Height(), 0);
541 void MediaWindowImpl::StateChanged(StateChangedType eType)
543 if (mxPlayerWindow.is())
545 // stop playing when going disabled or hidden
546 switch (eType)
548 case StateChangedType::Visible:
550 stopPlayingInternal(!IsVisible());
551 mxPlayerWindow->setVisible(IsVisible());
553 break;
555 case StateChangedType::Enable:
557 stopPlayingInternal(!IsEnabled());
558 mxPlayerWindow->setEnable(IsEnabled());
560 break;
562 default:
563 break;
568 void MediaWindowImpl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
570 if (mxPlayerWindow.is())
571 mxPlayerWindow->update();
573 BitmapEx* pLogo = nullptr;
575 if (!mxPlayer.is())
577 if (!mpEmptyBmpEx)
578 mpEmptyBmpEx.reset(new BitmapEx(AVMEDIA_BMP_EMPTYLOGO));
580 pLogo = mpEmptyBmpEx.get();
582 else if (!mxPlayerWindow.is())
584 if (!mpAudioBmpEx)
585 mpAudioBmpEx.reset(new BitmapEx(AVMEDIA_BMP_AUDIOLOGO));
587 pLogo = mpAudioBmpEx.get();
590 if (!mpChildWindow)
591 return;
593 const Point aBasePos(mpChildWindow->GetPosPixel());
594 const tools::Rectangle aVideoRect(aBasePos, mpChildWindow->GetSizePixel());
596 if (pLogo && !pLogo->IsEmpty() && (aVideoRect.GetWidth() > 0) && (aVideoRect.GetHeight() > 0))
598 Size aLogoSize(pLogo->GetSizePixel());
599 const Color aBackgroundColor(67, 67, 67);
601 rRenderContext.SetLineColor(aBackgroundColor);
602 rRenderContext.SetFillColor(aBackgroundColor);
603 rRenderContext.DrawRect(aVideoRect);
605 if ((aLogoSize.Width() > aVideoRect.GetWidth() || aLogoSize.Height() > aVideoRect.GetHeight() ) &&
606 (aLogoSize.Height() > 0))
608 const double fLogoWH = double(aLogoSize.Width()) / aLogoSize.Height();
610 if (fLogoWH < (double(aVideoRect.GetWidth()) / aVideoRect.GetHeight()))
612 aLogoSize.setWidth( long(aVideoRect.GetHeight() * fLogoWH) );
613 aLogoSize.setHeight( aVideoRect.GetHeight() );
615 else
617 aLogoSize.setWidth( aVideoRect.GetWidth() );
618 aLogoSize.setHeight( long(aVideoRect.GetWidth() / fLogoWH) );
622 Point aPoint(aBasePos.X() + ((aVideoRect.GetWidth() - aLogoSize.Width()) >> 1),
623 aBasePos.Y() + ((aVideoRect.GetHeight() - aLogoSize.Height()) >> 1));
625 rRenderContext.DrawBitmapEx(aPoint, aLogoSize, *pLogo);
629 void MediaWindowImpl::GetFocus()
633 void MediaWindowImpl::MouseMove(const MouseEvent& rMEvt)
635 if (mpMediaWindow)
636 mpMediaWindow->MouseMove(rMEvt);
639 void MediaWindowImpl::MouseButtonDown(const MouseEvent& rMEvt)
641 if (mpMediaWindow)
642 mpMediaWindow->MouseButtonDown(rMEvt);
645 void MediaWindowImpl::MouseButtonUp(const MouseEvent& rMEvt)
647 if (mpMediaWindow)
648 mpMediaWindow->MouseButtonUp(rMEvt);
651 void MediaWindowImpl::KeyInput(const KeyEvent& rKEvt)
653 if (mpMediaWindow)
654 mpMediaWindow->KeyInput(rKEvt);
657 void MediaWindowImpl::KeyUp(const KeyEvent& rKEvt)
659 if (mpMediaWindow)
660 mpMediaWindow->KeyUp(rKEvt);
663 void MediaWindowImpl::Command(const CommandEvent& rCEvt)
665 if (mpMediaWindow)
666 mpMediaWindow->Command(rCEvt);
669 sal_Int8 MediaWindowImpl::AcceptDrop(const AcceptDropEvent& rEvt)
671 return (mpMediaWindow ? mpMediaWindow->AcceptDrop(rEvt) : 0);
674 sal_Int8 MediaWindowImpl::ExecuteDrop(const ExecuteDropEvent& rEvt)
676 return (mpMediaWindow ? mpMediaWindow->ExecuteDrop(rEvt) : 0);
679 void MediaWindowImpl::StartDrag(sal_Int8 nAction, const Point& rPosPixel)
681 if (mpMediaWindow)
682 mpMediaWindow->StartDrag(nAction, rPosPixel);
685 } // namespace priv
686 } // namespace avmedia
688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */