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 .
21 #include "mediawindow_impl.hxx"
22 #include "mediaevent_impl.hxx"
23 #include <mediamisc.hxx>
24 #include <bitmaps.hlst>
28 #include <string_view>
30 #include <sal/log.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <tools/diagnose_ex.h>
33 #include <tools/urlobj.hxx>
34 #include <unotools/securityoptions.hxx>
35 #include <vcl/bitmapex.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/sysdata.hxx>
38 #include <vcl/commandevent.hxx>
39 #include <vcl/event.hxx>
40 #include <vcl/ptrstyle.hxx>
42 #include <com/sun/star/awt/SystemPointer.hpp>
43 #include <com/sun/star/lang/XComponent.hpp>
44 #include <com/sun/star/media/XManager.hpp>
45 #include <com/sun/star/uno/XComponentContext.hpp>
46 using namespace ::com::sun::star
;
48 namespace avmedia::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
)
73 void MediaChildWindow::MouseMove( const MouseEvent
& rMEvt
)
75 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
76 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
78 SystemChildWindow::MouseMove( rMEvt
);
79 GetParent()->MouseMove( aTransformedEvent
);
82 void MediaChildWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
84 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
85 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
87 SystemChildWindow::MouseButtonDown( rMEvt
);
88 GetParent()->MouseButtonDown( aTransformedEvent
);
91 void MediaChildWindow::MouseButtonUp( const MouseEvent
& rMEvt
)
93 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
94 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
96 SystemChildWindow::MouseButtonUp( rMEvt
);
97 GetParent()->MouseButtonUp( aTransformedEvent
);
100 void MediaChildWindow::KeyInput( const KeyEvent
& rKEvt
)
102 SystemChildWindow::KeyInput( rKEvt
);
103 GetParent()->KeyInput( rKEvt
);
106 void MediaChildWindow::KeyUp( const KeyEvent
& rKEvt
)
108 SystemChildWindow::KeyUp( rKEvt
);
109 GetParent()->KeyUp( rKEvt
);
112 void MediaChildWindow::Command( const CommandEvent
& rCEvt
)
114 const CommandEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rCEvt
.GetMousePosPixel() ) ),
115 rCEvt
.GetCommand(), rCEvt
.IsMouseEvent(), rCEvt
.GetEventData() );
117 SystemChildWindow::Command( rCEvt
);
118 GetParent()->Command( aTransformedEvent
);
121 MediaWindowImpl::MediaWindowImpl(vcl::Window
* pParent
, MediaWindow
* pMediaWindow
, bool bInternalMediaControl
)
123 , DropTargetHelper(this)
124 , DragSourceHelper(this)
125 , mpMediaWindow(pMediaWindow
)
126 , mpMediaWindowControl(bInternalMediaControl
? VclPtr
<MediaWindowControl
>::Create(this) : nullptr)
128 if (mpMediaWindowControl
)
130 mpMediaWindowControl
->SetSizePixel(mpMediaWindowControl
->GetOptimalSize());
131 mpMediaWindowControl
->Show();
135 MediaWindowImpl::~MediaWindowImpl()
140 void MediaWindowImpl::dispose()
145 if (mxPlayerWindow
.is())
147 auto pEventsIf
= static_cast<cppu::OWeakObject
*>(mxEvents
.get());
148 mxPlayerWindow
->removeKeyListener( uno::Reference
< awt::XKeyListener
>( pEventsIf
, uno::UNO_QUERY
) );
149 mxPlayerWindow
->removeMouseListener( uno::Reference
< awt::XMouseListener
>( pEventsIf
, uno::UNO_QUERY
) );
150 mxPlayerWindow
->removeMouseMotionListener( uno::Reference
< awt::XMouseMotionListener
>( pEventsIf
, uno::UNO_QUERY
) );
151 mxPlayerWindow
->dispose();
152 mxPlayerWindow
.clear();
155 uno::Reference
< lang::XComponent
> xComponent( mxPlayer
, uno::UNO_QUERY
);
156 if (xComponent
.is()) // this stops the player
157 xComponent
->dispose();
161 mpMediaWindow
= nullptr;
163 mpEmptyBmpEx
.reset();
164 mpAudioBmpEx
.reset();
165 mpMediaWindowControl
.disposeAndClear();
166 mpChildWindow
.disposeAndClear();
171 uno::Reference
<media::XPlayer
> MediaWindowImpl::createPlayer(const OUString
& rURL
, const OUString
& rReferer
, const OUString
* pMimeType
)
173 uno::Reference
<media::XPlayer
> xPlayer
;
178 if (SvtSecurityOptions().isUntrustedReferer(rReferer
))
183 if (!pMimeType
|| *pMimeType
== AVMEDIA_MIMETYPE_COMMON
)
185 uno::Reference
<uno::XComponentContext
> xContext(::comphelper::getProcessComponentContext());
187 static std::u16string_view aServiceManagers
[] =
189 u
"" AVMEDIA_MANAGER_SERVICE_PREFERRED
,
190 u
"" AVMEDIA_MANAGER_SERVICE_NAME
,
193 for (const auto& rServiceName
: aServiceManagers
)
195 xPlayer
= createPlayer(rURL
, rServiceName
, xContext
);
204 uno::Reference
< media::XPlayer
> MediaWindowImpl::createPlayer(
205 const OUString
& rURL
, const OUString
& rManagerServName
,
206 const uno::Reference
< uno::XComponentContext
>& xContext
)
208 uno::Reference
< media::XPlayer
> xPlayer
;
211 uno::Reference
< media::XManager
> xManager (
212 xContext
->getServiceManager()->createInstanceWithContext(rManagerServName
, xContext
),
215 xPlayer
= xManager
->createPlayer( rURL
);
217 SAL_INFO( "avmedia", "failed to create media player service " << rManagerServName
);
218 } catch ( const uno::Exception
& )
220 TOOLS_WARN_EXCEPTION( "avmedia", "couldn't create media player " << rManagerServName
);
225 void MediaWindowImpl::setURL( const OUString
& rURL
,
226 OUString
const& rTempURL
, OUString
const& rReferer
)
228 maReferer
= rReferer
;
229 if( rURL
== getURL() )
235 if( mxPlayerWindow
.is() )
237 mxPlayerWindow
->setVisible( false );
238 mxPlayerWindow
.clear();
242 mTempFileURL
.clear();
244 if (!rTempURL
.isEmpty())
247 mTempFileURL
= rTempURL
;
251 INetURLObject
aURL( rURL
);
253 if (aURL
.GetProtocol() != INetProtocol::NotValid
)
254 maFileURL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous
);
259 mxPlayer
= createPlayer((!mTempFileURL
.isEmpty()) ? mTempFileURL
: maFileURL
, rReferer
, &m_sMimeType
);
263 const OUString
& MediaWindowImpl::getURL() const
268 bool MediaWindowImpl::isValid() const
270 return mxPlayer
.is();
273 Size
MediaWindowImpl::getPreferredSize() const
279 awt::Size
aPrefSize( mxPlayer
->getPreferredPlayerWindowSize() );
281 aRet
.setWidth( aPrefSize
.Width
);
282 aRet
.setHeight( aPrefSize
.Height
);
288 bool MediaWindowImpl::start()
290 return mxPlayer
.is() && ( mxPlayer
->start(), true );
293 void MediaWindowImpl::updateMediaItem( MediaItem
& rItem
) const
296 rItem
.setState( MediaState::Play
);
298 rItem
.setState( ( getMediaTime() == 0.0 ) ? MediaState::Stop
: MediaState::Pause
);
300 rItem
.setDuration( getDuration() );
301 rItem
.setTime( getMediaTime() );
302 rItem
.setLoop( mxPlayer
.is() && mxPlayer
->isPlaybackLoop() );
303 rItem
.setMute( mxPlayer
.is() && mxPlayer
->isMute() );
304 rItem
.setVolumeDB( mxPlayer
.is() ? mxPlayer
->getVolumeDB() : 0 );
305 rItem
.setZoom( mxPlayerWindow
.is() ? mxPlayerWindow
->getZoomLevel() : media::ZoomLevel_NOT_AVAILABLE
);
306 rItem
.setURL( getURL(), mTempFileURL
, maReferer
);
309 void MediaWindowImpl::executeMediaItem( const MediaItem
& rItem
)
311 const AVMediaSetMask nMaskSet
= rItem
.getMaskSet();
314 if (nMaskSet
& AVMediaSetMask::URL
)
316 m_sMimeType
= rItem
.getMimeType();
317 setURL(rItem
.getURL(), rItem
.getTempURL(), rItem
.getReferer());
320 // set different states next
321 if (nMaskSet
& AVMediaSetMask::TIME
)
322 setMediaTime(std::min(rItem
.getTime(), getDuration()));
324 if (nMaskSet
& AVMediaSetMask::LOOP
&& mxPlayer
.is() )
325 mxPlayer
->setPlaybackLoop( rItem
.isLoop() );
327 if (nMaskSet
& AVMediaSetMask::MUTE
&& mxPlayer
.is() )
328 mxPlayer
->setMute( rItem
.isMute() );
330 if (nMaskSet
& AVMediaSetMask::VOLUMEDB
&& mxPlayer
.is() )
331 mxPlayer
->setVolumeDB( rItem
.getVolumeDB() );
333 if (nMaskSet
& AVMediaSetMask::ZOOM
&& mxPlayerWindow
.is() )
334 mxPlayerWindow
->setZoomLevel( rItem
.getZoom() );
336 // set play state at last
337 if (!(nMaskSet
& AVMediaSetMask::STATE
))
340 switch (rItem
.getState())
342 case MediaState::Play
:
349 case MediaState::Pause
:
356 case MediaState::Stop
:
369 void MediaWindowImpl::stop()
375 bool MediaWindowImpl::isPlaying() const
377 return( mxPlayer
.is() && mxPlayer
->isPlaying() );
380 double MediaWindowImpl::getDuration() const
382 return( mxPlayer
.is() ? mxPlayer
->getDuration() : 0.0 );
385 void MediaWindowImpl::setMediaTime( double fTime
)
388 mxPlayer
->setMediaTime( fTime
);
391 double MediaWindowImpl::getMediaTime() const
393 return( mxPlayer
.is() ? mxPlayer
->getMediaTime() : 0.0 );
396 void MediaWindowImpl::stopPlayingInternal(bool bStop
)
400 bStop
? mxPlayer
->stop() : mxPlayer
->start();
404 void MediaWindowImpl::onURLChanged()
406 if (m_sMimeType
== AVMEDIA_MIMETYPE_COMMON
)
408 mpChildWindow
.disposeAndClear();
409 mpChildWindow
.reset(VclPtr
<MediaChildWindow
>::Create(this));
413 mpChildWindow
->SetHelpId(HID_AVMEDIA_PLAYERWINDOW
);
414 mxEvents
= new MediaEventListenersImpl(*mpChildWindow
);
419 uno::Sequence
<uno::Any
> aArgs( 3 );
420 uno::Reference
<media::XPlayerWindow
> xPlayerWindow
;
422 const Size
aSize(mpChildWindow
->GetSizePixel());
424 sal_IntPtr
nParentWindowHandle(0);
425 const SystemEnvData
* pEnvData
= mpChildWindow
->GetSystemData();
426 // tdf#139609 gtk doesn't need the handle, and fetching it is undesirable
427 if (!pEnvData
|| pEnvData
->toolkit
!= SystemEnvData::Toolkit::Gtk3
)
428 nParentWindowHandle
= mpChildWindow
->GetParentWindowHandle();
429 aArgs
[0] <<= nParentWindowHandle
;
430 aArgs
[1] <<= awt::Rectangle(aPoint
.X(), aPoint
.Y(), aSize
.Width(), aSize
.Height());
431 aArgs
[2] <<= reinterpret_cast<sal_IntPtr
>(mpChildWindow
.get());
435 xPlayerWindow
= mxPlayer
->createPlayerWindow( aArgs
);
437 catch( const uno::RuntimeException
& )
439 // happens eg, on MacOSX where Java frames cannot be created from X11 window handles
442 mxPlayerWindow
= xPlayerWindow
;
444 if( xPlayerWindow
.is() )
446 auto pEventsIf
= static_cast<cppu::OWeakObject
*>(mxEvents
.get());
447 xPlayerWindow
->addKeyListener( uno::Reference
< awt::XKeyListener
>( pEventsIf
, uno::UNO_QUERY
) );
448 xPlayerWindow
->addMouseListener( uno::Reference
< awt::XMouseListener
>( pEventsIf
, uno::UNO_QUERY
) );
449 xPlayerWindow
->addMouseMotionListener( uno::Reference
< awt::XMouseMotionListener
>( pEventsIf
, uno::UNO_QUERY
) );
450 xPlayerWindow
->addFocusListener( uno::Reference
< awt::XFocusListener
>( pEventsIf
, uno::UNO_QUERY
) );
454 mxPlayerWindow
.clear();
456 if( mxPlayerWindow
.is() )
457 mpChildWindow
->Show();
459 mpChildWindow
->Hide();
461 if( mpMediaWindowControl
)
465 updateMediaItem( aItem
);
466 mpMediaWindowControl
->setState( aItem
);
470 void MediaWindowImpl::setPosSize(const tools::Rectangle
& rRect
)
472 SetPosSizePixel(rRect
.TopLeft(), rRect
.GetSize());
475 void MediaWindowImpl::setPointer(PointerStyle aPointer
)
477 SetPointer(aPointer
);
480 mpChildWindow
->SetPointer(aPointer
);
482 if (!mxPlayerWindow
.is())
489 case PointerStyle::Cross
:
490 nPointer
= awt::SystemPointer::CROSS
;
492 case PointerStyle::Hand
:
493 nPointer
= awt::SystemPointer::HAND
;
495 case PointerStyle::Move
:
496 nPointer
= awt::SystemPointer::MOVE
;
498 case PointerStyle::Wait
:
499 nPointer
= awt::SystemPointer::WAIT
;
502 nPointer
= awt::SystemPointer::ARROW
;
506 mxPlayerWindow
->setPointerType(nPointer
);
509 void MediaWindowImpl::Resize()
511 const Size
aCurSize(GetOutputSizePixel());
512 const sal_Int32
nOffset(mpMediaWindowControl
? AVMEDIA_CONTROLOFFSET
: 0);
514 Size
aPlayerWindowSize(aCurSize
.Width() - (nOffset
<< 1),
515 aCurSize
.Height() - (nOffset
<< 1));
517 if (mpMediaWindowControl
)
519 const sal_Int32 nControlHeight
= mpMediaWindowControl
->GetSizePixel().Height();
520 const sal_Int32 nControlY
= std::max(aCurSize
.Height() - nControlHeight
- nOffset
, tools::Long(0));
522 aPlayerWindowSize
.setHeight( nControlY
- (nOffset
<< 1) );
523 mpMediaWindowControl
->SetPosSizePixel(Point(nOffset
, nControlY
), Size(aCurSize
.Width() - (nOffset
<< 1), nControlHeight
));
526 mpChildWindow
->SetPosSizePixel(Point(0, 0), aPlayerWindowSize
);
528 if (mxPlayerWindow
.is())
529 mxPlayerWindow
->setPosSize(0, 0, aPlayerWindowSize
.Width(), aPlayerWindowSize
.Height(), 0);
532 void MediaWindowImpl::StateChanged(StateChangedType eType
)
534 if (!mxPlayerWindow
.is())
537 // stop playing when going disabled or hidden
540 case StateChangedType::Visible
:
542 stopPlayingInternal(!IsVisible());
543 mxPlayerWindow
->setVisible(IsVisible());
547 case StateChangedType::Enable
:
549 stopPlayingInternal(!IsEnabled());
550 mxPlayerWindow
->setEnable(IsEnabled());
559 void MediaWindowImpl::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
561 if (mxPlayerWindow
.is())
562 mxPlayerWindow
->update();
564 BitmapEx
* pLogo
= nullptr;
569 mpEmptyBmpEx
.reset(new BitmapEx(AVMEDIA_BMP_EMPTYLOGO
));
571 pLogo
= mpEmptyBmpEx
.get();
573 else if (!mxPlayerWindow
.is())
576 mpAudioBmpEx
.reset(new BitmapEx(AVMEDIA_BMP_AUDIOLOGO
));
578 pLogo
= mpAudioBmpEx
.get();
584 const Point
aBasePos(mpChildWindow
->GetPosPixel());
585 const tools::Rectangle
aVideoRect(aBasePos
, mpChildWindow
->GetSizePixel());
587 if (!pLogo
|| pLogo
->IsEmpty() || aVideoRect
.IsEmpty())
590 Size
aLogoSize(pLogo
->GetSizePixel());
591 const Color
aBackgroundColor(67, 67, 67);
593 rRenderContext
.SetLineColor(aBackgroundColor
);
594 rRenderContext
.SetFillColor(aBackgroundColor
);
595 rRenderContext
.DrawRect(aVideoRect
);
597 if ((aLogoSize
.Width() > aVideoRect
.GetWidth() || aLogoSize
.Height() > aVideoRect
.GetHeight() ) &&
598 (aLogoSize
.Height() > 0))
600 const double fLogoWH
= double(aLogoSize
.Width()) / aLogoSize
.Height();
602 if (fLogoWH
< (double(aVideoRect
.GetWidth()) / aVideoRect
.GetHeight()))
604 aLogoSize
.setWidth( tools::Long(aVideoRect
.GetHeight() * fLogoWH
) );
605 aLogoSize
.setHeight( aVideoRect
.GetHeight() );
609 aLogoSize
.setWidth( aVideoRect
.GetWidth() );
610 aLogoSize
.setHeight( tools::Long(aVideoRect
.GetWidth() / fLogoWH
) );
614 Point
aPoint(aBasePos
.X() + ((aVideoRect
.GetWidth() - aLogoSize
.Width()) >> 1),
615 aBasePos
.Y() + ((aVideoRect
.GetHeight() - aLogoSize
.Height()) >> 1));
617 rRenderContext
.DrawBitmapEx(aPoint
, aLogoSize
, *pLogo
);
620 void MediaWindowImpl::GetFocus()
624 void MediaWindowImpl::MouseMove(const MouseEvent
& rMEvt
)
627 mpMediaWindow
->MouseMove(rMEvt
);
630 void MediaWindowImpl::MouseButtonDown(const MouseEvent
& rMEvt
)
633 mpMediaWindow
->MouseButtonDown(rMEvt
);
636 void MediaWindowImpl::MouseButtonUp(const MouseEvent
& rMEvt
)
639 mpMediaWindow
->MouseButtonUp(rMEvt
);
642 void MediaWindowImpl::KeyInput(const KeyEvent
& rKEvt
)
645 mpMediaWindow
->KeyInput(rKEvt
);
648 void MediaWindowImpl::KeyUp(const KeyEvent
& rKEvt
)
651 mpMediaWindow
->KeyUp(rKEvt
);
654 void MediaWindowImpl::Command(const CommandEvent
& rCEvt
)
657 mpMediaWindow
->Command(rCEvt
);
660 sal_Int8
MediaWindowImpl::AcceptDrop(const AcceptDropEvent
& rEvt
)
662 return (mpMediaWindow
? mpMediaWindow
->AcceptDrop(rEvt
) : 0);
665 sal_Int8
MediaWindowImpl::ExecuteDrop(const ExecuteDropEvent
& rEvt
)
667 return (mpMediaWindow
? mpMediaWindow
->ExecuteDrop(rEvt
) : 0);
670 void MediaWindowImpl::StartDrag(sal_Int8 nAction
, const Point
& rPosPixel
)
673 mpMediaWindow
->StartDrag(nAction
, rPosPixel
);
678 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */