summaryrefslogtreecommitdiffstats
path: root/avmedia/source/viewer
diff options
context:
space:
mode:
Diffstat (limited to 'avmedia/source/viewer')
-rw-r--r--avmedia/source/viewer/mediaevent_impl.cxx169
-rw-r--r--avmedia/source/viewer/mediaevent_impl.hxx78
-rw-r--r--avmedia/source/viewer/mediawindow.cxx512
-rw-r--r--avmedia/source/viewer/mediawindow_impl.cxx674
-rw-r--r--avmedia/source/viewer/mediawindow_impl.hxx158
5 files changed, 1591 insertions, 0 deletions
diff --git a/avmedia/source/viewer/mediaevent_impl.cxx b/avmedia/source/viewer/mediaevent_impl.cxx
new file mode 100644
index 000000000..d6a2c082c
--- /dev/null
+++ b/avmedia/source/viewer/mediaevent_impl.cxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "mediaevent_impl.hxx"
+#include <osl/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/event.hxx>
+#include <vcl/window.hxx>
+
+using namespace ::com::sun::star;
+
+namespace avmedia::priv {
+
+MediaEventListenersImpl::MediaEventListenersImpl( vcl::Window& rEventWindow ) :
+ mpNotifyWindow( &rEventWindow )
+{
+}
+
+
+MediaEventListenersImpl::~MediaEventListenersImpl()
+{
+}
+
+
+void MediaEventListenersImpl::cleanUp()
+{
+ Application::RemoveMouseAndKeyEvents( mpNotifyWindow.get() );
+ mpNotifyWindow = nullptr;
+}
+
+
+void SAL_CALL MediaEventListenersImpl::disposing( const css::lang::EventObject& )
+{
+}
+
+
+void SAL_CALL MediaEventListenersImpl::keyPressed( const css::awt::KeyEvent& e )
+{
+ const std::unique_lock aGuard( maMutex );
+
+ if( mpNotifyWindow )
+ {
+ vcl::KeyCode aVCLKeyCode( e.KeyCode,
+ ( ( e.Modifiers & 1 ) ? KEY_SHIFT : 0 ) |
+ ( ( e.Modifiers & 2 ) ? KEY_MOD1 : 0 ) |
+ ( ( e.Modifiers & 4 ) ? KEY_MOD2 : 0 ) );
+ KeyEvent aVCLKeyEvt( e.KeyChar, aVCLKeyCode );
+
+ Application::PostKeyEvent( VclEventId::WindowKeyInput, mpNotifyWindow.get(), &aVCLKeyEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::keyReleased( const css::awt::KeyEvent& e )
+{
+ const std::unique_lock aGuard( maMutex );
+
+ if( mpNotifyWindow )
+ {
+ vcl::KeyCode aVCLKeyCode( e.KeyCode,
+ ( ( e.Modifiers & 1 ) ? KEY_SHIFT : 0 ) |
+ ( ( e.Modifiers & 2 ) ? KEY_MOD1 : 0 ) |
+ ( ( e.Modifiers & 4 ) ? KEY_MOD2 : 0 ) );
+ KeyEvent aVCLKeyEvt( e.KeyChar, aVCLKeyCode );
+ Application::PostKeyEvent( VclEventId::WindowKeyUp, mpNotifyWindow.get(), &aVCLKeyEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mousePressed( const css::awt::MouseEvent& e )
+{
+ const std::unique_lock aGuard( maMutex );
+
+ if( mpNotifyWindow )
+ {
+ MouseEvent aVCLMouseEvt( Point( e.X, e.Y ),
+ sal::static_int_cast< sal_uInt16 >(e.ClickCount),
+ MouseEventModifiers::NONE,
+ ( ( e.Buttons & 1 ) ? MOUSE_LEFT : 0 ) |
+ ( ( e.Buttons & 2 ) ? MOUSE_RIGHT : 0 ) |
+ ( ( e.Buttons & 4 ) ? MOUSE_MIDDLE : 0 ),
+ e.Modifiers );
+ Application::PostMouseEvent( VclEventId::WindowMouseButtonDown, mpNotifyWindow.get(), &aVCLMouseEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseReleased( const css::awt::MouseEvent& e )
+{
+ const std::unique_lock aGuard( maMutex );
+ const SolarMutexGuard aAppGuard;
+
+ if( mpNotifyWindow )
+ {
+ MouseEvent aVCLMouseEvt( Point( e.X, e.Y ),
+ sal::static_int_cast< sal_uInt16 >(e.ClickCount),
+ MouseEventModifiers::NONE,
+ ( ( e.Buttons & 1 ) ? MOUSE_LEFT : 0 ) |
+ ( ( e.Buttons & 2 ) ? MOUSE_RIGHT : 0 ) |
+ ( ( e.Buttons & 4 ) ? MOUSE_MIDDLE : 0 ),
+ e.Modifiers );
+ Application::PostMouseEvent( VclEventId::WindowMouseButtonUp, mpNotifyWindow.get(), &aVCLMouseEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseEntered( const css::awt::MouseEvent& )
+{
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseExited( const css::awt::MouseEvent& )
+{
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseDragged( const css::awt::MouseEvent& e )
+{
+ const std::unique_lock aGuard( maMutex );
+
+ if( mpNotifyWindow )
+ {
+ MouseEvent aVCLMouseEvt( Point( e.X, e.Y ), 0, MouseEventModifiers::NONE, e.Buttons, e.Modifiers );
+ Application::PostMouseEvent( VclEventId::WindowMouseMove, mpNotifyWindow.get(), &aVCLMouseEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::mouseMoved( const css::awt::MouseEvent& e )
+{
+ const std::unique_lock aGuard( maMutex );
+
+ if( mpNotifyWindow )
+ {
+ MouseEvent aVCLMouseEvt( Point( e.X, e.Y ), 0, MouseEventModifiers::NONE, e.Buttons, e.Modifiers );
+ Application::PostMouseEvent( VclEventId::WindowMouseMove, mpNotifyWindow.get(), &aVCLMouseEvt );
+ }
+}
+
+
+void SAL_CALL MediaEventListenersImpl::focusGained( const css::awt::FocusEvent& )
+{
+}
+
+
+void SAL_CALL MediaEventListenersImpl::focusLost( const css::awt::FocusEvent& )
+{
+}
+
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediaevent_impl.hxx b/avmedia/source/viewer/mediaevent_impl.hxx
new file mode 100644
index 000000000..682eff1d7
--- /dev/null
+++ b/avmedia/source/viewer/mediaevent_impl.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <avmedia/mediawindow.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/awt/XKeyListener.hpp>
+#include <com/sun/star/awt/XMouseListener.hpp>
+#include <com/sun/star/awt/XMouseMotionListener.hpp>
+#include <com/sun/star/awt/XFocusListener.hpp>
+#include <vcl/vclptr.hxx>
+
+#include <mutex>
+
+namespace avmedia::priv
+ {
+
+ // - MediaEventListenersImpl -
+
+ class MediaEventListenersImpl : public ::cppu::WeakImplHelper< css::awt::XKeyListener,
+ css::awt::XMouseListener,
+ css::awt::XMouseMotionListener,
+ css::awt::XFocusListener >
+ {
+ public:
+
+ explicit MediaEventListenersImpl( vcl::Window& rNotifyWindow );
+ virtual ~MediaEventListenersImpl() override;
+
+ void cleanUp();
+
+ protected:
+
+ // XKeyListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ virtual void SAL_CALL keyPressed( const css::awt::KeyEvent& e ) override;
+ virtual void SAL_CALL keyReleased( const css::awt::KeyEvent& e ) override;
+
+ // XMouseListener
+ virtual void SAL_CALL mousePressed( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseReleased( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseEntered( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseExited( const css::awt::MouseEvent& e ) override;
+
+ // XMouseMotionListener
+ virtual void SAL_CALL mouseDragged( const css::awt::MouseEvent& e ) override;
+ virtual void SAL_CALL mouseMoved( const css::awt::MouseEvent& e ) override;
+
+ // XFocusListener
+ virtual void SAL_CALL focusGained( const css::awt::FocusEvent& e ) override;
+ virtual void SAL_CALL focusLost( const css::awt::FocusEvent& e ) override;
+
+ private:
+
+ VclPtr<vcl::Window> mpNotifyWindow;
+ mutable std::mutex maMutex;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediawindow.cxx b/avmedia/source/viewer/mediawindow.cxx
new file mode 100644
index 000000000..df8110f54
--- /dev/null
+++ b/avmedia/source/viewer/mediawindow.cxx
@@ -0,0 +1,512 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <avmedia/mediawindow.hxx>
+#include "mediawindow_impl.hxx"
+#include <mediamisc.hxx>
+#include <bitmaps.hlst>
+#include <strings.hrc>
+#include <tools/urlobj.hxx>
+#include <utility>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/frame/XDispatchHelper.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <com/sun/star/media/XPlayerNotifier.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <memory>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+
+#define AVMEDIA_FRAMEGRABBER_DEFAULTFRAME_MEDIATIME 3.0
+
+using namespace ::com::sun::star;
+
+namespace avmedia {
+
+MediaWindow::MediaWindow( vcl::Window* parent, bool bInternalMediaControl ) :
+ mpImpl( VclPtr<priv::MediaWindowImpl>::Create( parent, this, bInternalMediaControl ) )
+{
+ mpImpl->Show();
+}
+
+
+MediaWindow::~MediaWindow()
+{
+ mpImpl.disposeAndClear();
+}
+
+
+void MediaWindow::setURL( const OUString& rURL, const OUString& rReferer )
+{
+ mpImpl->setURL( rURL, OUString(), rReferer );
+}
+
+
+const OUString& MediaWindow::getURL() const
+{
+ return mpImpl->getURL();
+}
+
+
+bool MediaWindow::isValid() const
+{
+ return mpImpl->isValid();
+}
+
+
+void MediaWindow::MouseMove( const MouseEvent& )
+{
+}
+
+
+void MediaWindow::MouseButtonDown( const MouseEvent& )
+{
+}
+
+
+void MediaWindow::MouseButtonUp( const MouseEvent& )
+{
+}
+
+
+void MediaWindow::KeyInput( const KeyEvent& )
+{
+}
+
+
+void MediaWindow::KeyUp( const KeyEvent& )
+{
+}
+
+void MediaWindow::Command( const CommandEvent& )
+{
+}
+
+
+sal_Int8 MediaWindow::AcceptDrop( const AcceptDropEvent& )
+{
+ return 0;
+}
+
+
+sal_Int8 MediaWindow::ExecuteDrop( const ExecuteDropEvent& )
+{
+ return 0;
+}
+
+
+void MediaWindow::StartDrag( sal_Int8, const Point& )
+{
+}
+
+
+Size MediaWindow::getPreferredSize() const
+{
+ return mpImpl->getPreferredSize();
+}
+
+
+void MediaWindow::setPosSize( const tools::Rectangle& rNewRect )
+{
+ mpImpl->setPosSize( rNewRect );
+}
+
+
+void MediaWindow::setPointer( PointerStyle nPointer )
+{
+ mpImpl->setPointer( nPointer );
+}
+
+
+bool MediaWindow::start()
+{
+ return mpImpl->start();
+}
+
+void MediaWindow::updateMediaItem( MediaItem& rItem ) const
+{
+ mpImpl->updateMediaItem( rItem );
+}
+
+void MediaWindow::executeMediaItem( const MediaItem& rItem )
+{
+ mpImpl->executeMediaItem( rItem );
+}
+
+void MediaWindow::show()
+{
+ mpImpl->Show();
+}
+
+void MediaWindow::hide()
+{
+ mpImpl->Hide();
+}
+
+bool MediaWindow::isVisible() const
+{
+ return mpImpl->IsVisible();
+}
+
+vcl::Window* MediaWindow::getWindow() const
+{
+ return mpImpl.get();
+}
+
+
+FilterNameVector MediaWindow::getMediaFilters()
+{
+ return {{"Advanced Audio Coding", "aac"},
+ {"AIF Audio", "aif;aiff"},
+ {"Advanced Systems Format", "asf;wma;wmv"},
+ {"AU Audio", "au"},
+ {"AC3 Audio", "ac3"},
+ {"AVI", "avi"},
+ {"CD Audio", "cda"},
+ {"Digital Video", "dv"},
+ {"FLAC Audio", "flac"},
+ {"Flash Video", "flv"},
+ {"Matroska Media", "mkv"},
+ {"MIDI Audio", "mid;midi"},
+ {"MPEG Audio", "mp2;mp3;mpa;m4a"},
+ {"MPEG Video", "mpg;mpeg;mpv;mp4;m4v"},
+ {"Ogg Audio", "ogg;oga;opus"},
+ {"Ogg Video", "ogv;ogx"},
+ {"Real Audio", "ra"},
+ {"Real Media", "rm"},
+ {"RMI MIDI Audio", "rmi"},
+ {"SND (SouND) Audio", "snd"},
+ {"Quicktime Video", "mov"},
+ {"Vivo Video", "viv"},
+ {"WAVE Audio", "wav"},
+ {"WebM Video", "webm"},
+ {"Windows Media Audio", "wma"},
+ {"Windows Media Video", "wmv"}};
+}
+
+
+bool MediaWindow::executeMediaURLDialog(weld::Window* pParent, OUString& rURL, bool *const o_pbLink)
+{
+ ::sfx2::FileDialogHelper aDlg(o_pbLink != nullptr
+ ? ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW
+ : ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, pParent);
+ static const char aWildcard[] = "*.";
+ FilterNameVector aFilters = getMediaFilters();
+ static const char aSeparator[] = ";";
+ OUStringBuffer aAllTypes;
+
+ aDlg.SetContext(sfx2::FileDialogHelper::InsertMedia);
+ aDlg.SetTitle( AvmResId( o_pbLink != nullptr
+ ? AVMEDIA_STR_INSERTMEDIA_DLG : AVMEDIA_STR_OPENMEDIA_DLG ) );
+
+ for( const auto &filter : aFilters )
+ {
+ for( sal_Int32 nIndex = 0; nIndex >= 0; )
+ {
+ if( !aAllTypes.isEmpty() )
+ aAllTypes.append(aSeparator);
+
+ aAllTypes.append(OUString::Concat(aWildcard) + o3tl::getToken(filter.second, 0, ';', nIndex ));
+ }
+ }
+
+ // add filter for all media types
+ aDlg.AddFilter( AvmResId( AVMEDIA_STR_ALL_MEDIAFILES ), aAllTypes.makeStringAndClear() );
+
+ for( const auto &filter : aFilters )
+ {
+ OUStringBuffer aTypes;
+
+ for( sal_Int32 nIndex = 0; nIndex >= 0; )
+ {
+ if( !aTypes.isEmpty() )
+ aTypes.append(aSeparator);
+
+ aTypes.append(OUString::Concat(aWildcard) + o3tl::getToken(filter.second, 0, ';', nIndex ));
+ }
+
+ // add single filters
+ aDlg.AddFilter( filter.first, aTypes.makeStringAndClear() );
+ }
+
+ // add filter for all types
+ aDlg.AddFilter( AvmResId( AVMEDIA_STR_ALL_FILES ), "*.*" );
+
+ uno::Reference<ui::dialogs::XFilePicker3> const xFP(aDlg.GetFilePicker());
+ uno::Reference<ui::dialogs::XFilePickerControlAccess> const xCtrlAcc(xFP,
+ uno::UNO_QUERY_THROW);
+ if (o_pbLink != nullptr)
+ {
+ // for video link should be the default
+ xCtrlAcc->setValue(
+ ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK, 0,
+ uno::Any(true) );
+ // disabled for now: TODO: preview?
+ xCtrlAcc->enableControl(
+ ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW,
+ false);
+ }
+
+ if( aDlg.Execute() == ERRCODE_NONE )
+ {
+ const INetURLObject aURL( aDlg.GetPath() );
+ rURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+
+ if (o_pbLink != nullptr)
+ {
+ uno::Any const any = xCtrlAcc->getValue(
+ ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK, 0);
+ if (!(any >>= *o_pbLink))
+ {
+ SAL_WARN("avmedia", "invalid link property");
+ *o_pbLink = true;
+ }
+ }
+ }
+ else if( !rURL.isEmpty() )
+ rURL.clear();
+
+ return !rURL.isEmpty();
+}
+
+void MediaWindow::executeFormatErrorBox(weld::Window* pParent)
+{
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Warning, VclButtonsType::Ok, AvmResId(AVMEDIA_STR_ERR_URL)));
+ xBox->run();
+}
+
+bool MediaWindow::isMediaURL(std::u16string_view rURL, const OUString& rReferer, bool bDeep, rtl::Reference<PlayerListener> xPreferredPixelSizeListener)
+{
+ const INetURLObject aURL( rURL );
+
+ if( aURL.GetProtocol() == INetProtocol::NotValid )
+ return false;
+
+ if (bDeep || xPreferredPixelSizeListener)
+ {
+ try
+ {
+ uno::Reference< media::XPlayer > xPlayer( priv::MediaWindowImpl::createPlayer(
+ aURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ),
+ rReferer, nullptr ) );
+
+ if( xPlayer.is() )
+ {
+ if (xPreferredPixelSizeListener)
+ {
+ uno::Reference<media::XPlayerNotifier> xPlayerNotifier(xPlayer, css::uno::UNO_QUERY);
+ if (xPlayerNotifier)
+ {
+ // wait until it's possible to query this to get a sensible answer
+ xPreferredPixelSizeListener->startListening(xPlayerNotifier);
+ }
+ else
+ {
+ // assume the size is possible to query immediately
+ xPreferredPixelSizeListener->callPlayerWindowSizeAvailable(xPlayer);
+ }
+ }
+ return true;
+ }
+ }
+ catch( ... )
+ {
+ }
+ }
+ else
+ {
+ FilterNameVector aFilters = getMediaFilters();
+ const OUString aExt( aURL.getExtension() );
+
+ for( const auto &filter : aFilters )
+ {
+ for( sal_Int32 nIndex = 0; nIndex >= 0; )
+ {
+ if( aExt.equalsIgnoreAsciiCase( o3tl::getToken(filter.second, 0, ';', nIndex ) ) )
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+uno::Reference< media::XPlayer > MediaWindow::createPlayer( const OUString& rURL, const OUString& rReferer, const OUString* pMimeType )
+{
+ return priv::MediaWindowImpl::createPlayer( rURL, rReferer, pMimeType );
+}
+
+uno::Reference<graphic::XGraphic>
+MediaWindow::grabFrame(const uno::Reference<media::XPlayer>& xPlayer,
+ const uno::Reference<graphic::XGraphic>& rGraphic)
+{
+ uno::Reference< graphic::XGraphic > xRet;
+ std::unique_ptr< Graphic > xGraphic;
+
+ if( xPlayer.is() )
+ {
+ uno::Reference< media::XFrameGrabber > xGrabber( xPlayer->createFrameGrabber() );
+
+ if( xGrabber.is() )
+ {
+ double fMediaTime = AVMEDIA_FRAMEGRABBER_DEFAULTFRAME_MEDIATIME;
+
+ if( fMediaTime >= xPlayer->getDuration() )
+ fMediaTime = ( xPlayer->getDuration() * 0.5 );
+
+ xRet = xGrabber->grabFrame( fMediaTime );
+ }
+
+ if( !xRet.is() )
+ {
+ awt::Size aPrefSize( xPlayer->getPreferredPlayerWindowSize() );
+
+ if( !aPrefSize.Width && !aPrefSize.Height )
+ {
+ const BitmapEx aBmpEx(AVMEDIA_BMP_AUDIOLOGO);
+ xGraphic.reset( new Graphic( aBmpEx ) );
+ }
+ }
+ }
+
+ if (!xRet.is() && !xGraphic)
+ {
+ const BitmapEx aBmpEx(AVMEDIA_BMP_EMPTYLOGO);
+ xGraphic.reset( new Graphic( aBmpEx ) );
+ }
+
+ if (xGraphic)
+ {
+ if (rGraphic)
+ xGraphic.reset(new Graphic(rGraphic));
+ xRet = xGraphic->GetXGraphic();
+ }
+
+ return xRet;
+}
+
+uno::Reference< graphic::XGraphic > MediaWindow::grabFrame(const OUString& rURL,
+ const OUString& rReferer,
+ const OUString& sMimeType,
+ rtl::Reference<PlayerListener> xPreferredPixelSizeListener)
+{
+ uno::Reference<media::XPlayer> xPlayer(createPlayer(rURL, rReferer, &sMimeType));
+
+ if (xPreferredPixelSizeListener)
+ {
+ uno::Reference<media::XPlayerNotifier> xPlayerNotifier(xPlayer, css::uno::UNO_QUERY);
+ if (xPlayerNotifier)
+ {
+ // set a callback to call when a more sensible result is available, which
+ // might be called immediately if already available
+ xPreferredPixelSizeListener->startListening(xPlayerNotifier);
+ }
+ else
+ {
+ // assume the size is possible to query immediately
+ xPreferredPixelSizeListener->callPlayerWindowSizeAvailable(xPlayer);
+ }
+
+ return nullptr;
+ }
+
+ return grabFrame(xPlayer);
+}
+
+void MediaWindow::dispatchInsertAVMedia(const css::uno::Reference<css::frame::XDispatchProvider>& rDispatchProvider,
+ const css::awt::Size& rSize, const OUString& rURL, bool bLink)
+{
+ util::URL aDispatchURL;
+ aDispatchURL.Complete = ".uno:InsertAVMedia";
+
+ css::uno::Reference<css::util::XURLTransformer> xTrans(css::util::URLTransformer::create(::comphelper::getProcessComponentContext()));
+ xTrans->parseStrict(aDispatchURL);
+
+ css::uno::Reference<css::frame::XDispatch> xDispatch = rDispatchProvider->queryDispatch(aDispatchURL, "", 0);
+ css::uno::Sequence<css::beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
+ { "URL", css::uno::Any(rURL) },
+ { "Size.Width", uno::Any(rSize.Width)},
+ { "Size.Height", uno::Any(rSize.Height)},
+ { "IsLink", css::uno::Any(bLink) },
+ }));
+ xDispatch->dispatch(aDispatchURL, aArgs);
+}
+
+PlayerListener::PlayerListener(std::function<void(const css::uno::Reference<css::media::XPlayer>&)> fn)
+ : PlayerListener_BASE(m_aMutex)
+ , m_aFn(std::move(fn))
+{
+}
+
+void PlayerListener::dispose()
+{
+ stopListening();
+ PlayerListener_BASE::dispose();
+}
+
+void PlayerListener::startListening(const css::uno::Reference<media::XPlayerNotifier>& rNotifier)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ m_xNotifier = rNotifier;
+ m_xNotifier->addPlayerListener(this);
+}
+
+void PlayerListener::stopListening()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (!m_xNotifier)
+ return;
+ m_xNotifier->removePlayerListener(this);
+ m_xNotifier.clear();
+}
+
+void SAL_CALL PlayerListener::preferredPlayerWindowSizeAvailable(const css::lang::EventObject&)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ css::uno::Reference<media::XPlayer> xPlayer(m_xNotifier, css::uno::UNO_QUERY_THROW);
+ callPlayerWindowSizeAvailable(xPlayer);
+
+ stopListening();
+}
+
+void SAL_CALL PlayerListener::disposing(const css::lang::EventObject&)
+{
+}
+
+PlayerListener::~PlayerListener()
+{
+}
+
+} // namespace avmedia
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediawindow_impl.cxx b/avmedia/source/viewer/mediawindow_impl.cxx
new file mode 100644
index 000000000..a12ed42d4
--- /dev/null
+++ b/avmedia/source/viewer/mediawindow_impl.cxx
@@ -0,0 +1,674 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <iostream>
+#include "mediawindow_impl.hxx"
+#include "mediaevent_impl.hxx"
+#include <mediamisc.hxx>
+#include <bitmaps.hlst>
+#include <helpids.h>
+
+#include <algorithm>
+#include <string_view>
+
+#include <sal/log.hxx>
+#include <comphelper/processfactory.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/scopeguard.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/securityoptions.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/awt/SystemPointer.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/media/XManager.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+using namespace ::com::sun::star;
+
+namespace avmedia::priv {
+
+MediaWindowControl::MediaWindowControl(vcl::Window* pParent)
+ : MediaControl(pParent, MediaControlStyle::MultiLine)
+{
+}
+
+void MediaWindowControl::update()
+{
+ MediaItem aItem;
+
+ static_cast< MediaWindowImpl* >( GetParent() )->updateMediaItem( aItem );
+ setState(aItem);
+}
+
+void MediaWindowControl::execute(const MediaItem& rItem)
+{
+ static_cast<MediaWindowImpl*>(GetParent())->executeMediaItem(rItem);
+}
+
+MediaChildWindow::MediaChildWindow(vcl::Window* pParent)
+ : SystemChildWindow(pParent, WB_CLIPCHILDREN)
+{
+}
+
+void MediaChildWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ SystemChildWindow::MouseMove( rMEvt );
+ GetParent()->MouseMove( aTransformedEvent );
+}
+
+void MediaChildWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ SystemChildWindow::MouseButtonDown( rMEvt );
+ GetParent()->MouseButtonDown( aTransformedEvent );
+}
+
+void MediaChildWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ const MouseEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ SystemChildWindow::MouseButtonUp( rMEvt );
+ GetParent()->MouseButtonUp( aTransformedEvent );
+}
+
+void MediaChildWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ SystemChildWindow::KeyInput( rKEvt );
+ GetParent()->KeyInput( rKEvt );
+}
+
+void MediaChildWindow::KeyUp( const KeyEvent& rKEvt )
+{
+ SystemChildWindow::KeyUp( rKEvt );
+ GetParent()->KeyUp( rKEvt );
+}
+
+void MediaChildWindow::Command( const CommandEvent& rCEvt )
+{
+ const CommandEvent aTransformedEvent( GetParent()->ScreenToOutputPixel( OutputToScreenPixel( rCEvt.GetMousePosPixel() ) ),
+ rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData() );
+
+ SystemChildWindow::Command( rCEvt );
+ GetParent()->Command( aTransformedEvent );
+}
+
+MediaWindowImpl::MediaWindowImpl(vcl::Window* pParent, MediaWindow* pMediaWindow, bool bInternalMediaControl)
+ : Control(pParent)
+ , DropTargetHelper(this)
+ , DragSourceHelper(this)
+ , mpMediaWindow(pMediaWindow)
+ , mpMediaWindowControl(bInternalMediaControl ? VclPtr<MediaWindowControl>::Create(this) : nullptr)
+{
+ if (mpMediaWindowControl)
+ {
+ mpMediaWindowControl->SetSizePixel(mpMediaWindowControl->GetOptimalSize());
+ mpMediaWindowControl->Show();
+ }
+}
+
+MediaWindowImpl::~MediaWindowImpl()
+{
+ disposeOnce();
+}
+
+void MediaWindowImpl::dispose()
+{
+ if (mxEvents.is())
+ mxEvents->cleanUp();
+
+ if (mxPlayerWindow.is())
+ {
+ mxPlayerWindow->removeKeyListener( uno::Reference< awt::XKeyListener >( mxEvents ) );
+ mxPlayerWindow->removeMouseListener( uno::Reference< awt::XMouseListener >( mxEvents ) );
+ mxPlayerWindow->removeMouseMotionListener( uno::Reference< awt::XMouseMotionListener >( mxEvents ) );
+ mxPlayerWindow->dispose();
+ mxPlayerWindow.clear();
+ }
+
+ uno::Reference< lang::XComponent > xComponent( mxPlayer, uno::UNO_QUERY );
+ if (xComponent.is()) // this stops the player
+ xComponent->dispose();
+
+ mxPlayer.clear();
+
+ mpMediaWindow = nullptr;
+
+ mpEmptyBmpEx.reset();
+ mpAudioBmpEx.reset();
+ mpMediaWindowControl.disposeAndClear();
+ mpChildWindow.disposeAndClear();
+
+ Control::dispose();
+}
+
+uno::Reference<media::XPlayer> MediaWindowImpl::createPlayer(const OUString& rURL, const OUString& rReferer, const OUString* pMimeType)
+{
+ uno::Reference<media::XPlayer> xPlayer;
+
+ if( rURL.isEmpty() )
+ return xPlayer;
+
+ if (SvtSecurityOptions::isUntrustedReferer(rReferer))
+ {
+ return xPlayer;
+ }
+
+ if (!pMimeType || *pMimeType == AVMEDIA_MIMETYPE_COMMON)
+ {
+ uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ if (Application::GetToolkitName() == "gtk4")
+ xPlayer = createPlayer(rURL, "com.sun.star.comp.avmedia.Manager_Gtk", xContext);
+ else
+ xPlayer = createPlayer(rURL, AVMEDIA_MANAGER_SERVICE_NAME, xContext);
+ }
+
+ return xPlayer;
+}
+
+uno::Reference< media::XPlayer > MediaWindowImpl::createPlayer(
+ const OUString& rURL, const OUString& rManagerServName,
+ const uno::Reference< uno::XComponentContext >& xContext)
+{
+ uno::Reference< media::XPlayer > xPlayer;
+ try
+ {
+ uno::Reference< media::XManager > xManager (
+ xContext->getServiceManager()->createInstanceWithContext(rManagerServName, xContext),
+ uno::UNO_QUERY );
+ if( xManager.is() )
+ xPlayer = xManager->createPlayer( rURL );
+ else
+ SAL_INFO( "avmedia", "failed to create media player service " << rManagerServName );
+ } catch ( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION( "avmedia", "couldn't create media player " << rManagerServName);
+ }
+ return xPlayer;
+}
+
+void MediaWindowImpl::setURL( const OUString& rURL,
+ OUString const& rTempURL, OUString const& rReferer)
+{
+ maReferer = rReferer;
+ if( rURL == getURL() )
+ return;
+
+ if( mxPlayer.is() )
+ mxPlayer->stop();
+
+ if( mxPlayerWindow.is() )
+ {
+ mxPlayerWindow->setVisible( false );
+ mxPlayerWindow.clear();
+ }
+
+ mxPlayer.clear();
+ mTempFileURL.clear();
+
+ if (!rTempURL.isEmpty())
+ {
+ maFileURL = rURL;
+ mTempFileURL = rTempURL;
+ }
+ else
+ {
+ INetURLObject aURL( rURL );
+
+ if (aURL.GetProtocol() != INetProtocol::NotValid)
+ maFileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous);
+ else
+ maFileURL = rURL;
+ }
+
+ mxPlayer = createPlayer((!mTempFileURL.isEmpty()) ? mTempFileURL : maFileURL, rReferer, &m_sMimeType );
+ onURLChanged();
+}
+
+const OUString& MediaWindowImpl::getURL() const
+{
+ return maFileURL;
+}
+
+bool MediaWindowImpl::isValid() const
+{
+ return mxPlayer.is();
+}
+
+Size MediaWindowImpl::getPreferredSize() const
+{
+ Size aRet(480, 360);
+
+ if( mxPlayer.is() )
+ {
+ awt::Size aPrefSize( mxPlayer->getPreferredPlayerWindowSize() );
+
+ aRet.setWidth( aPrefSize.Width );
+ aRet.setHeight( aPrefSize.Height );
+ }
+
+ return aRet;
+}
+
+bool MediaWindowImpl::start()
+{
+ return mxPlayer.is() && ( mxPlayer->start(), true );
+}
+
+void MediaWindowImpl::updateMediaItem( MediaItem& rItem ) const
+{
+ if( isPlaying() )
+ rItem.setState( MediaState::Play );
+ else
+ rItem.setState( ( getMediaTime() == 0.0 ) ? MediaState::Stop : MediaState::Pause );
+
+ rItem.setDuration( getDuration() );
+ rItem.setTime( getMediaTime() );
+ rItem.setLoop( mxPlayer.is() && mxPlayer->isPlaybackLoop() );
+ rItem.setMute( mxPlayer.is() && mxPlayer->isMute() );
+ rItem.setVolumeDB( mxPlayer.is() ? mxPlayer->getVolumeDB() : 0 );
+ rItem.setZoom( mxPlayerWindow.is() ? mxPlayerWindow->getZoomLevel() : media::ZoomLevel_NOT_AVAILABLE );
+ rItem.setURL( getURL(), mTempFileURL, maReferer );
+}
+
+void MediaWindowImpl::executeMediaItem( const MediaItem& rItem )
+{
+ mpItem = &rItem;
+ comphelper::ScopeGuard g([this] { this->mpItem = nullptr; });
+
+ const AVMediaSetMask nMaskSet = rItem.getMaskSet();
+
+ // set URL first
+ if (nMaskSet & AVMediaSetMask::URL)
+ {
+ m_sMimeType = rItem.getMimeType();
+ setURL(rItem.getURL(), rItem.getTempURL(), rItem.getReferer());
+ }
+
+ // set different states next
+ if (nMaskSet & AVMediaSetMask::TIME)
+ setMediaTime(std::min(rItem.getTime(), getDuration()));
+
+ if (nMaskSet & AVMediaSetMask::LOOP && mxPlayer.is() )
+ mxPlayer->setPlaybackLoop( rItem.isLoop() );
+
+ if (nMaskSet & AVMediaSetMask::MUTE && mxPlayer.is() )
+ mxPlayer->setMute( rItem.isMute() );
+
+ if (nMaskSet & AVMediaSetMask::VOLUMEDB && mxPlayer.is() )
+ mxPlayer->setVolumeDB( rItem.getVolumeDB() );
+
+ if (nMaskSet & AVMediaSetMask::ZOOM && mxPlayerWindow.is() )
+ mxPlayerWindow->setZoomLevel( rItem.getZoom() );
+
+ // set play state at last
+ if (!(nMaskSet & AVMediaSetMask::STATE))
+ return;
+
+ switch (rItem.getState())
+ {
+ case MediaState::Play:
+ {
+ if (!isPlaying())
+ start();
+ }
+ break;
+
+ case MediaState::Pause:
+ {
+ if (isPlaying())
+ stop();
+ }
+ break;
+
+ case MediaState::Stop:
+ {
+ if (isPlaying())
+ {
+ setMediaTime( 0.0 );
+ stop();
+ setMediaTime( 0.0 );
+ }
+ }
+ break;
+ }
+}
+
+void MediaWindowImpl::stop()
+{
+ if( mxPlayer.is() )
+ mxPlayer->stop();
+}
+
+bool MediaWindowImpl::isPlaying() const
+{
+ return( mxPlayer.is() && mxPlayer->isPlaying() );
+}
+
+double MediaWindowImpl::getDuration() const
+{
+ return( mxPlayer.is() ? mxPlayer->getDuration() : 0.0 );
+}
+
+void MediaWindowImpl::setMediaTime( double fTime )
+{
+ if( mxPlayer.is() )
+ mxPlayer->setMediaTime( fTime );
+}
+
+double MediaWindowImpl::getMediaTime() const
+{
+ return( mxPlayer.is() ? mxPlayer->getMediaTime() : 0.0 );
+}
+
+void MediaWindowImpl::stopPlayingInternal(bool bStop)
+{
+ if (isPlaying())
+ {
+ bStop ? mxPlayer->stop() : mxPlayer->start();
+ }
+}
+
+void MediaWindowImpl::onURLChanged()
+{
+ if (m_sMimeType == AVMEDIA_MIMETYPE_COMMON)
+ {
+ mpChildWindow.disposeAndClear();
+ mpChildWindow.reset(VclPtr<MediaChildWindow>::Create(this));
+ }
+ if (!mpChildWindow)
+ return;
+ mpChildWindow->SetHelpId(HID_AVMEDIA_PLAYERWINDOW);
+ mxEvents = new MediaEventListenersImpl(*mpChildWindow);
+
+ if (mxPlayer.is())
+ {
+ Resize();
+ uno::Reference<media::XPlayerWindow> xPlayerWindow;
+ const Point aPoint;
+ const Size aSize(mpChildWindow->GetSizePixel());
+
+ sal_IntPtr nParentWindowHandle(0);
+ const SystemEnvData* pEnvData = mpChildWindow->GetSystemData();
+ // tdf#139609 gtk doesn't need the handle, and fetching it is undesirable
+ if (!pEnvData || pEnvData->toolkit != SystemEnvData::Toolkit::Gtk)
+ nParentWindowHandle = mpChildWindow->GetParentWindowHandle();
+ uno::Sequence<uno::Any> aArgs{
+ uno::Any(nParentWindowHandle),
+ uno::Any(awt::Rectangle(aPoint.X(), aPoint.Y(), aSize.Width(), aSize.Height())),
+ uno::Any(reinterpret_cast<sal_IntPtr>(mpChildWindow.get())),
+ // Media item contains media properties, e.g. cropping.
+ uno::Any(reinterpret_cast<sal_IntPtr>(mpItem))
+ };
+
+ try
+ {
+ xPlayerWindow = mxPlayer->createPlayerWindow( aArgs );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ // happens eg, on MacOSX where Java frames cannot be created from X11 window handles
+ }
+
+ mxPlayerWindow = xPlayerWindow;
+
+ if( xPlayerWindow.is() )
+ {
+ xPlayerWindow->addKeyListener( uno::Reference< awt::XKeyListener >( mxEvents ) );
+ xPlayerWindow->addMouseListener( uno::Reference< awt::XMouseListener >( mxEvents ) );
+ xPlayerWindow->addMouseMotionListener( uno::Reference< awt::XMouseMotionListener >( mxEvents ) );
+ xPlayerWindow->addFocusListener( uno::Reference< awt::XFocusListener >( mxEvents ) );
+ }
+ }
+ else
+ mxPlayerWindow.clear();
+
+ if( mxPlayerWindow.is() )
+ mpChildWindow->Show();
+ else
+ mpChildWindow->Hide();
+
+ if( mpMediaWindowControl )
+ {
+ MediaItem aItem;
+
+ updateMediaItem( aItem );
+ mpMediaWindowControl->setState( aItem );
+ }
+}
+
+void MediaWindowImpl::setPosSize(const tools::Rectangle& rRect)
+{
+ SetPosSizePixel(rRect.TopLeft(), rRect.GetSize());
+}
+
+void MediaWindowImpl::setPointer(PointerStyle aPointer)
+{
+ SetPointer(aPointer);
+
+ if (mpChildWindow)
+ mpChildWindow->SetPointer(aPointer);
+
+ if (!mxPlayerWindow.is())
+ return;
+
+ sal_Int32 nPointer;
+
+ switch (aPointer)
+ {
+ case PointerStyle::Cross:
+ nPointer = awt::SystemPointer::CROSS;
+ break;
+ case PointerStyle::Hand:
+ nPointer = awt::SystemPointer::HAND;
+ break;
+ case PointerStyle::Move:
+ nPointer = awt::SystemPointer::MOVE;
+ break;
+ case PointerStyle::Wait:
+ nPointer = awt::SystemPointer::WAIT;
+ break;
+ default:
+ nPointer = awt::SystemPointer::ARROW;
+ break;
+ }
+
+ mxPlayerWindow->setPointerType(nPointer);
+}
+
+void MediaWindowImpl::Resize()
+{
+ const Size aCurSize(GetOutputSizePixel());
+ const sal_Int32 nOffset(mpMediaWindowControl ? AVMEDIA_CONTROLOFFSET : 0);
+
+ Size aPlayerWindowSize(aCurSize.Width() - (nOffset << 1),
+ aCurSize.Height() - (nOffset << 1));
+
+ if (mpMediaWindowControl)
+ {
+ const sal_Int32 nControlHeight = mpMediaWindowControl->GetSizePixel().Height();
+ const sal_Int32 nControlY = std::max(aCurSize.Height() - nControlHeight - nOffset, tools::Long(0));
+
+ aPlayerWindowSize.setHeight( nControlY - (nOffset << 1) );
+ mpMediaWindowControl->SetPosSizePixel(Point(nOffset, nControlY ), Size(aCurSize.Width() - (nOffset << 1), nControlHeight));
+ }
+ if (mpChildWindow)
+ mpChildWindow->SetPosSizePixel(Point(0, 0), aPlayerWindowSize);
+
+ if (mxPlayerWindow.is())
+ mxPlayerWindow->setPosSize(0, 0, aPlayerWindowSize.Width(), aPlayerWindowSize.Height(), 0);
+}
+
+void MediaWindowImpl::StateChanged(StateChangedType eType)
+{
+ if (!mxPlayerWindow.is())
+ return;
+
+ // stop playing when going disabled or hidden
+ switch (eType)
+ {
+ case StateChangedType::Visible:
+ {
+ stopPlayingInternal(!IsVisible());
+ mxPlayerWindow->setVisible(IsVisible());
+ }
+ break;
+
+ case StateChangedType::Enable:
+ {
+ stopPlayingInternal(!IsEnabled());
+ mxPlayerWindow->setEnable(IsEnabled());
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MediaWindowImpl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ if (mxPlayerWindow.is())
+ mxPlayerWindow->update();
+
+ BitmapEx* pLogo = nullptr;
+
+ if (!mxPlayer.is())
+ {
+ if (!mpEmptyBmpEx)
+ mpEmptyBmpEx.reset(new BitmapEx(AVMEDIA_BMP_EMPTYLOGO));
+
+ pLogo = mpEmptyBmpEx.get();
+ }
+ else if (!mxPlayerWindow.is())
+ {
+ if (!mpAudioBmpEx)
+ mpAudioBmpEx.reset(new BitmapEx(AVMEDIA_BMP_AUDIOLOGO));
+
+ pLogo = mpAudioBmpEx.get();
+ }
+
+ if (!mpChildWindow)
+ return;
+
+ const Point aBasePos(mpChildWindow->GetPosPixel());
+ const tools::Rectangle aVideoRect(aBasePos, mpChildWindow->GetSizePixel());
+
+ if (!pLogo || pLogo->IsEmpty() || aVideoRect.IsEmpty())
+ return;
+
+ Size aLogoSize(pLogo->GetSizePixel());
+ const Color aBackgroundColor(67, 67, 67);
+
+ rRenderContext.SetLineColor(aBackgroundColor);
+ rRenderContext.SetFillColor(aBackgroundColor);
+ rRenderContext.DrawRect(aVideoRect);
+
+ if ((aLogoSize.Width() > aVideoRect.GetWidth() || aLogoSize.Height() > aVideoRect.GetHeight() ) &&
+ (aLogoSize.Height() > 0))
+ {
+ const double fLogoWH = double(aLogoSize.Width()) / aLogoSize.Height();
+
+ if (fLogoWH < (double(aVideoRect.GetWidth()) / aVideoRect.GetHeight()))
+ {
+ aLogoSize.setWidth( tools::Long(aVideoRect.GetHeight() * fLogoWH) );
+ aLogoSize.setHeight( aVideoRect.GetHeight() );
+ }
+ else
+ {
+ aLogoSize.setWidth( aVideoRect.GetWidth() );
+ aLogoSize.setHeight( tools::Long(aVideoRect.GetWidth() / fLogoWH) );
+ }
+ }
+
+ Point aPoint(aBasePos.X() + ((aVideoRect.GetWidth() - aLogoSize.Width()) >> 1),
+ aBasePos.Y() + ((aVideoRect.GetHeight() - aLogoSize.Height()) >> 1));
+
+ rRenderContext.DrawBitmapEx(aPoint, aLogoSize, *pLogo);
+}
+
+void MediaWindowImpl::GetFocus()
+{
+}
+
+void MediaWindowImpl::MouseMove(const MouseEvent& rMEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->MouseMove(rMEvt);
+}
+
+void MediaWindowImpl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->MouseButtonDown(rMEvt);
+}
+
+void MediaWindowImpl::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->MouseButtonUp(rMEvt);
+}
+
+void MediaWindowImpl::KeyInput(const KeyEvent& rKEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->KeyInput(rKEvt);
+}
+
+void MediaWindowImpl::KeyUp(const KeyEvent& rKEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->KeyUp(rKEvt);
+}
+
+void MediaWindowImpl::Command(const CommandEvent& rCEvt)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->Command(rCEvt);
+}
+
+sal_Int8 MediaWindowImpl::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ return (mpMediaWindow ? mpMediaWindow->AcceptDrop(rEvt) : 0);
+}
+
+sal_Int8 MediaWindowImpl::ExecuteDrop(const ExecuteDropEvent& rEvt)
+{
+ return (mpMediaWindow ? mpMediaWindow->ExecuteDrop(rEvt) : 0);
+}
+
+void MediaWindowImpl::StartDrag(sal_Int8 nAction, const Point& rPosPixel)
+{
+ if (mpMediaWindow)
+ mpMediaWindow->StartDrag(nAction, rPosPixel);
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/avmedia/source/viewer/mediawindow_impl.hxx b/avmedia/source/viewer/mediawindow_impl.hxx
new file mode 100644
index 000000000..aa95fde22
--- /dev/null
+++ b/avmedia/source/viewer/mediawindow_impl.hxx
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include <vcl/syschild.hxx>
+
+#include <mediacontrol.hxx>
+
+namespace com::sun::star::media {
+ class XPlayer;
+ class XPlayerWindow;
+}
+
+namespace com::sun::star::uno {
+ class XComponentContext;
+}
+
+class BitmapEx;
+
+namespace avmedia
+{
+
+class MediaWindow;
+
+namespace priv
+{
+
+class MediaWindowControl : public MediaControl
+{
+public:
+
+ explicit MediaWindowControl( vcl::Window* pParent );
+
+protected:
+
+ void update() override;
+ void execute( const MediaItem& rItem ) override;
+};
+
+class MediaChildWindow : public SystemChildWindow
+{
+public:
+
+ explicit MediaChildWindow( vcl::Window* pParent );
+
+protected:
+
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void KeyUp( const KeyEvent& rKEvt ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+};
+
+class MediaEventListenersImpl;
+
+class MediaWindowImpl : public Control, public DropTargetHelper, public DragSourceHelper
+{
+public:
+ MediaWindowImpl(vcl::Window* parent, MediaWindow* pMediaWindow, bool bInternalMediaControl);
+ virtual ~MediaWindowImpl() override;
+
+ virtual void dispose() override;
+
+ static css::uno::Reference<css::media::XPlayer> createPlayer(const OUString& rURL, const OUString& rReferer, const OUString* pMimeType);
+
+ void setURL(const OUString& rURL, OUString const& rTempURL, OUString const& rReferer);
+
+ const OUString& getURL() const;
+
+ bool isValid() const;
+
+ Size getPreferredSize() const;
+
+ bool start();
+
+ void updateMediaItem( MediaItem& rItem ) const;
+ void executeMediaItem( const MediaItem& rItem );
+
+ void setPosSize( const tools::Rectangle& rRect );
+
+ void setPointer( PointerStyle nPointer );
+
+private:
+
+ // Window
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void KeyUp( const KeyEvent& rKEvt ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+ virtual void Resize() override;
+ virtual void StateChanged( StateChangedType ) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override; // const
+ virtual void GetFocus() override;
+
+ // DropTargetHelper
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ // DragSourceHelper
+ virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
+
+ void stop();
+
+ bool isPlaying() const;
+
+ double getDuration() const;
+
+ void setMediaTime( double fTime );
+ double getMediaTime() const;
+
+ void stopPlayingInternal( bool );
+
+ void onURLChanged();
+
+ static css::uno::Reference<css::media::XPlayer> createPlayer(const OUString& rURL, const OUString& rManagerServName,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext);
+
+ OUString maFileURL;
+ OUString mTempFileURL;
+ OUString maReferer;
+ OUString m_sMimeType;
+ css::uno::Reference<css::media::XPlayer> mxPlayer;
+ css::uno::Reference<css::media::XPlayerWindow> mxPlayerWindow;
+ MediaWindow* mpMediaWindow;
+
+ rtl::Reference<MediaEventListenersImpl> mxEvents;
+ VclPtr<MediaChildWindow> mpChildWindow;
+ VclPtr<MediaWindowControl> mpMediaWindowControl;
+ std::unique_ptr<BitmapEx> mpEmptyBmpEx;
+ std::unique_ptr<BitmapEx> mpAudioBmpEx;
+ const MediaItem* mpItem = nullptr;
+};
+
+}} // end namespace avmedia::priv
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */