diff options
Diffstat (limited to 'avmedia/source/viewer')
-rw-r--r-- | avmedia/source/viewer/mediaevent_impl.cxx | 169 | ||||
-rw-r--r-- | avmedia/source/viewer/mediaevent_impl.hxx | 78 | ||||
-rw-r--r-- | avmedia/source/viewer/mediawindow.cxx | 512 | ||||
-rw-r--r-- | avmedia/source/viewer/mediawindow_impl.cxx | 674 | ||||
-rw-r--r-- | avmedia/source/viewer/mediawindow_impl.hxx | 158 |
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: */ |