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 <comphelper/diagnose_ex.hxx>
33 #include <comphelper/scopeguard.hxx>
34 #include <tools/urlobj.hxx>
35 #include <unotools/securityoptions.hxx>
36 #include <vcl/bitmapex.hxx>
37 #include <vcl/sysdata.hxx>
38 #include <vcl/commandevent.hxx>
39 #include <vcl/event.hxx>
40 #include <vcl/ptrstyle.hxx>
41 #include <vcl/svapp.hxx>
43 #include <com/sun/star/awt/SystemPointer.hpp>
44 #include <com/sun/star/lang/XComponent.hpp>
45 #include <com/sun/star/media/XManager.hpp>
46 #include <com/sun/star/uno/XComponentContext.hpp>
47 using namespace ::com::sun::star
;
49 namespace avmedia::priv
{
51 MediaWindowControl::MediaWindowControl(vcl::Window
* pParent
)
52 : MediaControl(pParent
, MediaControlStyle::MultiLine
)
56 void MediaWindowControl::update()
60 static_cast< MediaWindowImpl
* >( GetParent() )->updateMediaItem( aItem
);
64 void MediaWindowControl::execute(const MediaItem
& rItem
)
66 static_cast<MediaWindowImpl
*>(GetParent())->executeMediaItem(rItem
);
69 MediaChildWindow::MediaChildWindow(vcl::Window
* pParent
)
70 : SystemChildWindow(pParent
, WB_CLIPCHILDREN
)
74 void MediaChildWindow::MouseMove( const MouseEvent
& rMEvt
)
76 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
77 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
79 SystemChildWindow::MouseMove( rMEvt
);
80 GetParent()->MouseMove( aTransformedEvent
);
83 void MediaChildWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
85 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
86 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
88 SystemChildWindow::MouseButtonDown( rMEvt
);
89 GetParent()->MouseButtonDown( aTransformedEvent
);
92 void MediaChildWindow::MouseButtonUp( const MouseEvent
& rMEvt
)
94 const MouseEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt
.GetPosPixel() ) ),
95 rMEvt
.GetClicks(), rMEvt
.GetMode(), rMEvt
.GetButtons(), rMEvt
.GetModifier() );
97 SystemChildWindow::MouseButtonUp( rMEvt
);
98 GetParent()->MouseButtonUp( aTransformedEvent
);
101 void MediaChildWindow::KeyInput( const KeyEvent
& rKEvt
)
103 SystemChildWindow::KeyInput( rKEvt
);
104 GetParent()->KeyInput( rKEvt
);
107 void MediaChildWindow::KeyUp( const KeyEvent
& rKEvt
)
109 SystemChildWindow::KeyUp( rKEvt
);
110 GetParent()->KeyUp( rKEvt
);
113 void MediaChildWindow::Command( const CommandEvent
& rCEvt
)
115 const CommandEvent
aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rCEvt
.GetMousePosPixel() ) ),
116 rCEvt
.GetCommand(), rCEvt
.IsMouseEvent(), rCEvt
.GetEventData() );
118 SystemChildWindow::Command( rCEvt
);
119 GetParent()->Command( aTransformedEvent
);
122 MediaWindowImpl::MediaWindowImpl(vcl::Window
* pParent
, MediaWindow
* pMediaWindow
, bool bInternalMediaControl
)
124 , DropTargetHelper(this)
125 , DragSourceHelper(this)
126 , mpMediaWindow(pMediaWindow
)
127 , mpMediaWindowControl(bInternalMediaControl
? VclPtr
<MediaWindowControl
>::Create(this) : nullptr)
129 if (mpMediaWindowControl
)
131 mpMediaWindowControl
->SetSizePixel(mpMediaWindowControl
->GetOptimalSize());
132 mpMediaWindowControl
->Show();
136 MediaWindowImpl::~MediaWindowImpl()
141 void MediaWindowImpl::dispose()
146 if (mxPlayerWindow
.is())
148 mxPlayerWindow
->removeKeyListener( uno::Reference
< awt::XKeyListener
>( mxEvents
) );
149 mxPlayerWindow
->removeMouseListener( uno::Reference
< awt::XMouseListener
>( mxEvents
) );
150 mxPlayerWindow
->removeMouseMotionListener( uno::Reference
< awt::XMouseMotionListener
>( mxEvents
) );
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
*)
173 uno::Reference
<media::XPlayer
> xPlayer
;
178 if (SvtSecurityOptions::isUntrustedReferer(rReferer
))
183 // currently there isn't anything else, throw any mime type to the media players
184 //if (!pMimeType || *pMimeType == AVMEDIA_MIMETYPE_COMMON)
186 uno::Reference
<uno::XComponentContext
> xContext(::comphelper::getProcessComponentContext());
187 if (Application::GetToolkitName() == "gtk4")
188 xPlayer
= createPlayer(rURL
, "com.sun.star.comp.avmedia.Manager_Gtk", xContext
);
190 xPlayer
= createPlayer(rURL
, AVMEDIA_MANAGER_SERVICE_NAME
, xContext
);
196 uno::Reference
< media::XPlayer
> MediaWindowImpl::createPlayer(
197 const OUString
& rURL
, const OUString
& rManagerServName
,
198 const uno::Reference
< uno::XComponentContext
>& xContext
)
200 uno::Reference
< media::XPlayer
> xPlayer
;
203 uno::Reference
< media::XManager
> xManager (
204 xContext
->getServiceManager()->createInstanceWithContext(rManagerServName
, xContext
),
207 xPlayer
= xManager
->createPlayer( rURL
);
209 SAL_INFO( "avmedia", "failed to create media player service " << rManagerServName
);
210 } catch ( const uno::Exception
& )
212 TOOLS_WARN_EXCEPTION( "avmedia", "couldn't create media player " << rManagerServName
);
217 void MediaWindowImpl::setURL( const OUString
& rURL
,
218 OUString
const& rTempURL
, OUString
const& rReferer
)
220 maReferer
= rReferer
;
221 if( rURL
== getURL() )
227 if( mxPlayerWindow
.is() )
229 mxPlayerWindow
->setVisible( false );
230 mxPlayerWindow
.clear();
234 mTempFileURL
.clear();
236 if (!rTempURL
.isEmpty())
239 mTempFileURL
= rTempURL
;
243 INetURLObject
aURL( rURL
);
245 if (aURL
.GetProtocol() != INetProtocol::NotValid
)
246 maFileURL
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous
);
251 mxPlayer
= createPlayer((!mTempFileURL
.isEmpty()) ? mTempFileURL
: maFileURL
, rReferer
, &m_sMimeType
);
255 const OUString
& MediaWindowImpl::getURL() const
260 bool MediaWindowImpl::isValid() const
262 return mxPlayer
.is();
265 Size
MediaWindowImpl::getPreferredSize() const
271 awt::Size
aPrefSize( mxPlayer
->getPreferredPlayerWindowSize() );
273 aRet
.setWidth( aPrefSize
.Width
);
274 aRet
.setHeight( aPrefSize
.Height
);
280 bool MediaWindowImpl::start()
282 return mxPlayer
.is() && ( mxPlayer
->start(), true );
285 void MediaWindowImpl::updateMediaItem( MediaItem
& rItem
) const
288 rItem
.setState( MediaState::Play
);
290 rItem
.setState( ( getMediaTime() == 0.0 ) ? MediaState::Stop
: MediaState::Pause
);
292 rItem
.setDuration( getDuration() );
293 rItem
.setTime( getMediaTime() );
294 rItem
.setLoop( mxPlayer
.is() && mxPlayer
->isPlaybackLoop() );
295 rItem
.setMute( mxPlayer
.is() && mxPlayer
->isMute() );
296 rItem
.setVolumeDB( mxPlayer
.is() ? mxPlayer
->getVolumeDB() : 0 );
297 rItem
.setZoom( mxPlayerWindow
.is() ? mxPlayerWindow
->getZoomLevel() : media::ZoomLevel_NOT_AVAILABLE
);
298 rItem
.setURL( getURL(), mTempFileURL
, maReferer
);
301 void MediaWindowImpl::executeMediaItem( const MediaItem
& rItem
)
304 comphelper::ScopeGuard
g([this] { this->mpItem
= nullptr; });
306 const AVMediaSetMask nMaskSet
= rItem
.getMaskSet();
309 if (nMaskSet
& AVMediaSetMask::URL
)
311 m_sMimeType
= rItem
.getMimeType();
312 setURL(rItem
.getURL(), rItem
.getTempURL(), rItem
.getReferer());
315 // set different states next
316 if (nMaskSet
& AVMediaSetMask::TIME
)
317 setMediaTime(std::min(rItem
.getTime(), getDuration()));
319 if (nMaskSet
& AVMediaSetMask::LOOP
&& mxPlayer
.is() )
320 mxPlayer
->setPlaybackLoop( rItem
.isLoop() );
322 if (nMaskSet
& AVMediaSetMask::MUTE
&& mxPlayer
.is() )
323 mxPlayer
->setMute( rItem
.isMute() );
325 if (nMaskSet
& AVMediaSetMask::VOLUMEDB
&& mxPlayer
.is() )
326 mxPlayer
->setVolumeDB( rItem
.getVolumeDB() );
328 if (nMaskSet
& AVMediaSetMask::ZOOM
&& mxPlayerWindow
.is() )
329 mxPlayerWindow
->setZoomLevel( rItem
.getZoom() );
331 // set play state at last
332 if (!(nMaskSet
& AVMediaSetMask::STATE
))
335 switch (rItem
.getState())
337 case MediaState::Play
:
344 case MediaState::Pause
:
351 case MediaState::Stop
:
364 void MediaWindowImpl::stop()
370 bool MediaWindowImpl::isPlaying() const
372 return( mxPlayer
.is() && mxPlayer
->isPlaying() );
375 double MediaWindowImpl::getDuration() const
377 return( mxPlayer
.is() ? mxPlayer
->getDuration() : 0.0 );
380 void MediaWindowImpl::setMediaTime( double fTime
)
383 mxPlayer
->setMediaTime( fTime
);
386 double MediaWindowImpl::getMediaTime() const
388 return( mxPlayer
.is() ? mxPlayer
->getMediaTime() : 0.0 );
391 void MediaWindowImpl::stopPlayingInternal(bool bStop
)
395 bStop
? mxPlayer
->stop() : mxPlayer
->start();
399 void MediaWindowImpl::onURLChanged()
401 //if (m_sMimeType == AVMEDIA_MIMETYPE_COMMON)
403 mpChildWindow
.disposeAndClear();
404 mpChildWindow
.reset(VclPtr
<MediaChildWindow
>::Create(this));
408 mpChildWindow
->SetHelpId(HID_AVMEDIA_PLAYERWINDOW
);
409 mxEvents
= new MediaEventListenersImpl(*mpChildWindow
);
414 uno::Reference
<media::XPlayerWindow
> xPlayerWindow
;
416 const Size
aSize(mpChildWindow
->GetSizePixel());
418 sal_IntPtr
nParentWindowHandle(0);
419 const SystemEnvData
* pEnvData
= mpChildWindow
->GetSystemData();
420 // tdf#139609 gtk doesn't need the handle, and fetching it is undesirable
421 if (!pEnvData
|| pEnvData
->toolkit
!= SystemEnvData::Toolkit::Gtk
)
422 nParentWindowHandle
= mpChildWindow
->GetParentWindowHandle();
423 uno::Sequence
<uno::Any
> aArgs
{
424 uno::Any(nParentWindowHandle
),
425 uno::Any(awt::Rectangle(aPoint
.X(), aPoint
.Y(), aSize
.Width(), aSize
.Height())),
426 uno::Any(reinterpret_cast<sal_IntPtr
>(mpChildWindow
.get())),
427 // Media item contains media properties, e.g. cropping.
428 uno::Any(reinterpret_cast<sal_IntPtr
>(mpItem
))
433 xPlayerWindow
= mxPlayer
->createPlayerWindow( aArgs
);
435 catch( const uno::RuntimeException
& )
437 // happens eg, on MacOSX where Java frames cannot be created from X11 window handles
440 mxPlayerWindow
= xPlayerWindow
;
442 if( xPlayerWindow
.is() )
444 xPlayerWindow
->addKeyListener( uno::Reference
< awt::XKeyListener
>( mxEvents
) );
445 xPlayerWindow
->addMouseListener( uno::Reference
< awt::XMouseListener
>( mxEvents
) );
446 xPlayerWindow
->addMouseMotionListener( uno::Reference
< awt::XMouseMotionListener
>( mxEvents
) );
447 xPlayerWindow
->addFocusListener( uno::Reference
< awt::XFocusListener
>( mxEvents
) );
451 mxPlayerWindow
.clear();
453 if( mxPlayerWindow
.is() )
454 mpChildWindow
->Show();
456 mpChildWindow
->Hide();
458 if( mpMediaWindowControl
)
462 updateMediaItem( aItem
);
463 mpMediaWindowControl
->setState( aItem
);
467 void MediaWindowImpl::setPosSize(const tools::Rectangle
& rRect
)
469 SetPosSizePixel(rRect
.TopLeft(), rRect
.GetSize());
472 void MediaWindowImpl::setPointer(PointerStyle aPointer
)
474 SetPointer(aPointer
);
477 mpChildWindow
->SetPointer(aPointer
);
479 if (!mxPlayerWindow
.is())
486 case PointerStyle::Cross
:
487 nPointer
= awt::SystemPointer::CROSS
;
489 case PointerStyle::Hand
:
490 nPointer
= awt::SystemPointer::HAND
;
492 case PointerStyle::Move
:
493 nPointer
= awt::SystemPointer::MOVE
;
495 case PointerStyle::Wait
:
496 nPointer
= awt::SystemPointer::WAIT
;
499 nPointer
= awt::SystemPointer::ARROW
;
503 mxPlayerWindow
->setPointerType(nPointer
);
506 void MediaWindowImpl::Resize()
508 const Size
aCurSize(GetOutputSizePixel());
509 const sal_Int32
nOffset(mpMediaWindowControl
? AVMEDIA_CONTROLOFFSET
: 0);
511 Size
aPlayerWindowSize(aCurSize
.Width() - (nOffset
<< 1),
512 aCurSize
.Height() - (nOffset
<< 1));
514 if (mpMediaWindowControl
)
516 const sal_Int32 nControlHeight
= mpMediaWindowControl
->GetSizePixel().Height();
517 const sal_Int32 nControlY
= std::max(aCurSize
.Height() - nControlHeight
- nOffset
, tools::Long(0));
519 aPlayerWindowSize
.setHeight( nControlY
- (nOffset
<< 1) );
520 mpMediaWindowControl
->SetPosSizePixel(Point(nOffset
, nControlY
), Size(aCurSize
.Width() - (nOffset
<< 1), nControlHeight
));
523 mpChildWindow
->SetPosSizePixel(Point(0, 0), aPlayerWindowSize
);
525 if (mxPlayerWindow
.is())
526 mxPlayerWindow
->setPosSize(0, 0, aPlayerWindowSize
.Width(), aPlayerWindowSize
.Height(), 0);
529 void MediaWindowImpl::StateChanged(StateChangedType eType
)
531 if (!mxPlayerWindow
.is())
534 // stop playing when going disabled or hidden
537 case StateChangedType::Visible
:
539 stopPlayingInternal(!IsVisible());
540 mxPlayerWindow
->setVisible(IsVisible());
544 case StateChangedType::Enable
:
546 stopPlayingInternal(!IsEnabled());
547 mxPlayerWindow
->setEnable(IsEnabled());
556 void MediaWindowImpl::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
558 if (mxPlayerWindow
.is())
559 mxPlayerWindow
->update();
561 BitmapEx
* pLogo
= nullptr;
566 mpEmptyBmpEx
.reset(new BitmapEx(AVMEDIA_BMP_EMPTYLOGO
));
568 pLogo
= mpEmptyBmpEx
.get();
570 else if (!mxPlayerWindow
.is())
573 mpAudioBmpEx
.reset(new BitmapEx(AVMEDIA_BMP_AUDIOLOGO
));
575 pLogo
= mpAudioBmpEx
.get();
581 const Point
aBasePos(mpChildWindow
->GetPosPixel());
582 const tools::Rectangle
aVideoRect(aBasePos
, mpChildWindow
->GetSizePixel());
584 if (!pLogo
|| pLogo
->IsEmpty() || aVideoRect
.IsEmpty())
587 Size
aLogoSize(pLogo
->GetSizePixel());
588 const Color
aBackgroundColor(67, 67, 67);
590 rRenderContext
.SetLineColor(aBackgroundColor
);
591 rRenderContext
.SetFillColor(aBackgroundColor
);
592 rRenderContext
.DrawRect(aVideoRect
);
594 if ((aLogoSize
.Width() > aVideoRect
.GetWidth() || aLogoSize
.Height() > aVideoRect
.GetHeight() ) &&
595 (aLogoSize
.Height() > 0))
597 const double fLogoWH
= double(aLogoSize
.Width()) / aLogoSize
.Height();
599 if (fLogoWH
< (double(aVideoRect
.GetWidth()) / aVideoRect
.GetHeight()))
601 aLogoSize
.setWidth( tools::Long(aVideoRect
.GetHeight() * fLogoWH
) );
602 aLogoSize
.setHeight( aVideoRect
.GetHeight() );
606 aLogoSize
.setWidth( aVideoRect
.GetWidth() );
607 aLogoSize
.setHeight( tools::Long(aVideoRect
.GetWidth() / fLogoWH
) );
611 Point
aPoint(aBasePos
.X() + ((aVideoRect
.GetWidth() - aLogoSize
.Width()) >> 1),
612 aBasePos
.Y() + ((aVideoRect
.GetHeight() - aLogoSize
.Height()) >> 1));
614 rRenderContext
.DrawBitmapEx(aPoint
, aLogoSize
, *pLogo
);
617 void MediaWindowImpl::GetFocus()
621 void MediaWindowImpl::MouseMove(const MouseEvent
& rMEvt
)
624 mpMediaWindow
->MouseMove(rMEvt
);
627 void MediaWindowImpl::MouseButtonDown(const MouseEvent
& rMEvt
)
630 mpMediaWindow
->MouseButtonDown(rMEvt
);
633 void MediaWindowImpl::MouseButtonUp(const MouseEvent
& rMEvt
)
636 mpMediaWindow
->MouseButtonUp(rMEvt
);
639 void MediaWindowImpl::KeyInput(const KeyEvent
& rKEvt
)
642 mpMediaWindow
->KeyInput(rKEvt
);
645 void MediaWindowImpl::KeyUp(const KeyEvent
& rKEvt
)
648 mpMediaWindow
->KeyUp(rKEvt
);
651 void MediaWindowImpl::Command(const CommandEvent
& rCEvt
)
654 mpMediaWindow
->Command(rCEvt
);
657 sal_Int8
MediaWindowImpl::AcceptDrop(const AcceptDropEvent
& rEvt
)
659 return (mpMediaWindow
? mpMediaWindow
->AcceptDrop(rEvt
) : 0);
662 sal_Int8
MediaWindowImpl::ExecuteDrop(const ExecuteDropEvent
& rEvt
)
664 return (mpMediaWindow
? mpMediaWindow
->ExecuteDrop(rEvt
) : 0);
667 void MediaWindowImpl::StartDrag(sal_Int8 nAction
, const Point
& rPosPixel
)
670 mpMediaWindow
->StartDrag(nAction
, rPosPixel
);
675 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */