diff options
author | Caolán McNamara <caolanm@redhat.com> | 2022-02-21 10:01:42 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2022-03-01 18:38:27 +0100 |
commit | 05db887bc226b85befe2c2b9e84b796020a6ca05 (patch) | |
tree | cdb86937b266212f6fae5f7d6e596f30350a49ad | |
parent | ae071f7d680545e284e5947d26cbea30e59bdfb5 (diff) |
gtk4: media dimensions are only reliably available async
this is also the case for the direct gstreamer use in gtk3 but
more egregious when abstracted away from it in gtk4
Change-Id: If90069308d67929585722c079c482cd4ad196e1f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130468
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r-- | avmedia/source/gtk/gtkplayer.cxx | 130 | ||||
-rw-r--r-- | avmedia/source/gtk/gtkplayer.hxx | 20 | ||||
-rw-r--r-- | avmedia/source/viewer/mediawindow.cxx | 127 | ||||
-rw-r--r-- | include/avmedia/mediawindow.hxx | 47 | ||||
-rw-r--r-- | sc/source/ui/drawfunc/fuins1.cxx | 57 | ||||
-rw-r--r-- | sd/source/ui/func/fuinsert.cxx | 99 | ||||
-rw-r--r-- | sd/source/ui/inc/View.hxx | 3 | ||||
-rw-r--r-- | sd/source/ui/inc/fuinsert.hxx | 5 | ||||
-rw-r--r-- | sd/source/ui/view/sdview.cxx | 7 | ||||
-rw-r--r-- | sd/source/ui/view/sdview4.cxx | 57 | ||||
-rw-r--r-- | sfx2/sdi/sfx.sdi | 6 | ||||
-rw-r--r-- | svx/source/svdraw/svdomedia.cxx | 15 | ||||
-rw-r--r-- | sw/source/uibase/shells/grfshex.cxx | 118 |
13 files changed, 512 insertions, 179 deletions
diff --git a/avmedia/source/gtk/gtkplayer.cxx b/avmedia/source/gtk/gtkplayer.cxx index 7ce488f231ec..b988e7f19684 100644 --- a/avmedia/source/gtk/gtkplayer.cxx +++ b/avmedia/source/gtk/gtkplayer.cxx @@ -37,8 +37,12 @@ namespace avmedia::gtk { GtkPlayer::GtkPlayer() : GtkPlayer_BASE(m_aMutex) + , m_lListener(m_aMutex) , m_pStream(nullptr) , m_pVideo(nullptr) + , m_nNotifySignalId(0) + , m_nInvalidateSizeSignalId(0) + , m_nTimeoutId(0) , m_nUnmutedVolume(0) { } @@ -61,6 +65,8 @@ void GtkPlayer::cleanup() if (m_pStream) { + uninstallNotify(); + // shouldn't have to attempt this unref on idle, but with gtk4-4.4.1 I get // intermittent "instance of invalid non-instantiatable type '(null)'" // on some mysterious gst dbus callback @@ -81,6 +87,51 @@ void SAL_CALL GtkPlayer::disposing() cleanup(); } +static void do_notify(GtkPlayer* pThis) +{ + rtl::Reference<GtkPlayer> xThis(pThis); + xThis->notifyListeners(); + xThis->uninstallNotify(); +} + +static void invalidate_size_cb(GdkPaintable* /*pPaintable*/, GtkPlayer* pThis) { do_notify(pThis); } + +static void notify_cb(GtkMediaStream* /*pStream*/, GParamSpec* pspec, GtkPlayer* pThis) +{ + if (g_str_equal(pspec->name, "prepared") || g_str_equal(pspec->name, "error")) + do_notify(pThis); +} + +static bool timeout_cb(GtkPlayer* pThis) +{ + do_notify(pThis); + return false; +} + +void GtkPlayer::installNotify() +{ + if (m_nNotifySignalId) + return; + m_nNotifySignalId = g_signal_connect(m_pStream, "notify", G_CALLBACK(notify_cb), this); + // notify should be enough, but there is an upstream bug so also try "invalidate-size" and add a timeout for + // audio-only case where that won't happen, see: https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4513 + m_nInvalidateSizeSignalId + = g_signal_connect(m_pStream, "invalidate-size", G_CALLBACK(invalidate_size_cb), this); + m_nTimeoutId = g_timeout_add_seconds(10, G_SOURCE_FUNC(timeout_cb), this); +} + +void GtkPlayer::uninstallNotify() +{ + if (!m_nNotifySignalId) + return; + g_signal_handler_disconnect(m_pStream, m_nNotifySignalId); + m_nNotifySignalId = 0; + g_signal_handler_disconnect(m_pStream, m_nInvalidateSizeSignalId); + m_nInvalidateSizeSignalId = 0; + g_source_remove(m_nTimeoutId); + m_nTimeoutId = 0; +} + bool GtkPlayer::create(const OUString& rURL) { bool bRet = false; @@ -104,6 +155,25 @@ bool GtkPlayer::create(const OUString& rURL) return bRet; } +void GtkPlayer::notifyListeners() +{ + comphelper::OInterfaceContainerHelper2* pContainer + = m_lListener.getContainer(cppu::UnoType<css::media::XPlayerListener>::get()); + if (!pContainer) + return; + + css::lang::EventObject aEvent; + aEvent.Source = static_cast<cppu::OWeakObject*>(this); + + comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer); + while (pIterator.hasMoreElements()) + { + css::uno::Reference<css::media::XPlayerListener> xListener( + static_cast<css::media::XPlayerListener*>(pIterator.next())); + xListener->preferredPlayerWindowSizeAvailable(aEvent); + } +} + void SAL_CALL GtkPlayer::start() { osl::MutexGuard aGuard(m_aMutex); @@ -231,41 +301,6 @@ sal_Int16 SAL_CALL GtkPlayer::getVolumeDB() return m_nUnmutedVolume; } -namespace -{ -void invalidate_size(GdkPaintable* /*paintable*/, Timer* pTimer) { pTimer->Stop(); } - -Size GetPreferredPlayerWindowSize(GdkPaintable* pStream) -{ - Size aSize(gdk_paintable_get_intrinsic_width(pStream), - gdk_paintable_get_intrinsic_height(pStream)); - - // This is pretty nasty, maybe for the XFrameGrabber case it could be - // possible to implement an XGraphic which can be updated when the - // information becomes available rather than explicitly wait for it here, - // but the getPreferredPlayerWindowSize problem would remain. - if (aSize.Width() == 0 && aSize.Height() == 0) - { - Timer aTimer("gtkplayer waiting to find out size"); - aTimer.SetTimeout(3000); - - gulong nSignalId - = g_signal_connect(pStream, "invalidate-size", G_CALLBACK(invalidate_size), &aTimer); - - aTimer.Start(); - while (aTimer.IsActive()) - Application::Yield(); - - g_signal_handler_disconnect(pStream, nSignalId); - - aSize = Size(gdk_paintable_get_intrinsic_width(pStream), - gdk_paintable_get_intrinsic_height(pStream)); - } - - return aSize; -} -} - awt::Size SAL_CALL GtkPlayer::getPreferredPlayerWindowSize() { osl::MutexGuard aGuard(m_aMutex); @@ -274,9 +309,8 @@ awt::Size SAL_CALL GtkPlayer::getPreferredPlayerWindowSize() if (m_pStream) { - Size aPrefSize = GetPreferredPlayerWindowSize(GDK_PAINTABLE(m_pStream)); - aSize.Width = aPrefSize.Width(); - aSize.Height = aPrefSize.Height(); + aSize.Width = gdk_paintable_get_intrinsic_width(GDK_PAINTABLE(m_pStream)); + aSize.Height = gdk_paintable_get_intrinsic_height(GDK_PAINTABLE(m_pStream)); } return aSize; @@ -325,6 +359,26 @@ uno::Reference<::media::XPlayerWindow> return xRet; } +void SAL_CALL +GtkPlayer::addPlayerListener(const css::uno::Reference<css::media::XPlayerListener>& rListener) +{ + m_lListener.addInterface(cppu::UnoType<css::media::XPlayerListener>::get(), rListener); + if (gtk_media_stream_is_prepared(m_pStream)) + { + css::lang::EventObject aEvent; + aEvent.Source = static_cast<cppu::OWeakObject*>(this); + rListener->preferredPlayerWindowSizeAvailable(aEvent); + } + else + installNotify(); +} + +void SAL_CALL +GtkPlayer::removePlayerListener(const css::uno::Reference<css::media::XPlayerListener>& rListener) +{ + m_lListener.removeInterface(cppu::UnoType<css::media::XPlayerListener>::get(), rListener); +} + namespace { class GtkFrameGrabber : public ::cppu::WeakImplHelper<css::media::XFrameGrabber> diff --git a/avmedia/source/gtk/gtkplayer.hxx b/avmedia/source/gtk/gtkplayer.hxx index 89f9355c94ae..46e416e79e25 100644 --- a/avmedia/source/gtk/gtkplayer.hxx +++ b/avmedia/source/gtk/gtkplayer.hxx @@ -15,6 +15,8 @@ #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/media/XPlayer.hpp> +#include <com/sun/star/media/XPlayerNotifier.hpp> +#include <comphelper/multicontainer2.hxx> #include <cppuhelper/compbase.hxx> #include <cppuhelper/basemutex.hxx> @@ -23,7 +25,9 @@ typedef struct _GtkWidget GtkWidget; namespace avmedia::gtk { -typedef cppu::WeakComponentImplHelper<css::media::XPlayer, css::lang::XServiceInfo> GtkPlayer_BASE; +typedef cppu::WeakComponentImplHelper<css::media::XPlayer, css::media::XPlayerNotifier, + css::lang::XServiceInfo> + GtkPlayer_BASE; class GtkPlayer final : public cppu::BaseMutex, public GtkPlayer_BASE { @@ -54,15 +58,29 @@ public: virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + virtual void SAL_CALL + addPlayerListener(const css::uno::Reference<css::media::XPlayerListener>& rListener) override; + virtual void SAL_CALL removePlayerListener( + const css::uno::Reference<css::media::XPlayerListener>& rListener) override; + virtual void SAL_CALL disposing() final override; + void notifyListeners(); + void installNotify(); + void uninstallNotify(); + private: void cleanup(); + comphelper::OMultiTypeInterfaceContainerHelper2 m_lListener; + OUString m_aURL; css::awt::Rectangle m_aArea; // Area of the player window. GtkMediaStream* m_pStream; GtkWidget* m_pVideo; + unsigned long m_nNotifySignalId; + unsigned long m_nInvalidateSizeSignalId; + unsigned long m_nTimeoutId; sal_Int16 m_nUnmutedVolume; }; diff --git a/avmedia/source/viewer/mediawindow.cxx b/avmedia/source/viewer/mediawindow.cxx index c251f020225e..f3c034146f1d 100644 --- a/avmedia/source/viewer/mediawindow.cxx +++ b/avmedia/source/viewer/mediawindow.cxx @@ -28,11 +28,16 @@ #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> @@ -296,14 +301,14 @@ void MediaWindow::executeFormatErrorBox(weld::Window* pParent) xBox->run(); } -bool MediaWindow::isMediaURL( const OUString& rURL, const OUString& rReferer, bool bDeep, Size* pPreferredSizePixel ) +bool MediaWindow::isMediaURL(const OUString& rURL, const OUString& rReferer, bool bDeep, rtl::Reference<PlayerListener> xPreferredPixelSizeListener) { const INetURLObject aURL( rURL ); if( aURL.GetProtocol() == INetProtocol::NotValid ) return false; - if( bDeep || pPreferredSizePixel ) + if (bDeep || xPreferredPixelSizeListener) { try { @@ -313,14 +318,20 @@ bool MediaWindow::isMediaURL( const OUString& rURL, const OUString& rReferer, bo if( xPlayer.is() ) { - if( pPreferredSizePixel ) + if (xPreferredPixelSizeListener) { - const awt::Size aAwtSize( xPlayer->getPreferredPlayerWindowSize() ); - - pPreferredSizePixel->setWidth( aAwtSize.Width ); - pPreferredSizePixel->setHeight( aAwtSize.Height ); + uno::Reference<media::XPlayerNotifier> xPlayerNotifier(xPlayer, css::uno::UNO_QUERY); + if (xPlayerNotifier) + { + // wait until its 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; } } @@ -346,18 +357,13 @@ bool MediaWindow::isMediaURL( const OUString& rURL, const OUString& rReferer, bo 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 OUString& rURL, - const OUString& rReferer, - const OUString& sMimeType ) +uno::Reference< graphic::XGraphic > MediaWindow::grabFrame(const css::uno::Reference<css::media::XPlayer>& xPlayer) { - uno::Reference< media::XPlayer > xPlayer( createPlayer( rURL, rReferer, &sMimeType ) ); uno::Reference< graphic::XGraphic > xRet; std::unique_ptr< Graphic > xGraphic; @@ -399,6 +405,99 @@ uno::Reference< graphic::XGraphic > MediaWindow::grabFrame( const OUString& rURL 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::makeAny(rURL) }, + { "Size.Width", uno::makeAny(rSize.Width)}, + { "Size.Height", uno::makeAny(rSize.Height)}, + { "IsLink", css::uno::makeAny(bLink) }, + })); + xDispatch->dispatch(aDispatchURL, aArgs); +} + +PlayerListener::PlayerListener(const std::function<void(const css::uno::Reference<css::media::XPlayer>&)> &rFn) + : PlayerListener_BASE(m_aMutex) + , m_aFn(rFn) +{ +} + +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 diff --git a/include/avmedia/mediawindow.hxx b/include/avmedia/mediawindow.hxx index d031f51adaf0..4954e04558bb 100644 --- a/include/avmedia/mediawindow.hxx +++ b/include/avmedia/mediawindow.hxx @@ -22,14 +22,22 @@ #include <vector> #include <tools/gen.hxx> +#include <com/sun/star/awt/Size.hpp> #include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/media/XPlayerListener.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> #include <vcl/vclptr.hxx> #include <avmedia/avmediadllapi.h> #define AVMEDIA_FRAMEGRABBER_DEFAULTFRAME -1.0 +namespace com::sun::star::frame { class XDispatchProvider; } namespace com::sun::star::graphic { class XGraphic; } -namespace com::sun::star::media { class XPlayer; } +namespace com::sun::star::media { + class XPlayer; + class XPlayerNotifier; +} namespace vcl { class Window; } namespace weld { class Window; } @@ -40,7 +48,6 @@ struct AcceptDropEvent; struct ExecuteDropEvent; enum class PointerStyle; - namespace avmedia { typedef ::std::vector< ::std::pair< OUString, OUString > > FilterNameVector; @@ -49,6 +56,29 @@ namespace avmedia namespace priv { class MediaWindowImpl; } + typedef cppu::WeakComponentImplHelper<css::media::XPlayerListener> PlayerListener_BASE; + + class AVMEDIA_DLLPUBLIC PlayerListener final : public cppu::BaseMutex, public PlayerListener_BASE + { + private: + css::uno::Reference<css::media::XPlayerNotifier> m_xNotifier; + std::function<void(const css::uno::Reference<css::media::XPlayer>&)> m_aFn; + + using WeakComponentImplHelperBase::disposing; + public: + PlayerListener(const std::function<void(const css::uno::Reference<css::media::XPlayer>&)> &rFn); + virtual void SAL_CALL dispose() override; + virtual ~PlayerListener() override; + + virtual void SAL_CALL preferredPlayerWindowSizeAvailable(const css::lang::EventObject& rSource) override; + virtual void SAL_CALL disposing(const css::lang::EventObject& rSource) override; + + void startListening(const css::uno::Reference<css::media::XPlayerNotifier>& rNotifier); + void stopListening(); + + void callPlayerWindowSizeAvailable(const css::uno::Reference<css::media::XPlayer>& rPlayer) { m_aFn(rPlayer); } + }; + class AVMEDIA_DLLPUBLIC MediaWindow { public: @@ -99,12 +129,18 @@ namespace avmedia /// checkbox and store its state in *o_pbLink static bool executeMediaURLDialog(weld::Window* pParent, OUString& rURL, bool *const o_pbLink); static void executeFormatErrorBox(weld::Window* pParent); - static bool isMediaURL( const OUString& rURL, const OUString& rReferer, bool bDeep = false, Size* pPreferredSizePixel = nullptr ); + static bool isMediaURL(const OUString& rURL, const OUString& rReferer, bool bDeep = false, + rtl::Reference<PlayerListener> xPreferredPixelSizeListener = nullptr); static css::uno::Reference< css::media::XPlayer > createPlayer( const OUString& rURL, const OUString& rReferer, const OUString* pMimeType = nullptr ); - static css::uno::Reference< css::graphic::XGraphic > grabFrame( const OUString& rURL, const OUString& rReferer, - const OUString& sMimeType ); + static css::uno::Reference<css::graphic::XGraphic> grabFrame(const css::uno::Reference<css::media::XPlayer>& rPlayer); + + static css::uno::Reference< css::graphic::XGraphic > grabFrame(const OUString& rURL, const OUString& rReferer, + const OUString& sMimeType, rtl::Reference<PlayerListener> xPreferredPixelSizeListener = nullptr); + + static void dispatchInsertAVMedia(const css::uno::Reference<css::frame::XDispatchProvider>&, + const css::awt::Size& rSize, const OUString& rURL, bool bLink); private: MediaWindow(const MediaWindow&) = delete; @@ -112,6 +148,7 @@ namespace avmedia VclPtr<priv::MediaWindowImpl> mpImpl; }; + } #endif // INCLUDED_AVMEDIA_MEDIAWINDOW_HXX diff --git a/sc/source/ui/drawfunc/fuins1.cxx b/sc/source/ui/drawfunc/fuins1.cxx index a447a56c6dca..cbc87373c467 100644 --- a/sc/source/ui/drawfunc/fuins1.cxx +++ b/sc/source/ui/drawfunc/fuins1.cxx @@ -20,8 +20,10 @@ #include <config_features.h> #include <officecfg/Office/Common.hxx> +#include <editeng/sizeitem.hxx> #include <sal/log.hxx> #include <sfx2/opengrf.hxx> +#include <sfx2/viewfrm.hxx> #include <svx/svdograf.hxx> #include <svx/svdomedia.hxx> #include <svx/svdpage.hxx> @@ -46,6 +48,8 @@ #include <globstr.hrc> #include <comphelper/lok.hxx> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/media/XPlayer.hpp> #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> #include <com/sun/star/ui/dialogs/ListboxControlActions.hpp> @@ -372,10 +376,16 @@ FuInsertMedia::FuInsertMedia( ScTabViewShell& rViewSh, const SfxRequest& rReq ) : FuPoor(rViewSh, pWin, pViewP, pDoc, rReq) { +#if HAVE_FEATURE_AVMEDIA OUString aURL; const SfxItemSet* pReqArgs = rReq.GetArgs(); bool bAPI = false; + const SvxSizeItem* pSizeItem = rReq.GetArg<SvxSizeItem>(FN_PARAM_1); + const SfxBoolItem* pLinkItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_2); + const bool bSizeUnknown = !pSizeItem; + Size aPrefSize; + if( pReqArgs ) { const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( &pReqArgs->Get( rReq.GetSlot() ) ); @@ -387,38 +397,49 @@ FuInsertMedia::FuInsertMedia( ScTabViewShell& rViewSh, } } - bool bLink(true); + bool bLink(pLinkItem ? pLinkItem->GetValue() : true); bool bInsertMedia = bAPI; -#if HAVE_FEATURE_AVMEDIA if (!bInsertMedia) bInsertMedia = ::avmedia::MediaWindow::executeMediaURLDialog(pWin ? pWin->GetFrameWeld() : nullptr, aURL, &bLink); -#endif if (!bInsertMedia) return; - Size aPrefSize; - - if( pWin ) - pWin->EnterWait(); - -#if HAVE_FEATURE_AVMEDIA - if( !::avmedia::MediaWindow::isMediaURL( aURL, ""/*TODO?*/, true, &aPrefSize ) ) + if (!bSizeUnknown) { - if( pWin ) - pWin->LeaveWait(); - - if( !bAPI ) - ::avmedia::MediaWindow::executeFormatErrorBox(pWindow ? pWindow->GetFrameWeld() : nullptr); + aPrefSize = pSizeItem->GetSize(); } else -#endif { - lcl_InsertMedia( aURL, bAPI, &rViewSh, pWindow, pView, aPrefSize, - bLink ); + if( pWin ) + pWin->EnterWait(); + + css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(rViewShell.GetViewFrame()->GetFrame().GetFrameInterface(), css::uno::UNO_QUERY); + + rtl::Reference<avmedia::PlayerListener> xPlayerListener(new avmedia::PlayerListener( + [xDispatchProvider, aURL, bLink](const css::uno::Reference<css::media::XPlayer>& rPlayer){ + css::awt::Size aSize = rPlayer->getPreferredPlayerWindowSize(); + avmedia::MediaWindow::dispatchInsertAVMedia(xDispatchProvider, aSize, aURL, bLink); + })); + + const bool bIsMediaURL = ::avmedia::MediaWindow::isMediaURL(aURL, ""/*TODO?*/, true, xPlayerListener); if( pWin ) pWin->LeaveWait(); + + if (!bIsMediaURL && !bAPI) + ::avmedia::MediaWindow::executeFormatErrorBox(pWindow ? pWindow->GetFrameWeld() : nullptr); + + return; } + + if (pWin) + pWin->EnterWait(); + + lcl_InsertMedia(aURL, bAPI, &rViewSh, pWindow, pView, aPrefSize, bLink); + + if (pWin) + pWin->LeaveWait(); +#endif } FuInsertMedia::~FuInsertMedia() diff --git a/sd/source/ui/func/fuinsert.cxx b/sd/source/ui/func/fuinsert.cxx index 5d95335e48ca..d65e7c8b2ff2 100644 --- a/sd/source/ui/func/fuinsert.cxx +++ b/sd/source/ui/func/fuinsert.cxx @@ -21,16 +21,21 @@ #include <fuinsert.hxx> #include <comphelper/storagehelper.hxx> +#include <comphelper/propertysequence.hxx> +#include <editeng/sizeitem.hxx> #include <officecfg/Office/Common.hxx> #include <toolkit/helper/vclunohelper.hxx> #include <svx/svxdlg.hxx> +#include <com/sun/star/chart2/XChartDocument.hpp> #include <com/sun/star/embed/EmbedVerbs.hpp> #include <com/sun/star/embed/NoVisualAreaSizeException.hpp> #include <com/sun/star/embed/Aspects.hpp> #include <com/sun/star/embed/XEmbeddedObject.hpp> -#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/media/XPlayer.hpp> #include <svl/stritem.hxx> +#include <sfx2/dispatch.hxx> #include <sfx2/msgpool.hxx> #include <sfx2/msg.hxx> #include <svtools/insdlg.hxx> @@ -664,6 +669,11 @@ void FuInsertAVMedia::DoExecute( SfxRequest& rReq ) const SfxItemSet* pReqArgs = rReq.GetArgs(); bool bAPI = false; + const SvxSizeItem* pSizeItem = rReq.GetArg<SvxSizeItem>(FN_PARAM_1); + const SfxBoolItem* pLinkItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_2); + const bool bSizeUnknown = !pSizeItem; + Size aPrefSize; + if( pReqArgs ) { const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( &pReqArgs->Get( rReq.GetSlot() ) ); @@ -675,58 +685,83 @@ void FuInsertAVMedia::DoExecute( SfxRequest& rReq ) } } - bool bLink(true); + bool bLink(pLinkItem ? pLinkItem->GetValue() : true); if (!(bAPI || ::avmedia::MediaWindow::executeMediaURLDialog(mpWindow ? mpWindow->GetFrameWeld() : nullptr, aURL, & bLink) )) return; - Size aPrefSize; - - if( mpWindow ) - mpWindow->EnterWait(); - - if( !::avmedia::MediaWindow::isMediaURL( aURL, "", true, &aPrefSize ) ) + if (!bSizeUnknown) { - if( mpWindow ) - mpWindow->LeaveWait(); - - if( !bAPI ) - ::avmedia::MediaWindow::executeFormatErrorBox(mpWindow->GetFrameWeld()); + aPrefSize = pSizeItem->GetSize(); } else { - Point aPos; - Size aSize; - sal_Int8 nAction = DND_ACTION_COPY; + // If we don't have a size then try and find that out, the resulted might be deliver async, so dispatch a follow up + // effort to insert the video, this time with a size. + if( mpWindow ) + mpWindow->EnterWait(); - if( aPrefSize.Width() && aPrefSize.Height() ) - { - if( mpWindow ) - aSize = mpWindow->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); - else - aSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); - } - else - aSize = Size( 5000, 5000 ); + css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(mpViewShell->GetViewFrame()->GetFrame().GetFrameInterface(), css::uno::UNO_QUERY); - if( mpWindow ) - { - aPos = mpWindow->PixelToLogic( ::tools::Rectangle( aPos, mpWindow->GetOutputSizePixel() ).Center() ); - aPos.AdjustX( -(aSize.Width() >> 1) ); - aPos.AdjustY( -(aSize.Height() >> 1) ); - } + rtl::Reference<avmedia::PlayerListener> xPlayerListener(new avmedia::PlayerListener( + [xDispatchProvider, aURL, bLink](const css::uno::Reference<css::media::XPlayer>& rPlayer){ + css::awt::Size aSize = rPlayer->getPreferredPlayerWindowSize(); + avmedia::MediaWindow::dispatchInsertAVMedia(xDispatchProvider, aSize, aURL, bLink); + })); - mpView->InsertMediaURL( aURL, nAction, aPos, aSize, bLink ) ; + const bool bIsMediaURL = ::avmedia::MediaWindow::isMediaURL(aURL, "", true, xPlayerListener); if( mpWindow ) mpWindow->LeaveWait(); + + if (!bIsMediaURL && !bAPI) + ::avmedia::MediaWindow::executeFormatErrorBox(mpWindow->GetFrameWeld()); + + return; } + + InsertMediaURL(aURL, aPrefSize, bLink); + #else (void)rReq; #endif } +#if HAVE_FEATURE_AVMEDIA +void FuInsertAVMedia::InsertMediaURL(const OUString& rURL, const Size& rPrefSize, bool bLink) +{ + if( mpWindow ) + mpWindow->EnterWait(); + + Point aPos; + Size aSize; + sal_Int8 nAction = DND_ACTION_COPY; + + if (rPrefSize.Width() && rPrefSize.Height()) + { + if( mpWindow ) + aSize = mpWindow->PixelToLogic(rPrefSize, MapMode(MapUnit::Map100thMM)); + else + aSize = Application::GetDefaultDevice()->PixelToLogic(rPrefSize, MapMode(MapUnit::Map100thMM)); + } + else + aSize = Size( 5000, 5000 ); + + if( mpWindow ) + { + aPos = mpWindow->PixelToLogic( ::tools::Rectangle( aPos, mpWindow->GetOutputSizePixel() ).Center() ); + aPos.AdjustX( -(aSize.Width() >> 1) ); + aPos.AdjustY( -(aSize.Height() >> 1) ); + } + + mpView->InsertMediaURL(rURL, nAction, aPos, aSize, bLink); + + if( mpWindow ) + mpWindow->LeaveWait(); +} +#endif + } // end of namespace sd /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/inc/View.hxx b/sd/source/ui/inc/View.hxx index 8d211d0c3533..4e530e3f9227 100644 --- a/sd/source/ui/inc/View.hxx +++ b/sd/source/ui/inc/View.hxx @@ -40,6 +40,8 @@ class ImageMap; class Graphic; class SdrOutliner; +namespace avmedia { class PlayerListener; } + namespace sd { class DrawDocShell; @@ -268,6 +270,7 @@ protected: sal_Int8 mnAction; Idle maDropErrorIdle; Idle maDropInsertFileIdle; + rtl::Reference<avmedia::PlayerListener> mxDropMediaSizeListener; sal_uInt16 mnLockRedrawSmph; bool mbIsDropAllowed; diff --git a/sd/source/ui/inc/fuinsert.hxx b/sd/source/ui/inc/fuinsert.hxx index 0ad622df36b8..a2b33596162d 100644 --- a/sd/source/ui/inc/fuinsert.hxx +++ b/sd/source/ui/inc/fuinsert.hxx @@ -19,6 +19,7 @@ #pragma once +#include <config_features.h> #include "fupoor.hxx" namespace sd { @@ -101,6 +102,10 @@ private: ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq); + +#if HAVE_FEATURE_AVMEDIA + void InsertMediaURL(const OUString& rURL, const Size& rPrefSize, bool bLink); +#endif }; } // end of namespace sd diff --git a/sd/source/ui/view/sdview.cxx b/sd/source/ui/view/sdview.cxx index b1ddd90c95cf..100374ae8205 100644 --- a/sd/source/ui/view/sdview.cxx +++ b/sd/source/ui/view/sdview.cxx @@ -22,6 +22,7 @@ #include <com/sun/star/linguistic2/XSpellChecker1.hpp> #include <View.hxx> +#include <avmedia/mediawindow.hxx> #include <editeng/outlobj.hxx> #include <editeng/unolingu.hxx> #include <o3tl/deleter.hxx> @@ -142,6 +143,12 @@ View::~View() // release content of selection clipboard, if we own the content ClearSelectionClipboard(); + if (mxDropMediaSizeListener) + { + mxDropMediaSizeListener->dispose(); + mxDropMediaSizeListener.clear(); + } + maDropErrorIdle.Stop(); maDropInsertFileIdle.Stop(); diff --git a/sd/source/ui/view/sdview4.cxx b/sd/source/ui/view/sdview4.cxx index 2b08a5a041f8..7a3c7c2267a5 100644 --- a/sd/source/ui/view/sdview4.cxx +++ b/sd/source/ui/view/sdview4.cxx @@ -61,6 +61,7 @@ #include <com/sun/star/embed/Aspects.hpp> #include <com/sun/star/embed/NoVisualAreaSizeException.hpp> #include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/media/XPlayer.hpp> #include <svtools/soerr.hxx> #include <sfx2/ipclient.hxx> #include <tools/debug.hxx> @@ -425,7 +426,7 @@ IMPL_LINK_NOARG(View, DropInsertFileHdl, Timer *, void) { OUString aCurrentDropFile( *aIter ); INetURLObject aURL( aCurrentDropFile ); - bool bOK = false; + bool bHandled = false; if( aURL.GetProtocol() == INetProtocol::NotValid ) { @@ -458,9 +459,9 @@ IMPL_LINK_NOARG(View, DropInsertFileHdl, Timer *, void) if( aIter == maDropFileVector.begin() ) mnAction = nTempAction; - bOK = true; + bHandled = true; } - if( !bOK ) + if (!bHandled) { std::shared_ptr<const SfxFilter> pFoundFilter; SfxMedium aSfxMedium( aCurrentDropFile, StreamMode::READ | StreamMode::SHARE_DENYNONE ); @@ -493,36 +494,48 @@ IMPL_LINK_NOARG(View, DropInsertFileHdl, Timer *, void) aReq.AppendItem( aItem1 ); aReq.AppendItem( aItem2 ); FuInsertFile::Create( mpViewSh, pWin, this, &mrDoc, aReq ); - bOK = true; + bHandled = true; } } } } - if( !bOK ) - { #if HAVE_FEATURE_AVMEDIA - Size aPrefSize; - - if( ::avmedia::MediaWindow::isMediaURL( aCurrentDropFile, ""/*TODO?*/ ) && - ::avmedia::MediaWindow::isMediaURL( aCurrentDropFile, ""/*TODO?*/, true, &aPrefSize ) ) + if (!bHandled) + { + bool bShallowDetect = ::avmedia::MediaWindow::isMediaURL(aCurrentDropFile, ""/*TODO?*/); + if (bShallowDetect) { - if( aPrefSize.Width() && aPrefSize.Height() ) - { - ::sd::Window* pWin = mpViewSh->GetActiveWindow(); + mxDropMediaSizeListener.set(new avmedia::PlayerListener( + [this, aCurrentDropFile](const css::uno::Reference<css::media::XPlayer>& rPlayer){ + SolarMutexGuard g; - if( pWin ) - aPrefSize = pWin->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); - else - aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); - } - else - aPrefSize = Size( 5000, 5000 ); + css::awt::Size aSize = rPlayer->getPreferredPlayerWindowSize(); + Size aPrefSize(aSize.Width, aSize.Height); + + if (aPrefSize.Width() && aPrefSize.Height()) + { + ::sd::Window* pWin = mpViewSh->GetActiveWindow(); - InsertMediaURL( aCurrentDropFile, mnAction, maDropPos, aPrefSize, true ) ; + if( pWin ) + aPrefSize = pWin->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); + else + aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); + } + else + aPrefSize = Size( 5000, 5000 ); + + InsertMediaURL(aCurrentDropFile, mnAction, maDropPos, aPrefSize, true); + + mxDropMediaSizeListener.clear(); + })); } - else + bHandled = bShallowDetect && ::avmedia::MediaWindow::isMediaURL(aCurrentDropFile, ""/*TODO?*/, true, mxDropMediaSizeListener); + } #endif + + if (!bHandled) + { if( mnAction & DND_ACTION_LINK ) static_cast< DrawViewShell* >( mpViewSh )->InsertURLButton( aCurrentDropFile, aCurrentDropFile, OUString(), &maDropPos ); else diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi index 8ef53ebaedc5..5115dec907c0 100644 --- a/sfx2/sdi/sfx.sdi +++ b/sfx2/sdi/sfx.sdi @@ -5387,7 +5387,11 @@ SfxVoidItem AVMediaPlayer SID_AVMEDIA_PLAYER ] SfxVoidItem InsertAVMedia SID_INSERT_AVMEDIA -() +( + SfxStringItem URL SID_INSERT_AVMEDIA, + SvxSizeItem Size FN_PARAM_1, + SfxBoolItem IsLink FN_PARAM_2 +) [ AutoUpdate = FALSE, FastCall = FALSE, diff --git a/svx/source/svdraw/svdomedia.cxx b/svx/source/svdraw/svdomedia.cxx index b40a0644aa15..62b2f9e8213f 100644 --- a/svx/source/svdraw/svdomedia.cxx +++ b/svx/source/svdraw/svdomedia.cxx @@ -51,6 +51,7 @@ struct SdrMediaObj::Impl std::shared_ptr< ::avmedia::MediaTempFile > m_pTempFile; #endif uno::Reference< graphic::XGraphic > m_xCachedSnapshot; + rtl::Reference<avmedia::PlayerListener> m_xPlayerListener; OUString m_LastFailedPkgURL; }; @@ -150,7 +151,18 @@ uno::Reference< graphic::XGraphic > const & SdrMediaObj::getSnapshot() const OUString aRealURL = m_xImpl->m_MediaProperties.getTempURL(); if( aRealURL.isEmpty() ) aRealURL = m_xImpl->m_MediaProperties.getURL(); - m_xImpl->m_xCachedSnapshot = avmedia::MediaWindow::grabFrame( aRealURL, m_xImpl->m_MediaProperties.getReferer(), m_xImpl->m_MediaProperties.getMimeType()); + OUString sReferer = m_xImpl->m_MediaProperties.getReferer(); + OUString sMimeType = m_xImpl->m_MediaProperties.getMimeType(); + uno::Reference<graphic::XGraphic> xCachedSnapshot = m_xImpl->m_xCachedSnapshot; + + m_xImpl->m_xPlayerListener.set(new avmedia::PlayerListener( + [this, xCachedSnapshot, aRealURL, sReferer, sMimeType](const css::uno::Reference<css::media::XPlayer>& rPlayer){ + SolarMutexGuard g; + m_xImpl->m_xCachedSnapshot = avmedia::MediaWindow::grabFrame(rPlayer); + ActionChanged(); + })); + + avmedia::MediaWindow::grabFrame(aRealURL, sReferer, sMimeType, m_xImpl->m_xPlayerListener); } #endif return m_xImpl->m_xCachedSnapshot; @@ -341,6 +353,7 @@ void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProper ( rNewProperties.getURL() != getURL() )) { m_xImpl->m_xCachedSnapshot.clear(); + m_xImpl->m_xPlayerListener.clear(); OUString const& url(rNewProperties.getURL()); if (url.startsWithIgnoreAsciiCase("vnd.sun.star.Package:")) { diff --git a/sw/source/uibase/shells/grfshex.cxx b/sw/source/uibase/shells/grfshex.cxx index 2fe098dba3a2..2f6ad40a36e5 100644 --- a/sw/source/uibase/shells/grfshex.cxx +++ b/sw/source/uibase/shells/grfshex.cxx @@ -25,12 +25,14 @@ #include <doc.hxx> #include <IDocumentDrawModelAccess.hxx> #include <docsh.hxx> -#include <svx/svdomedia.hxx> - +#include <avmedia/mediawindow.hxx> +#include <editeng/sizeitem.hxx> #include <sfx2/request.hxx> #include <sfx2/viewfrm.hxx> #include <svl/stritem.hxx> -#include <avmedia/mediawindow.hxx> +#include <svx/svdomedia.hxx> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/media/XPlayer.hpp> using namespace ::com::sun::star; using namespace ::com::sun::star::uno; @@ -49,6 +51,10 @@ bool SwTextShell::InsertMediaDlg( SfxRequest const & rReq ) vcl::Window& rWindow = GetView().GetViewFrame()->GetWindow(); bool bAPI = false; + const SvxSizeItem* pSizeItem = rReq.GetArg<SvxSizeItem>(FN_PARAM_1); + const SfxBoolItem* pLinkItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_2); + const bool bSizeUnknown = !pSizeItem; + if( pReqArgs ) { const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( &pReqArgs->Get( rReq.GetSlot() ) ); @@ -59,67 +65,85 @@ bool SwTextShell::InsertMediaDlg( SfxRequest const & rReq ) } } - bool bLink(true); + bool bLink(pLinkItem ? pLinkItem->GetValue() : true); + if (bAPI || ::avmedia::MediaWindow::executeMediaURLDialog(rWindow.GetFrameWeld(), aURL, & bLink)) { Size aPrefSize; - rWindow.EnterWait(); - - if( !::avmedia::MediaWindow::isMediaURL( aURL, "", true, &aPrefSize ) ) - { - rWindow.LeaveWait(); - - if( !bAPI ) - ::avmedia::MediaWindow::executeFormatErrorBox(rWindow.GetFrameWeld()); - } + if (!bSizeUnknown) + aPrefSize = pSizeItem->GetSize(); else { - SwWrtShell& rSh = GetShell(); + rWindow.EnterWait(); - if( !rSh.HasDrawView() ) - rSh.MakeDrawView(); + css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(GetView().GetViewFrame()->GetFrame().GetFrameInterface(), css::uno::UNO_QUERY); - Size aDocSz( rSh.GetDocSize() ); - const SwRect& rVisArea = rSh.VisArea(); - Point aPos( rVisArea.Center() ); - Size aSize; + rtl::Reference<avmedia::PlayerListener> xPlayerListener(new avmedia::PlayerListener( + [xDispatchProvider, aURL, bLink](const css::uno::Reference<css::media::XPlayer>& rPlayer){ + css::awt::Size aSize = rPlayer->getPreferredPlayerWindowSize(); + avmedia::MediaWindow::dispatchInsertAVMedia(xDispatchProvider, aSize, aURL, bLink); + })); - if( rVisArea.Width() > aDocSz.Width()) - aPos.setX( aDocSz.Width() / 2 + rVisArea.Left() ); + const bool bIsMediaURL = ::avmedia::MediaWindow::isMediaURL(aURL, "", true, xPlayerListener); - if(rVisArea.Height() > aDocSz.Height()) - aPos.setY( aDocSz.Height() / 2 + rVisArea.Top() ); - - if( aPrefSize.Width() && aPrefSize.Height() ) - aSize = rWindow.PixelToLogic(aPrefSize, MapMode(MapUnit::MapTwip)); - else - aSize = Size( 2835, 2835 ); + rWindow.LeaveWait(); - OUString realURL; - if (bLink) - { - realURL = aURL; - } - else + if (!bIsMediaURL) { - uno::Reference<frame::XModel> const xModel( - rSh.GetDoc()->GetDocShell()->GetModel()); - bRet = ::avmedia::EmbedMedia(xModel, aURL, realURL); - if (!bRet) { return bRet; } + if( !bAPI ) + ::avmedia::MediaWindow::executeFormatErrorBox(rWindow.GetFrameWeld()); + + return bRet; } + } - SdrMediaObj* pObj = new SdrMediaObj( - *rSh.GetDoc()->getIDocumentDrawModelAccess().GetDrawModel(), - tools::Rectangle(aPos, aSize)); + rWindow.EnterWait(); - pObj->setURL( realURL, "" ); - rSh.EnterStdMode(); - rSh.SwFEShell::InsertDrawObj( *pObj, aPos ); - bRet = true; + SwWrtShell& rSh = GetShell(); - rWindow.LeaveWait(); + if( !rSh.HasDrawView() ) + rSh.MakeDrawView(); + + Size aDocSz( rSh.GetDocSize() ); + const SwRect& rVisArea = rSh.VisArea(); + Point aPos( rVisArea.Center() ); + Size aSize; + + if( rVisArea.Width() > aDocSz.Width()) + aPos.setX( aDocSz.Width() / 2 + rVisArea.Left() ); + + if(rVisArea.Height() > aDocSz.Height()) + aPos.setY( aDocSz.Height() / 2 + rVisArea.Top() ); + + if( aPrefSize.Width() && aPrefSize.Height() ) + aSize = rWindow.PixelToLogic(aPrefSize, MapMode(MapUnit::MapTwip)); + else + aSize = Size( 2835, 2835 ); + + OUString realURL; + if (bLink) + { + realURL = aURL; + } + else + { + uno::Reference<frame::XModel> const xModel( + rSh.GetDoc()->GetDocShell()->GetModel()); + bRet = ::avmedia::EmbedMedia(xModel, aURL, realURL); + if (!bRet) { return bRet; } } + + SdrMediaObj* pObj = new SdrMediaObj( + *rSh.GetDoc()->getIDocumentDrawModelAccess().GetDrawModel(), + tools::Rectangle(aPos, aSize)); + + pObj->setURL( realURL, "" ); + rSh.EnterStdMode(); + rSh.SwFEShell::InsertDrawObj( *pObj, aPos ); + bRet = true; + + rWindow.LeaveWait(); } #endif |