android: Update app-specific/MIME type icons
[LibreOffice.git] / avmedia / source / viewer / mediawindow_impl.cxx
blob82ca1b92821c945ca91f6dd9ddb7e3499ae734c1
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 <iostream>
21 #include "mediawindow_impl.hxx"
22 #include "mediaevent_impl.hxx"
23 #include <mediamisc.hxx>
24 #include <bitmaps.hlst>
25 #include <helpids.h>
27 #include <algorithm>
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()
58 MediaItem aItem;
60 static_cast< MediaWindowImpl* >( GetParent() )->updateMediaItem( aItem );
61 setState(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)
123 : Control(pParent)
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()
138 disposeOnce();
141 void MediaWindowImpl::dispose()
143 if (mxEvents.is())
144 mxEvents->cleanUp();
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();
159 mxPlayer.clear();
161 mpMediaWindow = nullptr;
163 mpEmptyBmpEx.reset();
164 mpAudioBmpEx.reset();
165 mpMediaWindowControl.disposeAndClear();
166 mpChildWindow.disposeAndClear();
168 Control::dispose();
171 uno::Reference<media::XPlayer> MediaWindowImpl::createPlayer(const OUString& rURL, const OUString& rReferer, const OUString*)
173 uno::Reference<media::XPlayer> xPlayer;
175 if( rURL.isEmpty() )
176 return xPlayer;
178 if (SvtSecurityOptions::isUntrustedReferer(rReferer))
180 return xPlayer;
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);
189 else
190 xPlayer = createPlayer(rURL, AVMEDIA_MANAGER_SERVICE_NAME, xContext);
193 return xPlayer;
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),
205 uno::UNO_QUERY );
206 if( xManager.is() )
207 xPlayer = xManager->createPlayer( rURL );
208 else
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);
214 return xPlayer;
217 void MediaWindowImpl::setURL( const OUString& rURL,
218 OUString const& rTempURL, OUString const& rReferer)
220 maReferer = rReferer;
221 if( rURL == getURL() )
222 return;
224 if( mxPlayer.is() )
225 mxPlayer->stop();
227 if( mxPlayerWindow.is() )
229 mxPlayerWindow->setVisible( false );
230 mxPlayerWindow.clear();
233 mxPlayer.clear();
234 mTempFileURL.clear();
236 if (!rTempURL.isEmpty())
238 maFileURL = rURL;
239 mTempFileURL = rTempURL;
241 else
243 INetURLObject aURL( rURL );
245 if (aURL.GetProtocol() != INetProtocol::NotValid)
246 maFileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous);
247 else
248 maFileURL = rURL;
251 mxPlayer = createPlayer((!mTempFileURL.isEmpty()) ? mTempFileURL : maFileURL, rReferer, &m_sMimeType );
252 onURLChanged();
255 const OUString& MediaWindowImpl::getURL() const
257 return maFileURL;
260 bool MediaWindowImpl::isValid() const
262 return mxPlayer.is();
265 Size MediaWindowImpl::getPreferredSize() const
267 Size aRet(480, 360);
269 if( mxPlayer.is() )
271 awt::Size aPrefSize( mxPlayer->getPreferredPlayerWindowSize() );
273 aRet.setWidth( aPrefSize.Width );
274 aRet.setHeight( aPrefSize.Height );
277 return aRet;
280 bool MediaWindowImpl::start()
282 return mxPlayer.is() && ( mxPlayer->start(), true );
285 void MediaWindowImpl::updateMediaItem( MediaItem& rItem ) const
287 if( isPlaying() )
288 rItem.setState( MediaState::Play );
289 else
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 )
303 mpItem = &rItem;
304 comphelper::ScopeGuard g([this] { this->mpItem = nullptr; });
306 const AVMediaSetMask nMaskSet = rItem.getMaskSet();
308 // set URL first
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))
333 return;
335 switch (rItem.getState())
337 case MediaState::Play:
339 if (!isPlaying())
340 start();
342 break;
344 case MediaState::Pause:
346 if (isPlaying())
347 stop();
349 break;
351 case MediaState::Stop:
353 if (isPlaying())
355 setMediaTime( 0.0 );
356 stop();
357 setMediaTime( 0.0 );
360 break;
364 void MediaWindowImpl::stop()
366 if( mxPlayer.is() )
367 mxPlayer->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 )
382 if( mxPlayer.is() )
383 mxPlayer->setMediaTime( fTime );
386 double MediaWindowImpl::getMediaTime() const
388 return( mxPlayer.is() ? mxPlayer->getMediaTime() : 0.0 );
391 void MediaWindowImpl::stopPlayingInternal(bool bStop)
393 if (isPlaying())
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));
406 if (!mpChildWindow)
407 return;
408 mpChildWindow->SetHelpId(HID_AVMEDIA_PLAYERWINDOW);
409 mxEvents = new MediaEventListenersImpl(*mpChildWindow);
411 if (mxPlayer.is())
413 Resize();
414 uno::Reference<media::XPlayerWindow> xPlayerWindow;
415 const Point aPoint;
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 ) );
450 else
451 mxPlayerWindow.clear();
453 if( mxPlayerWindow.is() )
454 mpChildWindow->Show();
455 else
456 mpChildWindow->Hide();
458 if( mpMediaWindowControl )
460 MediaItem aItem;
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);
476 if (mpChildWindow)
477 mpChildWindow->SetPointer(aPointer);
479 if (!mxPlayerWindow.is())
480 return;
482 sal_Int32 nPointer;
484 switch (aPointer)
486 case PointerStyle::Cross:
487 nPointer = awt::SystemPointer::CROSS;
488 break;
489 case PointerStyle::Hand:
490 nPointer = awt::SystemPointer::HAND;
491 break;
492 case PointerStyle::Move:
493 nPointer = awt::SystemPointer::MOVE;
494 break;
495 case PointerStyle::Wait:
496 nPointer = awt::SystemPointer::WAIT;
497 break;
498 default:
499 nPointer = awt::SystemPointer::ARROW;
500 break;
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));
522 if (mpChildWindow)
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())
532 return;
534 // stop playing when going disabled or hidden
535 switch (eType)
537 case StateChangedType::Visible:
539 stopPlayingInternal(!IsVisible());
540 mxPlayerWindow->setVisible(IsVisible());
542 break;
544 case StateChangedType::Enable:
546 stopPlayingInternal(!IsEnabled());
547 mxPlayerWindow->setEnable(IsEnabled());
549 break;
551 default:
552 break;
556 void MediaWindowImpl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
558 if (mxPlayerWindow.is())
559 mxPlayerWindow->update();
561 BitmapEx* pLogo = nullptr;
563 if (!mxPlayer.is())
565 if (!mpEmptyBmpEx)
566 mpEmptyBmpEx.reset(new BitmapEx(AVMEDIA_BMP_EMPTYLOGO));
568 pLogo = mpEmptyBmpEx.get();
570 else if (!mxPlayerWindow.is())
572 if (!mpAudioBmpEx)
573 mpAudioBmpEx.reset(new BitmapEx(AVMEDIA_BMP_AUDIOLOGO));
575 pLogo = mpAudioBmpEx.get();
578 if (!mpChildWindow)
579 return;
581 const Point aBasePos(mpChildWindow->GetPosPixel());
582 const tools::Rectangle aVideoRect(aBasePos, mpChildWindow->GetSizePixel());
584 if (!pLogo || pLogo->IsEmpty() || aVideoRect.IsEmpty())
585 return;
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() );
604 else
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)
623 if (mpMediaWindow)
624 mpMediaWindow->MouseMove(rMEvt);
627 void MediaWindowImpl::MouseButtonDown(const MouseEvent& rMEvt)
629 if (mpMediaWindow)
630 mpMediaWindow->MouseButtonDown(rMEvt);
633 void MediaWindowImpl::MouseButtonUp(const MouseEvent& rMEvt)
635 if (mpMediaWindow)
636 mpMediaWindow->MouseButtonUp(rMEvt);
639 void MediaWindowImpl::KeyInput(const KeyEvent& rKEvt)
641 if (mpMediaWindow)
642 mpMediaWindow->KeyInput(rKEvt);
645 void MediaWindowImpl::KeyUp(const KeyEvent& rKEvt)
647 if (mpMediaWindow)
648 mpMediaWindow->KeyUp(rKEvt);
651 void MediaWindowImpl::Command(const CommandEvent& rCEvt)
653 if (mpMediaWindow)
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)
669 if (mpMediaWindow)
670 mpMediaWindow->StartDrag(nAction, rPosPixel);
673 } // namespace
675 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */