1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
23 #include "mediawindow_impl.hxx"
24 #include "mediaevent_impl.hxx"
25 #include "mediamisc.hxx"
26 #include "bitmaps.hlst"
27 #include "mediawindow.hrc"
28 #include "helpids.hrc"
33 #include <comphelper/processfactory.hxx>
34 #include <osl/mutex.hxx>
35 #include <tools/urlobj.hxx>
36 #include <unotools/securityoptions.hxx>
37 #include <vcl/svapp.hxx>
39 #include <com/sun/star/awt/SystemPointer.hpp>
40 #include <com/sun/star/lang/XComponent.hpp>
41 #include <com/sun/star/media/XManager.hpp>
42 #include <vcl/sysdata.hxx>
43 #if HAVE_FEATURE_OPENGL
44 #include <vcl/opengl/OpenGLContext.hxx>
46 using namespace ::com::sun::star
;
48 namespace avmedia
{ namespace priv
{
50 MediaWindowControl::MediaWindowControl(vcl::Window
* pParent
)
51 : MediaControl(pParent
, MEDIACONTROLSTYLE_MULTILINE
)
55 void MediaWindowControl::update()
59 static_cast< MediaWindowImpl
* >( GetParent() )->updateMediaItem( aItem
);
63 void MediaWindowControl::execute(const MediaItem
& rItem
)
65 static_cast<MediaWindowImpl
*>(GetParent())->executeMediaItem(rItem
);
68 MediaChildWindow::MediaChildWindow(vcl::Window
* pParent
)
69 : SystemChildWindow(pParent
, WB_CLIPCHILDREN
)
74 MediaChildWindow::MediaChildWindow(vcl::Window
* pParent
, SystemWindowData
* pData
)
75 : SystemChildWindow(pParent
, WB_CLIPCHILDREN
, pData
)
80 void MediaChildWindow::MouseMove( const MouseEvent
& rMEvt
)
82 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
83 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
85 SystemChildWindow::MouseMove( rMEvt
);
86 GetParent()->MouseMove( aTransformedEvent
);
89 void MediaChildWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
91 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
92 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
94 SystemChildWindow::MouseButtonDown( rMEvt
);
95 GetParent()->MouseButtonDown( aTransformedEvent
);
98 void MediaChildWindow::MouseButtonUp( const MouseEvent
& rMEvt
)
100 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
101 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
103 SystemChildWindow::MouseButtonUp( rMEvt
);
104 GetParent()->MouseButtonUp( aTransformedEvent
);
107 void MediaChildWindow::KeyInput( const KeyEvent
& rKEvt
)
109 SystemChildWindow::KeyInput( rKEvt
);
110 GetParent()->KeyInput( rKEvt
);
113 void MediaChildWindow::KeyUp( const KeyEvent
& rKEvt
)
115 SystemChildWindow::KeyUp( rKEvt
);
116 GetParent()->KeyUp( rKEvt
);
119 void MediaChildWindow::Command( const CommandEvent
& rCEvt
)
121 const CommandEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rCEvt
.GetMousePosPixel() ) ),
122 rCEvt
.GetCommand(), rCEvt
.IsMouseEvent(), rCEvt
.GetEventData() );
124 SystemChildWindow::Command( rCEvt
);
125 GetParent()->Command( aTransformedEvent
);
128 MediaWindowImpl::MediaWindowImpl(vcl::Window
* pParent
, MediaWindow
* pMediaWindow
, bool bInternalMediaControl
)
130 , DropTargetHelper(this)
131 , DragSourceHelper(this)
132 , mpMediaWindow(pMediaWindow
)
133 , mbEventTransparent(true)
134 , mpMediaWindowControl(bInternalMediaControl
? VclPtr
<MediaWindowControl
>::Create(this) : nullptr)
135 , mpEmptyBmpEx(nullptr)
136 , mpAudioBmpEx(nullptr)
138 if (mpMediaWindowControl
)
140 mpMediaWindowControl
->SetSizePixel(mpMediaWindowControl
->getMinSizePixel());
141 mpMediaWindowControl
->Show();
145 MediaWindowImpl::~MediaWindowImpl()
150 void MediaWindowImpl::dispose()
155 if (mxPlayerWindow
.is())
157 auto pEventsIf
= static_cast<cppu::OWeakObject
*>(mxEvents
.get());
158 mxPlayerWindow
->removeKeyListener( uno::Reference
< awt::XKeyListener
>( pEventsIf
, uno::UNO_QUERY
) );
159 mxPlayerWindow
->removeMouseListener( uno::Reference
< awt::XMouseListener
>( pEventsIf
, uno::UNO_QUERY
) );
160 mxPlayerWindow
->removeMouseMotionListener( uno::Reference
< awt::XMouseMotionListener
>( pEventsIf
, uno::UNO_QUERY
) );
162 uno::Reference
< lang::XComponent
> xComponent( mxPlayerWindow
, uno::UNO_QUERY
);
164 xComponent
->dispose();
166 mxPlayerWindow
.clear();
169 uno::Reference
< lang::XComponent
> xComponent( mxPlayer
, uno::UNO_QUERY
);
170 if (xComponent
.is()) // this stops the player
171 xComponent
->dispose();
175 mpMediaWindow
= nullptr;
178 mpEmptyBmpEx
= nullptr;
180 mpAudioBmpEx
= nullptr;
181 mpMediaWindowControl
.disposeAndClear();
182 mpChildWindow
.disposeAndClear();
187 uno::Reference
<media::XPlayer
> MediaWindowImpl::createPlayer(const OUString
& rURL
, const OUString
& rReferer
, const OUString
* pMimeType
)
189 uno::Reference
<media::XPlayer
> xPlayer
;
194 if (SvtSecurityOptions().isUntrustedReferer(rReferer
))
198 uno::Reference
<uno::XComponentContext
> xContext(::comphelper::getProcessComponentContext());
200 if (!pMimeType
|| *pMimeType
== AVMEDIA_MIMETYPE_COMMON
)
203 static const char * aServiceManagers
[] =
205 AVMEDIA_MANAGER_SERVICE_PREFERRED
,
206 AVMEDIA_MANAGER_SERVICE_NAME
,
207 // a fallback path just for gstreamer which has
208 // two significant versions deployed at once ...
209 #ifdef AVMEDIA_MANAGER_SERVICE_NAME_OLD
210 AVMEDIA_MANAGER_SERVICE_NAME_OLD
212 // fallback to AVMedia framework on OS X
213 #ifdef AVMEDIA_MANAGER_SERVICE_NAME_FALLBACK1
214 AVMEDIA_MANAGER_SERVICE_NAME_FALLBACK1
218 for (sal_uInt32 i
= 0; !xPlayer
.is() && i
< SAL_N_ELEMENTS( aServiceManagers
); ++i
)
220 const OUString
aServiceName(aServiceManagers
[i
],
221 strlen( aServiceManagers
[i
]),
222 RTL_TEXTENCODING_ASCII_US
);
224 xPlayer
= createPlayer(rURL
, aServiceName
, xContext
);
227 #if HAVE_FEATURE_GLTF
228 #if HAVE_FEATURE_OPENGL
229 else if ( *pMimeType
== AVMEDIA_MIMETYPE_JSON
)
231 xPlayer
= createPlayer(rURL
, AVMEDIA_OPENGL_MANAGER_SERVICE_NAME
, xContext
);
239 uno::Reference
< media::XPlayer
> MediaWindowImpl::createPlayer(
240 const OUString
& rURL
, const OUString
& rManagerServName
,
241 const uno::Reference
< uno::XComponentContext
>& xContext
)
243 uno::Reference
< media::XPlayer
> xPlayer
;
246 uno::Reference
< media::XManager
> xManager (
247 xContext
->getServiceManager()->createInstanceWithContext(rManagerServName
, xContext
),
250 xPlayer
.set( xManager
->createPlayer( rURL
), uno::UNO_QUERY
);
252 SAL_INFO( "avmedia", "failed to create media player service " << rManagerServName
);
253 } catch ( const uno::Exception
&e
)
255 SAL_WARN( "avmedia", "couldn't create media player " << rManagerServName
256 << ", exception '" << e
.Message
<< '\'');
261 void MediaWindowImpl::setURL( const OUString
& rURL
,
262 OUString
const& rTempURL
, OUString
const& rReferer
)
264 maReferer
= rReferer
;
265 if( rURL
!= getURL() )
270 if( mxPlayerWindow
.is() )
272 mxPlayerWindow
->setVisible( false );
273 mxPlayerWindow
.clear();
277 mTempFileURL
.clear();
279 if (!rTempURL
.isEmpty())
282 mTempFileURL
= rTempURL
;
286 INetURLObject
aURL( rURL
);
288 if (aURL
.GetProtocol() != INetProtocol::NotValid
)
289 maFileURL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous
);
294 mxPlayer
= createPlayer((!mTempFileURL
.isEmpty()) ? mTempFileURL
: maFileURL
, rReferer
, &m_sMimeType
);
299 const OUString
& MediaWindowImpl::getURL() const
304 bool MediaWindowImpl::isValid() const
306 return( mxPlayer
.is() );
309 Size
MediaWindowImpl::getPreferredSize() const
315 awt::Size
aPrefSize( mxPlayer
->getPreferredPlayerWindowSize() );
317 aRet
.Width() = aPrefSize
.Width
;
318 aRet
.Height() = aPrefSize
.Height
;
324 bool MediaWindowImpl::start()
326 return mxPlayer
.is() && ( mxPlayer
->start(), true );
329 void MediaWindowImpl::updateMediaItem( MediaItem
& rItem
) const
332 rItem
.setState( MediaState::Play
);
334 rItem
.setState( ( 0.0 == getMediaTime() ) ? MediaState::Stop
: MediaState::Pause
);
336 rItem
.setDuration( getDuration() );
337 rItem
.setTime( getMediaTime() );
338 rItem
.setLoop( mxPlayer
.is() && mxPlayer
->isPlaybackLoop() );
339 rItem
.setMute( mxPlayer
.is() && mxPlayer
->isMute() );
340 rItem
.setVolumeDB( mxPlayer
.is() ? mxPlayer
->getVolumeDB() : 0 );
341 rItem
.setZoom( mxPlayerWindow
.is() ? mxPlayerWindow
->getZoomLevel() : media::ZoomLevel_NOT_AVAILABLE
);
342 rItem
.setURL( getURL(), mTempFileURL
, maReferer
);
345 void MediaWindowImpl::executeMediaItem( const MediaItem
& rItem
)
347 const AVMediaSetMask nMaskSet
= rItem
.getMaskSet();
350 if (nMaskSet
& AVMediaSetMask::URL
)
352 m_sMimeType
= rItem
.getMimeType();
353 setURL(rItem
.getURL(), rItem
.getTempURL(), rItem
.getReferer());
356 // set different states next
357 if (nMaskSet
& AVMediaSetMask::TIME
)
358 setMediaTime(std::min(rItem
.getTime(), getDuration()));
360 if (nMaskSet
& AVMediaSetMask::LOOP
&& mxPlayer
.is() )
361 mxPlayer
->setPlaybackLoop( rItem
.isLoop() );
363 if (nMaskSet
& AVMediaSetMask::MUTE
&& mxPlayer
.is() )
364 mxPlayer
->setMute( rItem
.isMute() );
366 if (nMaskSet
& AVMediaSetMask::VOLUMEDB
&& mxPlayer
.is() )
367 mxPlayer
->setVolumeDB( rItem
.getVolumeDB() );
369 if (nMaskSet
& AVMediaSetMask::ZOOM
&& mxPlayerWindow
.is() )
370 mxPlayerWindow
->setZoomLevel( rItem
.getZoom() );
372 // set play state at last
373 if (nMaskSet
& AVMediaSetMask::STATE
)
375 switch (rItem
.getState())
377 case MediaState::Play
:
384 case MediaState::Pause
:
391 case MediaState::Stop
:
405 void MediaWindowImpl::stop()
411 bool MediaWindowImpl::isPlaying() const
413 return( mxPlayer
.is() && mxPlayer
->isPlaying() );
416 double MediaWindowImpl::getDuration() const
418 return( mxPlayer
.is() ? mxPlayer
->getDuration() : 0.0 );
421 void MediaWindowImpl::setMediaTime( double fTime
)
424 mxPlayer
->setMediaTime( fTime
);
427 double MediaWindowImpl::getMediaTime() const
429 return( mxPlayer
.is() ? mxPlayer
->getMediaTime() : 0.0 );
432 void MediaWindowImpl::stopPlayingInternal(bool bStop
)
436 bStop
? mxPlayer
->stop() : mxPlayer
->start();
440 void MediaWindowImpl::onURLChanged()
442 if (m_sMimeType
== AVMEDIA_MIMETYPE_COMMON
)
444 mpChildWindow
.disposeAndClear();
445 mpChildWindow
.reset(VclPtr
<MediaChildWindow
>::Create(this));
447 #if HAVE_FEATURE_GLTF
448 else if (m_sMimeType
== AVMEDIA_MIMETYPE_JSON
)
450 SystemWindowData aWinData
= OpenGLContext::Create()->generateWinData(this, false);
451 mpChildWindow
.disposeAndClear();
452 mpChildWindow
.reset(VclPtr
<MediaChildWindow
>::Create(this,&aWinData
));
453 mbEventTransparent
= false;
458 mpChildWindow
->SetHelpId(HID_AVMEDIA_PLAYERWINDOW
);
459 mxEvents
= new MediaEventListenersImpl(*mpChildWindow
.get());
464 uno::Sequence
<uno::Any
> aArgs( 3 );
465 uno::Reference
<media::XPlayerWindow
> xPlayerWindow
;
467 const Size
aSize(mpChildWindow
->GetSizePixel());
469 aArgs
[0] <<= mpChildWindow
->GetParentWindowHandle();
470 aArgs
[1] <<= awt::Rectangle(aPoint
.X(), aPoint
.Y(), aSize
.Width(), aSize
.Height());
471 aArgs
[2] <<= reinterpret_cast<sal_IntPtr
>(mpChildWindow
.get());
475 xPlayerWindow
= mxPlayer
->createPlayerWindow( aArgs
);
477 catch( const uno::RuntimeException
& )
479 // happens eg, on MacOSX where Java frames cannot be created from X11 window handles
482 mxPlayerWindow
= xPlayerWindow
;
484 if( xPlayerWindow
.is() )
486 auto pEventsIf
= static_cast<cppu::OWeakObject
*>(mxEvents
.get());
487 xPlayerWindow
->addKeyListener( uno::Reference
< awt::XKeyListener
>( pEventsIf
, uno::UNO_QUERY
) );
488 xPlayerWindow
->addMouseListener( uno::Reference
< awt::XMouseListener
>( pEventsIf
, uno::UNO_QUERY
) );
489 xPlayerWindow
->addMouseMotionListener( uno::Reference
< awt::XMouseMotionListener
>( pEventsIf
, uno::UNO_QUERY
) );
490 xPlayerWindow
->addFocusListener( uno::Reference
< awt::XFocusListener
>( pEventsIf
, uno::UNO_QUERY
) );
494 mxPlayerWindow
.clear();
496 if( mxPlayerWindow
.is() )
497 mpChildWindow
->Show();
499 mpChildWindow
->Hide();
501 if( mpMediaWindowControl
)
505 updateMediaItem( aItem
);
506 mpMediaWindowControl
->setState( aItem
);
510 void MediaWindowImpl::setPosSize(const tools::Rectangle
& rRect
)
512 SetPosSizePixel(rRect
.TopLeft(), rRect
.GetSize());
515 void MediaWindowImpl::setPointer(const Pointer
& rPointer
)
517 SetPointer(rPointer
);
520 mpChildWindow
->SetPointer(rPointer
);
522 if (mxPlayerWindow
.is())
526 switch (rPointer
.GetStyle())
528 case PointerStyle::Cross
:
529 nPointer
= awt::SystemPointer::CROSS
;
531 case PointerStyle::Hand
:
532 nPointer
= awt::SystemPointer::HAND
;
534 case PointerStyle::Move
:
535 nPointer
= awt::SystemPointer::MOVE
;
537 case PointerStyle::Wait
:
538 nPointer
= awt::SystemPointer::WAIT
;
541 nPointer
= awt::SystemPointer::ARROW
;
545 mxPlayerWindow
->setPointerType(nPointer
);
549 void MediaWindowImpl::Resize()
551 const Size
aCurSize(GetOutputSizePixel());
552 const sal_Int32
nOffset(mpMediaWindowControl
? AVMEDIA_CONTROLOFFSET
: 0);
554 Size
aPlayerWindowSize(aCurSize
.Width() - (nOffset
<< 1),
555 aCurSize
.Height() - (nOffset
<< 1));
557 if (mpMediaWindowControl
)
559 const sal_Int32 nControlHeight
= mpMediaWindowControl
->GetSizePixel().Height();
560 const sal_Int32 nControlY
= std::max(aCurSize
.Height() - nControlHeight
- nOffset
, 0L);
562 aPlayerWindowSize
.Height() = (nControlY
- (nOffset
<< 1));
563 mpMediaWindowControl
->SetPosSizePixel(Point(nOffset
, nControlY
), Size(aCurSize
.Width() - (nOffset
<< 1), nControlHeight
));
566 mpChildWindow
->SetPosSizePixel(Point(0, 0), aPlayerWindowSize
);
568 if (mxPlayerWindow
.is())
569 mxPlayerWindow
->setPosSize(0, 0, aPlayerWindowSize
.Width(), aPlayerWindowSize
.Height(), 0);
572 void MediaWindowImpl::StateChanged(StateChangedType eType
)
574 if (mxPlayerWindow
.is())
576 // stop playing when going disabled or hidden
579 case StateChangedType::Visible
:
581 stopPlayingInternal(!IsVisible());
582 mxPlayerWindow
->setVisible(IsVisible());
586 case StateChangedType::Enable
:
588 stopPlayingInternal(!IsEnabled());
589 mxPlayerWindow
->setEnable(IsEnabled());
599 void MediaWindowImpl::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
601 if (mxPlayerWindow
.is())
602 mxPlayerWindow
->update();
604 BitmapEx
* pLogo
= nullptr;
609 mpEmptyBmpEx
= new BitmapEx(AVMEDIA_BMP_EMPTYLOGO
);
611 pLogo
= mpEmptyBmpEx
;
613 else if (!mxPlayerWindow
.is())
616 mpAudioBmpEx
= new BitmapEx(AVMEDIA_BMP_AUDIOLOGO
);
618 pLogo
= mpAudioBmpEx
;
624 const Point
aBasePos(mpChildWindow
->GetPosPixel());
625 const tools::Rectangle
aVideoRect(aBasePos
, mpChildWindow
->GetSizePixel());
627 if (pLogo
&& !pLogo
->IsEmpty() && (aVideoRect
.GetWidth() > 0) && (aVideoRect
.GetHeight() > 0))
629 Size
aLogoSize(pLogo
->GetSizePixel());
630 const Color
aBackgroundColor(67, 67, 67);
632 rRenderContext
.SetLineColor(aBackgroundColor
);
633 rRenderContext
.SetFillColor(aBackgroundColor
);
634 rRenderContext
.DrawRect(aVideoRect
);
636 if ((aLogoSize
.Width() > aVideoRect
.GetWidth() || aLogoSize
.Height() > aVideoRect
.GetHeight() ) &&
637 (aLogoSize
.Height() > 0))
639 const double fLogoWH
= double(aLogoSize
.Width()) / aLogoSize
.Height();
641 if (fLogoWH
< (double(aVideoRect
.GetWidth()) / aVideoRect
.GetHeight()))
643 aLogoSize
.Width() = long(aVideoRect
.GetHeight() * fLogoWH
);
644 aLogoSize
.Height() = aVideoRect
.GetHeight();
648 aLogoSize
.Width() = aVideoRect
.GetWidth();
649 aLogoSize
.Height()= long(aVideoRect
.GetWidth() / fLogoWH
);
653 Point
aPoint(aBasePos
.X() + ((aVideoRect
.GetWidth() - aLogoSize
.Width()) >> 1),
654 aBasePos
.Y() + ((aVideoRect
.GetHeight() - aLogoSize
.Height()) >> 1));
656 rRenderContext
.DrawBitmapEx(aPoint
, aLogoSize
, *pLogo
);
660 void MediaWindowImpl::GetFocus()
664 void MediaWindowImpl::MouseMove(const MouseEvent
& rMEvt
)
666 if (mpMediaWindow
&& mbEventTransparent
)
667 mpMediaWindow
->MouseMove(rMEvt
);
670 void MediaWindowImpl::MouseButtonDown(const MouseEvent
& rMEvt
)
672 if (mpMediaWindow
&& mbEventTransparent
)
673 mpMediaWindow
->MouseButtonDown(rMEvt
);
676 void MediaWindowImpl::MouseButtonUp(const MouseEvent
& rMEvt
)
678 if (mpMediaWindow
&& mbEventTransparent
)
679 mpMediaWindow
->MouseButtonUp(rMEvt
);
682 void MediaWindowImpl::KeyInput(const KeyEvent
& rKEvt
)
684 if (mpMediaWindow
&& mbEventTransparent
)
685 mpMediaWindow
->KeyInput(rKEvt
);
688 void MediaWindowImpl::KeyUp(const KeyEvent
& rKEvt
)
690 if (mpMediaWindow
&& mbEventTransparent
)
691 mpMediaWindow
->KeyUp(rKEvt
);
694 void MediaWindowImpl::Command(const CommandEvent
& rCEvt
)
696 if (mpMediaWindow
&& mbEventTransparent
)
697 mpMediaWindow
->Command(rCEvt
);
700 sal_Int8
MediaWindowImpl::AcceptDrop(const AcceptDropEvent
& rEvt
)
702 return (mpMediaWindow
&& mbEventTransparent
? mpMediaWindow
->AcceptDrop(rEvt
) : 0);
705 sal_Int8
MediaWindowImpl::ExecuteDrop(const ExecuteDropEvent
& rEvt
)
707 return (mpMediaWindow
&& mbEventTransparent
? mpMediaWindow
->ExecuteDrop(rEvt
) : 0);
710 void MediaWindowImpl::StartDrag(sal_Int8 nAction
, const Point
& rPosPixel
)
712 if (mpMediaWindow
&& mbEventTransparent
)
713 mpMediaWindow
->StartDrag(nAction
, rPosPixel
);
717 } // namespace avmedia
719 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */